Greasy Fork is available in English.

Simple URL Unshortener

Unshortens URLs by following redirect chains (console only)

  1. // ==UserScript==
  2. // @name Simple URL Unshortener
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Unshortens URLs by following redirect chains (console only)
  6. // @author maanimis
  7. // @match *://*/*
  8. // @grant GM_registerMenuCommand
  9. // @grant GM_xmlhttpRequest
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. // Register the menu command
  17. GM_registerMenuCommand("Unshorten URL", startUrlUnshortener);
  18.  
  19. function startUrlUnshortener() {
  20. // Ask user for the shortened URL
  21. const shortUrl = prompt("Enter the shortened URL to unshorten:");
  22.  
  23. if (!shortUrl) {
  24. console.log("No URL entered. Operation cancelled.");
  25. return;
  26. }
  27.  
  28. // Validate URL format
  29. try {
  30. new URL(shortUrl);
  31. } catch (e) {
  32. console.log("Invalid URL format. Please enter a valid URL.");
  33. return;
  34. }
  35.  
  36. // Start the unshortening process
  37. console.log("Starting URL unshortening process...");
  38. console.log("Initial URL:", shortUrl);
  39.  
  40. const redirectChain = [shortUrl];
  41. followRedirect(shortUrl, redirectChain, 0);
  42. }
  43.  
  44. function followRedirect(url, redirectChain, step) {
  45. // Maximum of 3 redirects
  46. if (step >= 3) {
  47. console.log("Reached maximum redirect depth (3)");
  48. displayResults(redirectChain);
  49. return;
  50. }
  51.  
  52. console.log(`Following step ${step+1}: ${url}`);
  53.  
  54. GM_xmlhttpRequest({
  55. method: "HEAD",
  56. url: url,
  57. headers: {
  58. "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"
  59. },
  60. timeout: 10000, // 10 second timeout
  61. anonymous: true, // Don't send cookies
  62. fetch: true, // Use fetch mode if available
  63. onload: function(response) {
  64. console.log(`Received response for ${url} with status: ${response.status}`);
  65.  
  66. // Check if we have a redirect status code
  67. if (response.status >= 300 && response.status < 400) {
  68. let nextUrl = null;
  69.  
  70. // Try to get location from response headers
  71. if (response.responseHeaders) {
  72. const locationMatch = response.responseHeaders.match(/location:\s*(.*?)(?:\r?\n|$)/i);
  73. if (locationMatch && locationMatch[1]) {
  74. nextUrl = locationMatch[1].trim();
  75. }
  76. }
  77.  
  78. // If we still don't have a nextUrl, try finalUrl
  79. if (!nextUrl && response.finalUrl && response.finalUrl !== url) {
  80. nextUrl = response.finalUrl;
  81. }
  82.  
  83. // Process relative URLs if needed
  84. if (nextUrl && !nextUrl.match(/^https?:\/\//i)) {
  85. try {
  86. const urlObj = new URL(url);
  87. if (nextUrl.startsWith('/')) {
  88. nextUrl = `${urlObj.protocol}//${urlObj.host}${nextUrl}`;
  89. } else {
  90. const path = urlObj.pathname.substring(0, urlObj.pathname.lastIndexOf('/') + 1);
  91. nextUrl = `${urlObj.protocol}//${urlObj.host}${path}${nextUrl}`;
  92. }
  93. } catch (e) {
  94. console.error("Error processing relative URL:", e);
  95. }
  96. }
  97.  
  98. if (nextUrl && nextUrl !== url) {
  99. console.log(`Redirect found: ${nextUrl}`);
  100. redirectChain.push(nextUrl);
  101. followRedirect(nextUrl, redirectChain, step + 1);
  102. } else {
  103. console.log("No valid redirect found or redirect to same URL.");
  104. displayResults(redirectChain);
  105. }
  106. } else {
  107. // No redirect, we've reached the final URL
  108. console.log(`Final URL reached: ${url}`);
  109. displayResults(redirectChain);
  110. }
  111. },
  112. onerror: function(error) {
  113. console.error(`Error following redirect for ${url}:`, error);
  114. displayResults(redirectChain);
  115. },
  116. ontimeout: function() {
  117. console.error(`Request timed out for ${url}`);
  118. displayResults(redirectChain);
  119. }
  120. });
  121. }
  122.  
  123. function displayResults(redirectChain) {
  124. console.log("\n===== URL UNSHORTENING RESULTS =====");
  125. console.log("Complete redirect chain:");
  126.  
  127. redirectChain.forEach((url, index) => {
  128. console.log(`${index + 1}. ${url}`);
  129. });
  130.  
  131. console.log(`\nTotal URLs in chain: ${redirectChain.length}`);
  132. console.log("======================================\n");
  133. }
  134. })();
  135.