Last active
July 16, 2024 02:01
-
-
Save jix/e67c127820954e1d1571c1f6f800ac2c to your computer and use it in GitHub Desktop.
User script to resolve t.co links on twitter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Resolve t.co links on twitter | |
// @namespace Violentmonkey Scripts | |
// @match *://twitter.com/* | |
// @grant GM_xmlhttpRequest | |
// @version 1.1 | |
// @author @jix_ | |
// @homepage https://gist.github.com/jix/e67c127820954e1d1571c1f6f800ac2c | |
// @description Tries to resolve all annoying t.co links on twitter and replaces them with the | |
// target URL. | |
// ==/UserScript== | |
// 2021-02-23: 1.1: Also handle http not only https. Handle initial DOM nodes. Slightly improved | |
// error handling/logging. | |
// 2021-02-17: 1.0: Initial version | |
const inFlight = {}; // Have just one request in flight per URL | |
const cached = {}; // Cache results until page reload | |
// Takes a 't.co' url, strips '?amp=1' if present and resolves it by making a GET request. With curl | |
// on the command line you can also use a HEAD request, but I didn't manage to make it work in here. | |
const resolveTcoUrl = function (url, callback) { | |
url = url.replace('?amp=1', ''); | |
if (cached.hasOwnProperty(url)) { | |
callback(cached[url]); | |
return; | |
} | |
console.log(`resolving ${url}`); | |
if (inFlight.hasOwnProperty(url)) { | |
// Request already in flight, just push this callback to it | |
inFlight[url].push(callback); | |
return; | |
} else { | |
inFlight[url] = [callback]; | |
} | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: url, | |
anonymous: true, | |
onload: function (response) { | |
if (response.status != 200) { | |
console.log(`failed resolve for ${url}`); | |
// We reset the callbacks so if the url appears again we can retry... untested though | |
delete inFlight[url]; | |
return; | |
} | |
let target; | |
try { | |
// The resulting url is in a meta http eqiv tag, easy to parse with browser APIs | |
const parsed = new DOMParser().parseFromString(response.responseText, 'text/html'); | |
const meta = parsed.querySelector('META[http-equiv="refresh"]'); | |
target = meta.content.replace(/^0;URL=/, ''); | |
cached[url] = target; // Cache until page reload | |
} catch (e) { | |
console.log([`parsing response for ${url} failed`, e]); | |
delete inFlight[url]; | |
return; | |
} | |
const callbacks = inFlight[url]; // Get and reset all pending callbacks | |
delete inFlight[url]; | |
for (const callback of callbacks) { | |
try { | |
callback(target); // And notify them | |
} catch (e) { | |
console.log([`callback after resolving ${url} failed`, e]); | |
} | |
} | |
} | |
}); | |
}; | |
// Resolve all <a href=...> contained in the passed DOM node | |
const replaceContainedLinks = function (subtree) { | |
for (const linkNode of subtree.querySelectorAll('a')) { | |
if (!linkNode.href.startsWith('https://t.co/') && !linkNode.href.startsWith('http://t.co/')) continue; | |
resolveTcoUrl(linkNode.href, function (resolved) { | |
linkNode.href = resolved; | |
}); | |
} | |
} | |
// This gets called whenever twitter javascript adds new subtrees to the DOM which we'll scan for | |
// links. | |
const mutationCallback = function (mutationsList, observer) { | |
// We scan all added subtrees for all <a> tags and check whether we need to rsolve them | |
for (const mutation of mutationsList) { | |
for (const addedSubtree of mutation.addedNodes) { | |
replaceContainedLinks(addedSubtree) | |
} | |
} | |
}; | |
// Install the mutation callback | |
new MutationObserver(mutationCallback).observe(document, { childList: true, subtree: true }); | |
// Replace links in static content | |
replaceContainedLinks(document); |
This code does not run in the console but requires an extension like Violentmonkey. I also stopped using Twitter so I'm not using or maintaining this script anymore.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I tried to run this code in the Firefox console today and it returned this page as an explanation for the error I received. I couldn't see where the let command in your code would interfere with anything. Do you have any insights?