mirror of
https://github.com/ergosteur/misc-userscripts.git
synced 2026-04-19 13:09:33 -04:00
136 lines
4.5 KiB
JavaScript
136 lines
4.5 KiB
JavaScript
// ==UserScript==
|
|
// @name Expand t.co links (live replace, Location header fixed)
|
|
// @namespace https://github.com/ergosteur/misc-userscripts
|
|
// @author ergosteur
|
|
// @version 0.7
|
|
// @description Expand t.co shortlinks into final URLs by parsing Location header
|
|
// @match https://twitter.com/*
|
|
// @match https://x.com/*
|
|
// @grant GM_registerMenuCommand
|
|
// @grant GM_xmlhttpRequest
|
|
// ==/UserScript==
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
function showTextareaDialog(title, callback) {
|
|
const overlay = document.createElement("div");
|
|
overlay.style.position = "fixed";
|
|
overlay.style.top = 0;
|
|
overlay.style.left = 0;
|
|
overlay.style.width = "100%";
|
|
overlay.style.height = "100%";
|
|
overlay.style.background = "rgba(0,0,0,0.7)";
|
|
overlay.style.zIndex = 999999;
|
|
|
|
const box = document.createElement("div");
|
|
box.style.position = "absolute";
|
|
box.style.top = "50%";
|
|
box.style.left = "50%";
|
|
box.style.transform = "translate(-50%, -50%)";
|
|
box.style.background = "#fff";
|
|
box.style.padding = "20px";
|
|
box.style.borderRadius = "8px";
|
|
box.style.maxWidth = "600px";
|
|
box.style.width = "80%";
|
|
box.style.display = "flex";
|
|
box.style.flexDirection = "column";
|
|
|
|
const label = document.createElement("div");
|
|
label.textContent = title;
|
|
label.style.marginBottom = "8px";
|
|
|
|
const textarea = document.createElement("textarea");
|
|
textarea.style.width = "100%";
|
|
textarea.style.height = "300px";
|
|
textarea.style.whiteSpace = "pre";
|
|
|
|
const controls = document.createElement("div");
|
|
controls.style.marginTop = "8px";
|
|
controls.style.display = "flex";
|
|
controls.style.justifyContent = "space-between";
|
|
controls.style.alignItems = "center";
|
|
|
|
const button = document.createElement("button");
|
|
button.textContent = "Expand";
|
|
|
|
const status = document.createElement("div");
|
|
status.textContent = "Ready.";
|
|
|
|
controls.appendChild(button);
|
|
controls.appendChild(status);
|
|
|
|
box.appendChild(label);
|
|
box.appendChild(textarea);
|
|
box.appendChild(controls);
|
|
overlay.appendChild(box);
|
|
document.body.appendChild(overlay);
|
|
|
|
button.onclick = () => {
|
|
const val = textarea.value.trim();
|
|
if (!val) {
|
|
overlay.remove();
|
|
return;
|
|
}
|
|
callback(textarea, status);
|
|
};
|
|
}
|
|
|
|
function expandOne(link) {
|
|
return new Promise((resolve) => {
|
|
GM_xmlhttpRequest({
|
|
method: "GET", // GET is safer than HEAD for t.co
|
|
url: link,
|
|
redirect: "manual", // we want the Location header
|
|
onload: (resp) => {
|
|
let out = link;
|
|
|
|
// responseHeaders is a string in Tampermonkey
|
|
const headers = resp.responseHeaders.split(/\r?\n/);
|
|
const locLine = headers.find(h => /^location:/i.test(h));
|
|
if (locLine) {
|
|
out = locLine.split(/:\s*/i)[1].trim();
|
|
}
|
|
|
|
resolve(out);
|
|
},
|
|
onerror: () => resolve(link)
|
|
});
|
|
});
|
|
}
|
|
|
|
async function expandLinks() {
|
|
showTextareaDialog("Paste t.co links (one per line):", async (textarea, status) => {
|
|
let lines = textarea.value.split(/\r?\n/);
|
|
const total = lines.length;
|
|
|
|
for (let i = 0; i < total; i++) {
|
|
const line = lines[i].trim();
|
|
if (!line) continue;
|
|
|
|
status.textContent = `Expanding ${i + 1}/${total}...`;
|
|
const full = await expandOne(line);
|
|
|
|
lines[i] = full;
|
|
textarea.value = lines.join("\n");
|
|
|
|
textarea.scrollTop = textarea.scrollHeight; // auto-scroll
|
|
}
|
|
|
|
status.textContent = `Done! Expanded ${total} links.`;
|
|
|
|
const blob = new Blob([lines.join("\n")], {type: "text/plain"});
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
const dl = document.createElement("a");
|
|
dl.href = url;
|
|
dl.download = "expanded_links.txt";
|
|
dl.textContent = "⬇ Download results";
|
|
dl.style.marginLeft = "10px";
|
|
|
|
status.appendChild(dl);
|
|
});
|
|
}
|
|
|
|
GM_registerMenuCommand("Expand t.co Links", expandLinks);
|
|
})(); |