您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Unshortens URLs by following redirect chains (console only)
// ==UserScript== // @name Simple URL Unshortener // @namespace http://tampermonkey.net/ // @version 1.0 // @description Unshortens URLs by following redirect chains (console only) // @author maanimis // @match *://*/* // @grant GM_registerMenuCommand // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function() { 'use strict'; // Register the menu command GM_registerMenuCommand("Unshorten URL", startUrlUnshortener); function startUrlUnshortener() { // Ask user for the shortened URL const shortUrl = prompt("Enter the shortened URL to unshorten:"); if (!shortUrl) { console.log("No URL entered. Operation cancelled."); return; } // Validate URL format try { new URL(shortUrl); } catch (e) { console.log("Invalid URL format. Please enter a valid URL."); return; } // Start the unshortening process console.log("Starting URL unshortening process..."); console.log("Initial URL:", shortUrl); const redirectChain = [shortUrl]; followRedirect(shortUrl, redirectChain, 0); } function followRedirect(url, redirectChain, step) { // Maximum of 3 redirects if (step >= 3) { console.log("Reached maximum redirect depth (3)"); displayResults(redirectChain); return; } console.log(`Following step ${step+1}: ${url}`); GM_xmlhttpRequest({ method: "HEAD", url: url, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" }, timeout: 10000, // 10 second timeout anonymous: true, // Don't send cookies fetch: true, // Use fetch mode if available onload: function(response) { console.log(`Received response for ${url} with status: ${response.status}`); // Check if we have a redirect status code if (response.status >= 300 && response.status < 400) { let nextUrl = null; // Try to get location from response headers if (response.responseHeaders) { const locationMatch = response.responseHeaders.match(/location:\s*(.*?)(?:\r?\n|$)/i); if (locationMatch && locationMatch[1]) { nextUrl = locationMatch[1].trim(); } } // If we still don't have a nextUrl, try finalUrl if (!nextUrl && response.finalUrl && response.finalUrl !== url) { nextUrl = response.finalUrl; } // Process relative URLs if needed if (nextUrl && !nextUrl.match(/^https?:\/\//i)) { try { const urlObj = new URL(url); if (nextUrl.startsWith('/')) { nextUrl = `${urlObj.protocol}//${urlObj.host}${nextUrl}`; } else { const path = urlObj.pathname.substring(0, urlObj.pathname.lastIndexOf('/') + 1); nextUrl = `${urlObj.protocol}//${urlObj.host}${path}${nextUrl}`; } } catch (e) { console.error("Error processing relative URL:", e); } } if (nextUrl && nextUrl !== url) { console.log(`Redirect found: ${nextUrl}`); redirectChain.push(nextUrl); followRedirect(nextUrl, redirectChain, step + 1); } else { console.log("No valid redirect found or redirect to same URL."); displayResults(redirectChain); } } else { // No redirect, we've reached the final URL console.log(`Final URL reached: ${url}`); displayResults(redirectChain); } }, onerror: function(error) { console.error(`Error following redirect for ${url}:`, error); displayResults(redirectChain); }, ontimeout: function() { console.error(`Request timed out for ${url}`); displayResults(redirectChain); } }); } function displayResults(redirectChain) { console.log("\n===== URL UNSHORTENING RESULTS ====="); console.log("Complete redirect chain:"); redirectChain.forEach((url, index) => { console.log(`${index + 1}. ${url}`); }); console.log(`\nTotal URLs in chain: ${redirectChain.length}`); console.log("======================================\n"); } })();