批量打开链结

批量打开文本链结、批量选取链结后打开。

目前为 2024-09-20 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Open Multiple URLs
  3. // @name:zh-CN 批量打开链结
  4. // @name:zh-TW 批量打開鏈結
  5. // @version 2024-09-20
  6. // @description Open Multiple Text URLs,Open Multiple Element URLs.
  7. // @description:zh-CN 批量打开文本链结、批量选取链结后打开。
  8. // @description:zh-TW 批量打開文字鏈結、批量選取鏈結後打開。
  9. // @author tony0809
  10. // @match *://*/*
  11. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAQAAAD9CzEMAAACVklEQVR42u2XwUsUURzHf+6GgUTloUNaaUZRJNQpJIsNfb/vLCorEqNgdslO5aGLRBvrQJeMTi7kyd1E9tCp/pDwVhGYmISEVxHWzd1GcJ8/BnZWxzdz3M/v9nvzPt83zPwGhho0OIT+a3ii0nihUolTFDUMfIUrVeRs8hxFhRPDO/zXain+gzsUCU08D9e3tq0HUZx+Qc5cwmc4nMUP6Wxxb3T6NeumdB1IhOqJSt9JHnhaVv72tZMZ1uMavX/EEpmBGV+9wBm9XlFtZMJABzbg8oroa9+vZR0xSWYMteCW3SyT3GUNJ86SB7zWAbMUHmuUd+Dy78FWEvi5DshGoMeulo2QwHnde0XhwJjoS8krpFE3UKx2rftR6csYl3vq5LVqF6t2nMxhG6LnCR+9a40GmlqewMxAx/H1+BBMn9u/eGOo5Wi9uoRVmeJPiRNB9HnZcPsoffK0R79kxwPo8VE2rCRP1tELeAhX16ITC6JflA3r/V21773WC9zN5f1+XvSHwVnvF9NPj0c1QzfMBUwF09sB9ObYcf5Vq8c4l3XsLsYoDOqeFhVxXXpXuRRWL6i0Pn+OBB6B1st8GiMPmJ+RMNiKdbi8I/ow8Gw1QKXJgzqjUnyZNNZ5zmDKbiYT1FN9B8vURH7IN4fnyYS+dq7oiEw9vV7/RmZwQeZg2l+v6w2ZkbyATUhEXf2CEyNTuBfbInIORNwdXi+oBCSCv2MODn/Bv2j0MtG8BdevOCf6cOAuNn3070UfHlzkAlc88p8qRVGj2niS32IOL1WPE2v89Daoyx7M5xLNLagfwwAAAABJRU5ErkJggg==
  12. // @grant GM_openInTab
  13. // @grant GM_registerMenuCommand
  14. // @grant unsafeWindow
  15. // @license MIT
  16. // @namespace https://gf.qytechs.cn/users/20361
  17. // ==/UserScript==
  18.  
  19. /***
  20.  
  21. 一個用處不大的腳本,主要是我的另一個腳本圖片全載,需要手動確認網站存活時會用到。
  22.  
  23. 注意一次性打開太多鏈結會造成瀏覽器嚴重卡頓,慎用!!!,在有需要的時候再開啟這個腳本。
  24.  
  25. 說明
  26.  
  27. 模式一:批量打開文字鏈結
  28.  
  29. 創建一個文字輸入區,一行一個網址或域名,批量打開。
  30.  
  31. 模式二:選取鏈結後打開
  32.  
  33. 步驟1.透過腳本管理器選單或按快捷鍵Ctrl + Alt + U或雙擊頁面的空白處來注入事件。
  34. 步驟2.鼠標懸停要打開的鏈結進行標記和預讀,標記會對鏈結添加橙色的邊框,再次懸停會取消標記。
  35.  
  36. Q:如何取消?
  37. A:按Esc鍵或點擊頁面的空白處。
  38.  
  39. 步驟3.頁面的空白處按滑鼠右鍵或快捷鍵Ctrl + Alt + O,打開被標記的所有鏈結。
  40.  
  41. 再次使用重複步驟1
  42.  
  43. ***/
  44.  
  45. (() => {
  46. 'use strict';
  47.  
  48. const _unsafeWindow = unsafeWindow ?? window;
  49. const hasTouchEvents = (() => ("ontouchstart" in _unsafeWindow) || (_unsafeWindow.navigator.maxTouchPoints > 0) || (_unsafeWindow.navigator.msMaxTouchPoints > 0))();
  50.  
  51. const language = _unsafeWindow.navigator.language;
  52.  
  53. let scriptLanguage;
  54. switch (language) {
  55. case "zh-TW":
  56. case "zh-HK":
  57. case "zh-Hant-TW":
  58. case "zh-Hant-HK":
  59. scriptLanguage = "TW";
  60. break;
  61. case "zh":
  62. case "zh-CN":
  63. case "zh-Hans-CN":
  64. scriptLanguage = "CH";
  65. break;
  66. default:
  67. scriptLanguage = "EN";
  68. }
  69.  
  70. let i18n;
  71. switch (scriptLanguage) {
  72. case "TW":
  73. i18n = {
  74. omu: "批量打開鏈結",
  75. ou: "批量打開",
  76. close: "關閉",
  77. otu: "批量打開文字鏈結",
  78. oeu: "選取鏈結後打開(Ctrl + Alt + U)"
  79. };
  80. break;
  81. case "CN":
  82. i18n = {
  83. omu: "批量打开链结",
  84. ou: "批量打开",
  85. close: "关闭",
  86. otu: "批量打开文本链结",
  87. oeu: "选取链结后打开(Ctrl + Alt + U)"
  88. };
  89. break;
  90. default:
  91. i18n = {
  92. omu: "Open Multiple URLs",
  93. ou: "Open URLs",
  94. close: "Close",
  95. otu: "Open Multiple Text URLs",
  96. oeu: "Open Multiple Element URLs(Ctrl + Alt + U)"
  97. };
  98. }
  99.  
  100. const createFixedElement = () => {
  101.  
  102. const mainHtml = '<div id="Batch_open_links" style="display: initial !important;position: fixed !important;z-index: 9999999 !important;"></div>';
  103. document.body.insertAdjacentHTML("beforeend", mainHtml);
  104.  
  105. const mainElement = document.querySelector("#Batch_open_links");
  106. const shadow = mainElement.attachShadow({
  107. mode: "open"
  108. });
  109.  
  110. const div = document.createElement("div");
  111.  
  112. Object.assign(div.style, {
  113. left: "0",
  114. right: "0",
  115. top: "0",
  116. bottom: "0",
  117. width: "100vw",
  118. height: "100vh",
  119. margin: "auto",
  120. padding: "25px 10px 10px 10px",
  121. position: "fixed",
  122. opacity: "1",
  123. zIndex: "9999999",
  124. backgroundColor: "#eee",
  125. color: "#222",
  126. fontSize: "14px",
  127. overflow: "scroll",
  128. textAlign: "left"
  129. });
  130.  
  131. const html = `
  132. <h3 style="font-size: 22px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">${i18n.omu}</h3>
  133. <textarea id="links_textarea" style="display: block; margin: 10px 0 10px 0; white-space:pre; overflow:scroll; resize: revert; text-transform: initial;"></textarea>
  134. <button id="open" style="margin-right: 20px;">${i18n.ou}</button>
  135. <button id="close">${i18n.close}</button>
  136. `;
  137. div.innerHTML = html;
  138. shadow.appendChild(div);
  139.  
  140. const reWidth = () => {
  141. shadow.querySelector("#links_textarea").style.width = hasTouchEvents ? (_unsafeWindow.innerWidth - 26) + "px": (_unsafeWindow.innerWidth - 40) + "px";
  142. shadow.querySelector("#links_textarea").style.height = hasTouchEvents ? (_unsafeWindow.innerHeight - 140) + "px": (_unsafeWindow.innerHeight - 200) + "px";
  143. };
  144. reWidth();
  145.  
  146. _unsafeWindow.addEventListener("resize", reWidth);
  147.  
  148. shadow.querySelector("#close").addEventListener("click", () => {
  149. mainElement.remove();
  150. _unsafeWindow.removeEventListener("resize", reWidth);
  151. });
  152.  
  153. shadow.querySelector("#open").addEventListener("click", () => {
  154. const value = shadow.querySelector("#links_textarea").value;
  155.  
  156. let links = value.split("\n").filter(e => e).map(url => {
  157. if (/^https?:\/\//.test(url)) {
  158. return url;
  159. } else {
  160. return "https://" + url;
  161. }
  162. });
  163. links = [...new Set(links)];
  164.  
  165. for (const link of links) {
  166. let ok = true;
  167. try {
  168. new URL(link);
  169. } catch (error) {
  170. ok = false;
  171. console.error(link, error);
  172. }
  173. if (ok) GM_openInTab(link);
  174. }
  175.  
  176. shadow.querySelector("#links_textarea").value = "";
  177. });
  178. };
  179.  
  180. GM_registerMenuCommand(i18n.otu, () => createFixedElement());
  181.  
  182. if (hasTouchEvents) return;
  183.  
  184. const preloadLink = (url) => {
  185. if ([...document.getElementsByTagName("link")].some(link => link.href == url)) return;
  186. const preloadElement = document.createElement("link");
  187. preloadElement.rel = "prefetch";
  188. preloadElement.as = "document";
  189. preloadElement.href = url;
  190. document.head.appendChild(preloadElement);
  191. };
  192.  
  193. const openElementLinks = () => {
  194.  
  195. const contextmenuEvent = (event) => event.preventDefault();
  196. document.addEventListener("contextmenu", contextmenuEvent);
  197.  
  198. const clickEvent = () => open_cb(0);
  199. document.addEventListener("click", clickEvent);
  200.  
  201. const kEvent = (event) => {
  202. if (event.code === "Escape" || event.key === "Escape") {
  203. return open_cb(0);
  204. }
  205. if (event.ctrlKey && event.altKey && event.code === "KeyO") {
  206. open_cb();
  207. }
  208. };
  209. document.addEventListener("keydown", kEvent);
  210.  
  211. const aElements = [...document.getElementsByTagName("a")];
  212.  
  213. const aEvent = (event) => {
  214. if (event.target.getAttribute("select") == "true") {
  215. event.target.removeAttribute("select");
  216. event.target.removeAttribute("style");
  217. } else {
  218. event.target.setAttribute("select", "true");
  219. Object.assign(event.target.style, {
  220. paddingLeft: "4px",
  221. paddingRight: "4px",
  222. borderWidth: "2px",
  223. borderStyle: "solid",
  224. borderColor: "#ff9933"
  225. });
  226. preloadLink(event.target.href);
  227. }
  228. };
  229.  
  230. const open_cb = (open = 1) => {
  231. const links = [...document.querySelectorAll("a[select=true]")];
  232. if (links.length > 0) {
  233. const urls = [];
  234. links.forEach(a => {
  235. try {
  236. if (open === 1 && !urls.includes(a.href)) {
  237. new URL(a.href);
  238. urls.push(a.href);
  239. GM_openInTab(a.href);
  240. }
  241. } catch (error) {
  242. console.error(a.href, error);
  243. }
  244. a.removeAttribute("select");
  245. a.removeAttribute("style");
  246. });
  247. }
  248. aElements.forEach(a => a.removeEventListener("mouseenter", aEvent));
  249. document.removeEventListener("keydown", kEvent);
  250. document.removeEventListener("click", clickEvent);
  251. setTimeout(() => {
  252. document.removeEventListener("contextmenu", contextmenuEvent);
  253. }, 1000);
  254. };
  255.  
  256. aElements.forEach(a => a.addEventListener("mouseenter", aEvent));
  257.  
  258. document.addEventListener("mousedown", (event) => {
  259. if (event.button == 2) {
  260. open_cb();
  261. }
  262. });
  263. };
  264.  
  265. const kEvent = (event) => {
  266. if (event.ctrlKey && event.altKey && event.code === "KeyU") {
  267. openElementLinks();
  268. }
  269. };
  270.  
  271. document.addEventListener("keydown", kEvent);
  272. document.addEventListener("dblclick", () => openElementLinks());
  273.  
  274. GM_registerMenuCommand(i18n.oeu, () => openElementLinks());
  275.  
  276.  
  277. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址