FuckShortenedUrl

Replace shortened URLs with real URLs

当前为 2021-02-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name FuckShortenedUrl
  3. // @namespace https://greasyfork.org/en/users/173996-wtfjs
  4. // @version 0.25
  5. // @description Replace shortened URLs with real URLs
  6. // @author wtfjs
  7. // @license MIT
  8. // @run-at document-start
  9. // @match https://*/*
  10. // @match http://*/*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. ;(function __FuckShortenedUrl() {
  15. "use strict";
  16. var utils = {
  17. $: function $(selector, parent) {
  18. var _parent = parent || document
  19. return _parent.querySelector(selector)
  20. },
  21.  
  22. $$: function $$(selector, parent) {
  23. var _parent = parent || document
  24. return _parent.querySelectorAll(selector)
  25. },
  26.  
  27. forEachRight: function forEachRight(arr, fn) {
  28. for (var i = (arr.length >>> 0) - 1; i >= 0; i -= 1) {
  29. var it = arr[i]
  30. var res = fn(it, i, arr)
  31. if (res === false) {
  32. break;
  33. }
  34. }
  35. },
  36.  
  37. concurrent: function concurrent(job) {
  38. var dispatch = window.requestIdleCallback || window.requestAnimationFrame || window.setTimeout
  39. dispatch(job)
  40. },
  41.  
  42. isElement: function isElement(any) {
  43. return typeof any === "object" && any.nodeType === 1 // Node.ELEMENT_NODE
  44. },
  45.  
  46. getSearchParams: function getSearchParams(urlStr) {
  47. try {
  48. return new URL(urlStr).searchParams
  49. } catch (e) {}
  50. return null
  51. },
  52.  
  53. findParent: function findParent(el, elOrMatchFn) {
  54. var matchFn = typeof elOrMatchFn === "function" ? elOrMatchFn : function matchFn(it) {
  55. return it === elOrMatchFn
  56. }
  57.  
  58. var node = el.parentElement
  59. while (node !== null) {
  60. if (matchFn(node)) {
  61. return node
  62. }
  63. node = node.parentElement
  64. }
  65. return null
  66. }
  67. }
  68.  
  69. var handlers = [
  70. [
  71. /https?:\/\/link\.zhihu\.com/,
  72. function transform($link) {
  73. var searchParams = utils.getSearchParams($link.href)
  74. if (searchParams && searchParams.get("target")) {
  75. var realHref = searchParams.get("target")
  76. $link.href = realHref
  77. return realHref
  78. }
  79. }
  80. ],
  81. [
  82. /https?:\/\/douc\.cc/,
  83. function transform($link) {
  84. if (/https?:\/\//.test($link.title)) {
  85. var realHref = $link.title
  86. $link.textContent = $link.textContent.replace($link.href, realHref)
  87. $link.href = realHref
  88. return realHref
  89. }
  90. }
  91. ],
  92. [
  93. /https?:\/\/(www.)?douban\.com\/link2/,
  94. function transform($link) {
  95. var searchParams = utils.getSearchParams($link.href)
  96. if (searchParams && searchParams.get("url")) {
  97. var realHref = searchParams.get("url")
  98. $link.href = realHref
  99. return realHref
  100. }
  101. }
  102. ],
  103. [
  104. /https?:\/\/t\.co/,
  105. function transform($link) {
  106. var $cardWrapper = utils.findParent($link, function(node) {
  107. return node.dataset.testid === "card.wrapper"
  108. })
  109. var isCardLink = !!$cardWrapper
  110. var realHref
  111. if (isCardLink) {
  112. try {
  113. var $textContent = $cardWrapper.parentElement.parentElement.parentElement.previousElementSibling
  114. var $textLink = utils.$("a[href^=http]", $textContent)
  115. if ($textLink) {
  116. realHref = getTextLinkHref($textLink)
  117. $link.href = realHref
  118. return realHref
  119. }
  120. } catch (e) {}
  121. } else {
  122. realHref = getTextLinkHref($link)
  123. $link.href = realHref
  124. return realHref
  125. }
  126.  
  127. function getTextLinkHref($el) {
  128. return $el.textContent.replace(/((\.\.\.)|(…))$/, '')
  129. }
  130. }
  131. ],
  132. [
  133. /https?:\/\/(www\.)?youtube\.com\/redirect\?/,
  134. function transform($link) {
  135. var searchParams = utils.getSearchParams($link.href)
  136. if (searchParams && searchParams.get("q")) {
  137. var realHref = searchParams.get("q")
  138. $link.href = realHref
  139. return realHref
  140. }
  141. }
  142. ]
  143. ]
  144.  
  145. var REDIRECT_URL_SELECTORS = [
  146. "t.co","link.zhihu.com","douc.cc","douban.com/link2",
  147. "youtube.com/redirect"
  148. ]
  149. .map(function(url) {return 'a[href*="' + url + '/"]'})
  150. .join(",")
  151.  
  152. function selectLinks(parent) {
  153. return utils.$$(REDIRECT_URL_SELECTORS, parent)
  154. }
  155.  
  156. function transformLinks($links, cache) {
  157. utils.forEachRight($links, function($link) {
  158. utils.concurrent(function transform() {
  159. if (!$link || !$link.href) return
  160.  
  161. var href = $link.href
  162. var cachedHref = cache[href]
  163. if (cachedHref) {
  164. if (href !== cachedHref) {
  165. $link.href = cachedHref
  166. }
  167. return
  168. }
  169.  
  170. utils.forEachRight(handlers, function(handler) {
  171. var pattern = handler[0]
  172. var fn = handler[1]
  173. if (pattern.test(href)) {
  174. var res = fn($link)
  175. if (res) {
  176. cache[href] = res
  177. }
  178. return false
  179. }
  180. })
  181. })
  182. })
  183. }
  184.  
  185. function onDomMutation(mutationList) {
  186. var cache = {}
  187. utils.forEachRight(mutationList, function(mutation) {
  188. utils.concurrent(function () {
  189. var target = mutation.target
  190. if (!target || !utils.isElement(target)) return
  191.  
  192. var $newLinks = []
  193.  
  194. utils.forEachRight(selectLinks(target), function addNewLink($link) {
  195. $newLinks.push($link)
  196. })
  197.  
  198. transformLinks($newLinks, cache)
  199. })
  200. })
  201. }
  202.  
  203. function start() {
  204. console.log("----------- FuckShortenedUrl -------------")
  205.  
  206. transformLinks(selectLinks(), {})
  207.  
  208. var observer = new MutationObserver(onDomMutation)
  209. observer.observe(document.body, {subtree: true, childList: true})
  210. }
  211.  
  212. window.addEventListener("load", start)
  213. })()