Highlight OCH links

Link Checker. Hit escape to check whether one-click hoster links are online or offline.

当前为 2019-07-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Highlight OCH links
  3. // @namespace cuzi
  4. // @license MIT
  5. // @description Link Checker. Hit escape to check whether one-click hoster links are online or offline.
  6. // @icon https://greasyfork.org/system/screenshots/screenshots/000/003/868/original/och.png
  7. // @compatible firefox Greasemonkey
  8. // @compatible chrome Tampermonkey. Allow all domains on first run.
  9. // @homepageURL https://openuserjs.org/scripts/cuzi/Highlight_OCH_links
  10. // @require https://openuserjs.org/src/libs/cuzi/RequestQueue.js
  11. // @require https://openuserjs.org/src/libs/cuzi/OCH_List.min.js
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM.xmlHttpRequest
  14. // @connect *
  15. // @version 17
  16. // @include *
  17. // @exclude *.yahoo.*
  18. // @exclude *.google.*
  19. // @exclude *.youtube.*
  20. // @exclude *.bing.com*
  21. // @exclude *duckduckgo.com*
  22. // ==/UserScript==
  23.  
  24. (function() {
  25. "use strict";
  26.  
  27.  
  28. // Maximal number of links that are checked (per website)
  29. var MAXREQUESTS = 1000;
  30.  
  31. // Maximal number of links that are checked in parallel (per website)
  32. var MAXPARALLELCONNECTIONS = 16;
  33.  
  34. // Maximal number of DOM nodes that are examined. Decrease this number on slow machines.
  35. var MAXTEXTNODES = 10000;
  36.  
  37. // Maximum download size per link (in KB). If you have activated direct downloads, the script will try to download the whole file instead of checking the link. This limit prevents this.
  38. var MAXDOWNLOADSIZE = 2000; // kilobytes
  39.  
  40.  
  41. /*
  42. // Export
  43. var mypatterns = [];
  44. var mynames = [];
  45. var myurls = [];
  46. for(var key in OCH) {
  47. var o = OCH[key];
  48. if((""+o.check).length > 30) { // If check function implemented
  49. mypatterns.push(o.pattern.toString());
  50. mynames.push("'"+key+"'");
  51. myurls.push(" - ["+o.title+"]("+o.homepage+")");
  52. }
  53. }
  54.  
  55. alert(mypatterns.join(",\n"));
  56. alert(mynames.join(",\n"));
  57. alert(myurls.join("\n"));
  58. */
  59.  
  60.  
  61.  
  62. var links = []; // [ { hoster: "", url: "", element: DOMNode} , ... ]
  63. var rq = new RequestQueue(MAXPARALLELCONNECTIONS, MAXREQUESTS);
  64.  
  65.  
  66. if(typeof GM == "undefined") {
  67. var GM = {};
  68. }
  69. if(! "xmlHttpRequest" in GM) {
  70. GM.xmlHttpRequest = GM_xmlhttpRequest;
  71. }
  72.  
  73.  
  74. // Get OCH list
  75. const OCH = getOCH(rq, MAXDOWNLOADSIZE);
  76.  
  77.  
  78.  
  79. function linkOffline(link) {
  80. link.element.style.backgroundColor = "rgba(255, 0, 20, 0.5)";
  81. link.element.dataset.linkValidatedAs = "offline";
  82. }
  83. function linkOnline(link) {
  84. link.element.style.backgroundColor = "rgba(70, 255 ,0, 0.5)";
  85. link.element.dataset.linkValidatedAs = "online";
  86. }
  87. function linkWaiting(link) {
  88. link.element.style.backgroundColor = "rgba(255, 150, 80, 0.4)";
  89. }
  90.  
  91. function handleResult(link,result,errorstring) {
  92. if(result === 1) {
  93. linkOnline(link);
  94. } else if(result === 0) {
  95. linkOffline(link);
  96. } else if(result == -1) {
  97. link.element.style.backgroundColor = "blue";
  98. link.element.title = errorstring;
  99. console.log(errorstring);
  100. } else {
  101. console.log("handleResult(link,result,errorstring) wrong resultcode: "+result);
  102. }
  103. }
  104.  
  105. function matchHoster(str) {
  106. // Return name of first hoster that matches, otherwise return false
  107. for(var name in OCH) {
  108. for(let i = 0; i < OCH[name].pattern.length; i++) {
  109. if(OCH[name].pattern[i].test(str)) {
  110. return name;
  111. }
  112. }
  113. }
  114. return false;
  115. }
  116.  
  117. function findLinks() {
  118. links = [];
  119.  
  120. // Normalize hoster object: Replace single patterns with arrays [RegExp]
  121. for(var name in OCH) {
  122. if(!Array.isArray(OCH[name].pattern)) {
  123. OCH[name].pattern = [ OCH[name].pattern ];
  124. }
  125. }
  126.  
  127. // Find all text nodes that contain "http://"
  128. var nodes = [];
  129. var walk = document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{ acceptNode: function(node) {
  130. if(node.parentNode.href || node.parentNode.parentNode.href || node.parentNode.parentNode.parentNode.href)
  131. return NodeFilter.FILTER_REJECT;
  132. if(node.parentNode.tagName == "TEXTAREA" || node.parentNode.parentNode.tagName == "TEXTAREA")
  133. return NodeFilter.FILTER_REJECT;
  134. if(node.data.match(/(\s|^)https?:\/\/\w+/))
  135. return NodeFilter.FILTER_ACCEPT;
  136. } },false);
  137. var node = walk.nextNode();
  138. while(node) {
  139. nodes.push(node);
  140. node = walk.nextNode();
  141. }
  142.  
  143. // For each found text nodes check whether the URL is a valid OCH URL
  144. for(let i = 0; i < nodes.length && i < MAXTEXTNODES; i++) {
  145. if("" === nodes[i].data) {
  146. continue;
  147. }
  148. var httpPosition = nodes[i].data.indexOf("http");
  149. if(httpPosition == -1) {
  150. continue;
  151. }
  152.  
  153. var urlnode;
  154. if(httpPosition > 0) {
  155. urlnode = nodes[i].splitText(httpPosition); // Split leading text
  156. } else {
  157. urlnode = nodes[i];
  158. }
  159. var stop = urlnode.data.match(/$|\s/)[0]; // Find end of URL
  160. if("" !== stop) { // If empty string, we found $ end of string
  161. var nextnode = urlnode.splitText(urlnode.data.indexOf(stop)); // Split trailing text
  162. if("" !== nextnode.data && nextnode.data.indexOf("http") != -1) {// The trailing text might contain another URL
  163. nodes.push(nextnode);
  164. }
  165. }
  166.  
  167. // Check whether the URL is a OCH. If so, create an <a> element
  168. var url = urlnode.data;
  169. var mh = matchHoster(url);
  170. if(mh !== false) {
  171. var a = document.createElement("a");
  172. a.href = url;
  173. a.appendChild(urlnode.parentNode.replaceChild(a, urlnode));
  174. links.push( {
  175. 'hoster' : mh,
  176. 'url' : url,
  177. 'element' : a
  178. });
  179. }
  180. }
  181.  
  182. // Find actual <a> links
  183. var al = document.getElementsByTagName('a');
  184. for(let i = 0; i < al.length; i++) {
  185. if(al[i].dataset.linkValidatedAs) {
  186. continue; // Link was already checked
  187. }
  188. var mH = matchHoster(al[i].href);
  189. if(mH !== false) {
  190. links.push( {
  191. 'hoster' : mH,
  192. 'url' : al[i].href,
  193. 'element' : al[i]
  194. });
  195. }
  196. }
  197.  
  198. return links.length;
  199. }
  200.  
  201. function checkLinks() {
  202. // Check all links by calling the hoster's check function
  203. for(let i = 0; i < links.length; i++) {
  204. if(links[i] && OCH[links[i].hoster].check && typeof(OCH[links[i].hoster].check) === 'function') {
  205. linkWaiting(links[i]);
  206. OCH[links[i].hoster].check(links[i],handleResult);
  207. }
  208. }
  209. }
  210.  
  211.  
  212. document.addEventListener('keydown',function(ev) {
  213. if (ev.keyCode == 27) {
  214. if(!rq.hasRunning()) {
  215. // Highlight links and check them
  216. rq.resetTotal();
  217. var n = findLinks();
  218. if(n > 0 ) {
  219. checkLinks();
  220. }
  221. } else {
  222. // Abort all requests
  223. rq.abort();
  224. }
  225. }
  226. },false);
  227.  
  228. })();