URL Shortener Unshortener

Adds small button next to shortened URLs (t.co/bit.ly/goo.gl) on Twitter and other sites that will replace the shortened URLs with their real locations and vice-versa. Useful for when you don't want to blindly click links.

  1. // ==UserScript==
  2. // @name URL Shortener Unshortener
  3. // @namespace Smiths
  4. // @description Adds small button next to shortened URLs (t.co/bit.ly/goo.gl) on Twitter and other sites that will replace the shortened URLs with their real locations and vice-versa. Useful for when you don't want to blindly click links.
  5. // @include *
  6. // @version 1.0.5
  7. // @grant GM_getValue
  8. // @grant GM_setValue
  9. // @grant GM_addStyle
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_registerMenuCommand
  12. // @attribution changes [d:03.05.14][u:<ul><li>Fix for oversized buttons; needed to specify size. Oops./li></ul>]
  13. // ==/UserScript==
  14.  
  15. //note to self: gotta make sure to update the one in the metadata too!
  16. var v = "1.0.5";
  17. var scriptNum = "140411";
  18. var scriptName = "URL Shortener Unshortener";
  19.  
  20. //<--Updater Stuff
  21. var isFireFox = navigator.userAgent.indexOf("Firefox") > -1 || navigator.userAgent.indexOf("Iceweasel") > -1;
  22. GM_addStyle("#smgm_bgdiv{ text-align: center;position:fixed;top:0px;left:0px;z-index:9991;width:100%;height:100%;background-color:black;opacity:0.7;display:block;visibility:visible;}");
  23. GM_addStyle("#smgm_dialogbox { vertical-align:middle;left:40px;top:15px;border:3px solid #000 !important;text-align:center !important;background-color:#fff !important;color:#000 !important;font-family:arial,verdana !important;z-Index:9999;position:fixed;width:18%;height:50%;margin-left:auto;margin-right:auto;display:block;visibility:visible;}");
  24. GM_addStyle(".smgm_buttons { color:#000 !important;font: 90% 'arial','trebuchet ms',helvetica,sans-serif !important;background-color:#B2CCFF !important;border:2px solid !important;border-color: #E0EBFF #000 #000 #E0EBFF !important;vertical-align: top !important;}");
  25. GM_addStyle(".smgm_table { margin-bottom:10px !important;border:0px !important;border-collapse:collapse !important;margin-left:auto;margin-right:auto; }");
  26. var remindLaterV = GM_getValue('remindLaterV', remindLaterV);
  27. if (!remindLaterV) { remindLaterV = 0; GM_setValue('remindLaterV',remindLaterV); }
  28.  
  29. var homepageURL = "http://userscripts.org/scripts/show/" + scriptNum ;
  30. var metaURL = "http://userscripts.org/scripts/source/" + scriptNum + ".meta.js";
  31. var scriptJSURL = "http://userscripts.org/scripts/source/" + scriptNum + ".user.js";
  32.  
  33. function doremindLater(clicked,span)
  34. {
  35. if (clicked)
  36. remindLaterV = span;
  37. else
  38. remindLaterV--;
  39. GM_setValue('remindLaterV',remindLaterV);
  40. }
  41.  
  42. function hideUpdate()
  43. {
  44. document.body.removeChild(document.getElementById('smgm_bgdiv'));
  45. document.body.removeChild(document.getElementById('smgm_dialogbox'));
  46. }
  47.  
  48. function checkNew(version)
  49. {
  50. var upgrade = 0;
  51. var verstring = "";
  52. var theHTML = "";
  53. GM_xmlhttpRequest({
  54. method:"GET",
  55. url:metaURL,
  56. onload:function(content){
  57. var aResponse = content.responseText;
  58. var USversion = aResponse.match(/@version.*?(\d[^<]+?)\n/);
  59. aResponse = aResponse.replace(/ \/>/g,'>');
  60. aResponse = aResponse.replace(/\n/g,'');
  61. var changeDate = aResponse.match(/\[d:([0-9]+?\.[0-9]+?\.[0-9]+?)\]/i)[1];
  62. var theChanges = aResponse.match(/\[u:(.*?)\]/i)[1];
  63. vSplit = version.split(".");
  64. vmain = Number(vSplit[0]);
  65. vvsub = Number(vSplit[1]);
  66. vrsub = Number(vSplit[2]);
  67. USsplit = USversion[1].split(".");
  68. USvmain = Number(USsplit[0]);
  69. USvsub = Number(USsplit[1]);
  70. USrsub = Number(USsplit[2]);
  71. verstring = "<div style='padding:5px;border-bottom:1px dotted #000;'>Latest Version on Userscripts: <a href='" + homepageURL + "' target='_new' title='Click to visit script's page'><b>" + USvmain + "." + USvsub + "." + USrsub + "</b></a><br>Your Installed Version: <b>" + vmain + "." + vvsub + "." + vrsub + "</b></div>";
  72. if (USvmain > vmain) upgrade = 1;
  73. if ( (USvsub > vvsub) && (USvmain >= vmain) ) upgrade = 1;
  74. if ( (USrsub > vrsub) && (USvsub == vvsub) && (USvmain >= vmain) ) upgrade = 1;
  75. if (upgrade == 1) //upgrade available, pop a box
  76. {
  77. theHTML += "<div style='padding:5px;border-bottom:1px dotted #000;'>New version of " + scriptName + " available.</div>";
  78. theHTML += verstring + "<p>";
  79. theHTML += "<table class='smgm_table'><tr><td><input type='button' class='smgm_buttons' id='smgm_installButton' onMouseUp=\"document.location.href=\'" + scriptJSURL + "\';\" value='Install'></td>";
  80. theHTML += "<td style='width:25px;'>&nbsp;</td><td><input style='' class='smgm_buttons' type='button' id='smgm_remindButton' value='Remind Me Later'></td>";
  81. theHTML += "</tr></table><div style='background-color:white !important;overflow:auto !important;height:50%;text-align:left;border-top:1px dotted #000;padding:7px;' colspan='5'>Changes (" + changeDate.replace(/\./g,"/") + "):<br><span style='font-style:italic;'>" + theChanges + "</span></div>";
  82. div1 = document.createElement('div');
  83. div1.id = 'smgm_dialogbox';
  84. div1.style.display = "none";
  85. div1.innerHTML = theHTML;
  86. document.body.appendChild(div1);
  87. div2 = document.createElement('div');
  88. div2.id = 'smgm_bgdiv';
  89. div2.style.display = "none";
  90. div2.addEventListener("click",function(){doremindLater(true,15);hideUpdate();},false);
  91. document.body.appendChild(div2);
  92. document.getElementById('smgm_bgdiv').style.display='block';
  93. document.getElementById('smgm_dialogbox').style.display='block';
  94. document.getElementById('smgm_remindButton').addEventListener("click", function(){doremindLater(true,60);hideUpdate();},false);
  95. document.getElementById('smgm_installButton').addEventListener("click", function(){hideUpdate();},false);
  96. }
  97. }
  98. })
  99. }
  100.  
  101. if (isFireFox) //only do update on FFox, Chrome/Tampermonkey are weird
  102. {
  103. doremindLater(false);
  104. if (remindLaterV < 1)
  105. checkNew(v);
  106. }
  107. //end updater stuff-->
  108.  
  109.  
  110. var b1 = "data:image/gif;base64,R0lGODlhCAAIANUAAAAAAP///xa9JhKcHxKaHw56GQ1wFwxnFR3zMRzoLxrbLBnSKhjMKRa5JRWuIxKXHg9/Gh/9NCP9OCX9OS79QTH9RDv9TT79UEr9Ww4sERQ+GBI4FhlNHhtSIBZDGlf+Z13+bGH+cGn+dy1iMnn+hXv+h37+iob+kU97U1N+V3mbfIKihYOihgsjDQ0oDxI2FQwkDg8sET1uQW2ScHCUc////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADUALAAAAAAIAAgAAAY3wFptpZqhhDXWqRS6jGo0E0mEoUQ4KdDHMkkwNLKKBKFwDF4dxUJAgBgyNU/jUTi0kJuYCyYMAgA7";
  111. var b2 = "data:image/gif;base64,R0lGODlhCAAIANUAAAAAAP///703FpwuEpotEnokDnAhDWceDPNHHehEHNtAGtI+Gcw8GLk2Fq4zFZcsEn8lD/1LH/1OI/1QJf1XLv1ZMf1hO/1kPv1tSiMQCywUDj4cFDgaEk0jGVImG0MfFjYZEiQRDP54V/58Xf6AYf6GaWI3Lf6Tef6Ve/6Xfv6ehn5cU5J0bZR3cJuAeaKJgygSDSwUD25GPXtXT6KIgv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADUALAAAAAAIAAgAAAY3wFotBItxhLXMofBofGoaA4QgWCg8oIFDgZBUZBtGYmIRjVadCAVTOqVaNdOFhFK9kDOWiyYMAgA7";
  112. var b3 = "data:image/gif;base64,R0lGODlhCAAIAPYEAKKUh5uLfZKAcXtlUv7Ejf67gf6xaP2dRGJIMJSDdP6/hP66f/61cP2kUf2WNf2OJk0zG35pVv6uZP6rXv2cQf2RLOiCI8xyHj4pFm5VQP2XOP2QKvOII9t6IK5fGpxXFjYjE1I2HdJ1Hr1pG5pWFn9HEnA+ECwdD0MsGLlnG5dSFnpEEWc6DyMXDDglFCwdECgaDiQYDaGifJubc5KSZ3t7SqGiffz+ff7+cfv+V/r9NGFiKZSUavz+dP7+b/v+X/r9QPn9JPn9FUxNFn1+Tvv+U/v+Tfr9Mfn9G+ToE8nMED0+Em5uOfn9J/n9Ge/zE9jbEa6uDpqcDDY2EFJSGM/SELq9D5iaDH1/Cm5wCSssDENDE7a5D5eXDHh6CWVnCCMjCjc4ECwrDSgoCyQkCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgBlACwAAAAACAAIAAAHPIBlZQAAAgOCgwQKBg2HAAQEDA0aFQgRBhIHFRYXLhkaGxwdHiQgIR0iKSQlJi9lCB4qKywtiC4vL2KCgQAh+QQFCgBlACwAAAAACAAIAAAHO4BlZTY2NDWCgzc9OUCHNjc3P0BNSDtEOUU6SElKYUyUT1BRV1NUUFVWV1hZWmVUXF1eX2SIU2JkU4KBADs=";
  113.  
  114. function getRealURL(urlID) {
  115. var theURL,link;
  116. link = document.querySelector('a[slID="'+urlID+'"]');
  117. theURL = link.getAttribute('data-full-url');
  118. var plusBox = document.getElementById('bsl'+urlID.substr(2));
  119. plusBox.innerHTML = '<img title="Click to fetch full URL" style="width:8px;height:8px;padding:2px;border:none" src="'+b3+'" alt="[+]">';
  120. GM_xmlhttpRequest({
  121. method:"HEAD",
  122. url:theURL,
  123. headers:{ "User-Agent":"monkeyagent", "Accept":"text/monkey,text/xml" },
  124. onload:function(content){
  125. var minusBox = document.createElement('a');
  126. link.setAttribute('smgm_origURL',link.innerHTML);
  127. link.setAttribute('smgm_origfURL',theURL);
  128. var newLink = link.cloneNode(true);
  129. newLink.href = content.finalUrl;
  130. newLink.innerHTML = content.finalUrl;
  131. link.parentNode.replaceChild(newLink,link);
  132.  
  133. minusBox.innerHTML = '<img title="Click to collapse back to shortened URL" style="width:8px;height:8px;padding:2px;border:none" src="'+b2+'" alt="[-]">';
  134. minusBox.href="javascript:void(0);";
  135. minusBox.id = 'bsl'+urlID.substr(2);
  136. minusBox.addEventListener("click",function(){
  137. this.innerHTML = '<img title="Click to fetch full URL" style="width:8px;height:8px;padding:2px;border:none" src="'+b1+'" alt="[+]">';
  138. var aLink = document.querySelector('a[slID="'+this.id.substr(1)+'"]');
  139. aLink.setAttribute('data-full-url',aLink.getAttribute('smgm_origfURL'));
  140. aLink.innerHTML=aLink.getAttribute('smgm_origURL');
  141. aLink.href=aLink.getAttribute('smgm_origfURL');
  142. aLink.target="_blank";
  143. this.addEventListener("click",function(){getRealURL(this.id.substr(1));},false);
  144. },false);
  145. plusBox.parentNode.replaceChild(minusBox,plusBox);
  146. }
  147. })
  148. }
  149.  
  150. function unescapeHTML(s){return s.replace('&amp;', '&').replace('&lt;',"<").replace('&gt;','>').replace('&quot;','1"').replace('&#39;','\'');}
  151.  
  152. var lc = 0;
  153. document.addEventListener('DOMNodeInserted',function(e){
  154. window.setTimeout(function(){
  155. var newLinks = document.querySelectorAll('a[href*="po.st/"],a[href*="img.ly/"],a[href*="bit.ly/"],a[href*="goo.gl/"],a[href*="t.co/"],a[href*="db.tt/"],a[class*="extLink"],a[class*="url-ext"],a[class*="twitter-timeline-link"]');
  156. if (newLinks.length > 0)
  157. {
  158. for (var i = 0; i < newLinks.length; i++) {
  159. if (newLinks[i].className.match(/\bsmgm_usTitle\b/) == null && newLinks[i].innerHTML.indexOf('<img') < 0)
  160. {
  161. lc++;
  162. var plusBox = document.createElement('a');
  163. newLinks[i].setAttribute('slID','sl'+lc);
  164. if (newLinks[i].getAttribute('data-full-url') == null) newLinks[i].setAttribute('data-full-url',newLinks[i].href);
  165. plusBox.innerHTML = '<img title="Click to fetch full URL" style="width:8px;height:8px;padding:2px;border:none" src="'+b1+'" alt="[+]">';
  166. plusBox.href="javascript:void(0);";
  167. plusBox.id = "bsl" + lc;
  168. plusBox.addEventListener("click",function(){getRealURL(this.id.substr(1));},false);
  169. newLinks[i].parentNode.insertBefore(plusBox,newLinks[i].nextSibling);
  170. (newLinks[i].className == "") ? newLinks[i].className = "smgm_usTitle" : newLinks[i].className = newLinks[i].className + " smgm_usTitle";
  171. }
  172. }
  173. }
  174. }, 200);}
  175. , false);