Open CyberShadow opened 2 years ago
Hi, this raises multiple issues. Mainly, the idea of nitter is to be a more usable lighter and faster front end to twitter. If we do the same thing twitter does, then there is no point. Second, we are trying to implement this using no JavaScript, to not slow down website that use nitter embeds, load faster, avoid content jumping and more. This complicates things a bit, but we think its worth the effort, evidently since the mashable link you sent took me around a minute to load.
As to your problem, embeds are still a prototype, we are waiting on some fixes in other places to make them closer to actually usable for the purpose of replacing embeds on sites automatically. It will be a bit easier after that.
For now just replace the whole twitter blockquote with a nitter iframe, the height will be a bit weird but its something.
I want to add my voice in hoping this issue is resolved. Nitter embeds + LibRedirect are the only way to view Twitter embeds while keeping Firefox's Strict Enhanced Tracking Protection turned on. Toggling it off for every website that relies on Twitter embeds means surfing a large portion of the internet without essential privacy features such as Total Cookie Protection.
Nitter embeds were working wonderfully until April 10, when they simply stopped working across all websites for all users simultaneously. I filed an issue with LibRedirect but after some back and forth was notified that any potential fix would have to happen to Nitter's codebase. As of now while using Firefox Enhanced Tracking Protection set to Strict one must click through every single Twitter embed individually to see what was said. It's not ideal.
I'm not a programmer or developer, so I can't deign to understand what exactly needs to be done, but I really hope this issue is resolved, as it is an absolutely killer feature. I'm even willing to contribute money towards a developer and/or bounty if that's what it takes to devise a durable solution for fixing Nitter embeds across most websites. Please let me know how I can help, and thanks for all of your hard work.
If it's better for me to open a separate issue for Nitter embeds breaking across all websites let me know. Thanks!
@catwithbanana I think you need to file a separate issue. This one is referring to replacing embeds when the tweet has a non-standard height, as Nitter embeds don't dynamically adjust their height in relation to the tweet content. But now instead there's an issue where every embed is no longer working.
@catwithbanana I think you need to file a separate issue. This one is referring to replacing embeds when the tweet has a non-standard height, as Nitter embeds don't dynamically adjust their height in relation to the tweet content. But now instead there's an issue where every embed is no longer working.
Done -- thank you for the heads up.
let tweet_regex = /^https?:\/\/twitter\.com\/[^/]+\/status\/(\d+)\??/
let blockquotes = document.querySelectorAll("blockquote.twitter-tweet")
for (i = 0; i < blockquotes.length; ++i) {
let blockquote = blockquotes.item(i)
let link = blockquote.lastChild.href
let id = tweet_regex.exec(link)[1]
let embed = document.createElement("iframe")
embed.src = `https://nitter.cunnycon.org/i/status/${id}/embed`
embed.style = 'width:100%;height:400px'
embed.loading = 'lazy'
blockquote.parentNode.replaceChildren(embed)
}
I wrote this code a week back which works well enough as a userscript but isn't perfect. No idea how you would determine the right height. You could also serve this as widgets.js.
(EDIT: If we could pre-calculate the size of images, height: auto
would work.)
Maybe this helps someone implement a better and more complete solution.
Modified the script slightly since it didn't work for me:
let tweet_regex = /^https?:\/\/twitter\.com\/[^/]+\/status\/(\d+)\??/
let blockquotes = document.querySelectorAll("blockquote.twitter-tweet")
for (i = 0; i < blockquotes.length; ++i) {
let blockquote = blockquotes[i]
let link = blockquote.children[0].href
let id = tweet_regex.exec(link)[1]
let embed = document.createElement("iframe")
embed.src = `https://nitter.cunnycon.org/i/status/${id}/embed`
embed.style = 'width:100%;height:400px'
embed.loading = 'lazy'
blockquote.replaceChildren(embed)
}
blockquote.children[0].href
doesn't seem right.
The link is always the last one. finding an a
element would probably better though.
The link is always the last one
In the Mashable case I think it's a custom think they're doing where your version doesn't work, I didn't test on any other site.
This works:
const tweet_regex = /^https?:\/\/twitter\.com\/[^/]+\/status\/(\d+)\??/
const blockquotes = document.querySelectorAll("blockquote.twitter-tweet a")
for (const blockquote of blockquotes) {
const link = blockquote.href
const id = tweet_regex.exec(link)[1]
const embed = document.createElement("iframe")
embed.src = `https://nitter.cunnycon.org/i/status/${id}/embed?theme=Twitter`
embed.style = 'width:100%;height:400px'
embed.loading = 'lazy'
blockquote.replaceWith(embed)
}
That breaks if there are other links in the blockquote.
blockquote.twitter-tweet > a
should do it
If you get a userscript working, may I suggest posting it on OpenUserJS or Greasy Fork or a GitHub gist so that others can use it also.
After a lot of back and forth I concluded that the only reliable way of doing this is:
window.parent.postMessage
With 'load' awaiting full page load this works even without setting individual image sizes.
The big drawback is that this requires enabling javascript on the parent site.
https://github.com/zedeus/nitter/commit/06679c6f64427187a4dbaf48f6d24b35ea4bb13f
document.querySelectorAll('script[src="https://platform.twitter.com/widgets.js"]').forEach(s => s.remove())
let iframeMap = {}
const instance = 'https://nitter.cunnycon.org'
const tweet_regex = /^https?:\/\/twitter\.com\/[^/]+\/status\/(\d+)\??/
const blockquotes = document.querySelectorAll('blockquote.twitter-tweet > a')
for (const blockquote of blockquotes) {
const link = blockquote.href
const id = tweet_regex.exec(link)[1]
const embed = document.createElement('iframe')
const url = `${instance}/i/status/${id}/embed`
embed.src = url
embed.style = 'width:100%;height:600px'
embed.loading = 'lazy'
blockquote.parentNode.replaceWith(embed)
if (iframeMap[url]) {
iframeMap[url].push(embed)
} else {
iframeMap[url] = [embed]
}
}
window.addEventListener('message', function(e) {
if (e.origin != instance || e.data[0] != 'resizeIframe')
return
const data = e.data[1];
const height = data['h']
if (height == 0)
return
for (const embed of iframeMap[data['url']]) {
embed.style.height = `${height}px`
}
}, false);
Added the script to the PR, ready for review.
It would be great to also support Twitter's dynamic embedding mechanism in conjunction with e.g. libredirect.
Two examples of pages that currently don't work:
Both of these pages seem to use a similar mechanism:
blockquote
withclass="twitter-tweet"
is present in the page HTML, containing some placeholder text and a link (a
tag) to the tweetwidgets.js
script:<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
blockquote.twitter-tweet
and turns it into Twitter embeds (iframes).If Twitter's
widgets.js
is allowed to execute, it does create iframes which libredirect successfully redirects to Nitter embeds. However, these iframes remain hidden. I thinkwidgets.js
is waiting for the iframe to somehow signal that it finished loading, but that never happens in the Nitter implementation.I can see one of two approaches to make this work:
widgets.js
scriptwidgets.js
script, which libredirect could load instead of the Twitter one.Twitter's documentation for this mechanism:
widgets.js
)blockquote.twitter-tweet
convention)Libredirect discussion: https://github.com/libredirect/libredirect/issues/20