MG-Linkcollector

提取页面中的磁力\Ed2k链接并收集到文本框中,支持跨网页收集,文本框内容实时更新。快捷键:监测当前页面(Alt+Q),删除当前链接(Alt+W),清除全部(Alt+A),一键复制(Alt+S),展开/关闭(无快捷键)。新增功能:自动获取新标签页的链接,聚焦页面超过2秒后再次自动获取。

  1. // ==UserScript==
  2. // @name MG-Linkcollector
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.1.5
  5. // @description 提取页面中的磁力\Ed2k链接并收集到文本框中,支持跨网页收集,文本框内容实时更新。快捷键:监测当前页面(Alt+Q),删除当前链接(Alt+W),清除全部(Alt+A),一键复制(Alt+S),展开/关闭(无快捷键)。新增功能:自动获取新标签页的链接,聚焦页面超过2秒后再次自动获取。
  6. // @author 黄萌萌可爱多
  7. // @match *://*/*
  8. // @license MIT
  9. // @grant GM_registerMenuCommand
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_setClipboard
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // 提取磁力链接和Ed2k链接
  19. function extractMagnetLinks() {
  20. var magnetLinks = [];
  21. var linkElements = document.getElementsByTagName('a');
  22. for (var i = 0; i < linkElements.length; i++) {
  23. var linkElement = linkElements[i];
  24. var link = linkElement.href;
  25. if (link.startsWith('magnet:') || link.startsWith('ed2k:')) {
  26. magnetLinks.push(link);
  27. }
  28. }
  29. var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
  30. while (walker.nextNode()) {
  31. var node = walker.currentNode;
  32. var text = node.textContent.trim();
  33. if (text.startsWith('magnet:') || text.startsWith('ed2k:')) {
  34. magnetLinks.push(text);
  35. }
  36. }
  37. return magnetLinks;
  38. }
  39.  
  40. // 从localStorage中获取已保存的磁力链接
  41. function getSavedMagnetLinks() {
  42. var savedLinks = localStorage.getItem('magnetLinks');
  43. return savedLinks ? JSON.parse(savedLinks) : [];
  44. }
  45.  
  46. // 将新的磁力链接保存到localStorage
  47. function saveMagnetLinks(magnetLinks) {
  48. var savedLinks = getSavedMagnetLinks();
  49. var combinedLinks = Array.from(new Set([...savedLinks, ...magnetLinks]));
  50. try {
  51. localStorage.setItem('magnetLinks', JSON.stringify(combinedLinks));
  52. } catch (e) {
  53. if (e instanceof DOMException && e.code === 22) {
  54. console.warn('localStorage空间不足,正在清理旧数据...');
  55. var maxLinks = 100;
  56. if (combinedLinks.length > maxLinks) {
  57. combinedLinks = combinedLinks.slice(-maxLinks);
  58. }
  59. localStorage.setItem('magnetLinks', JSON.stringify(combinedLinks));
  60. console.log('清理完成,现在可以继续保存新数据。');
  61. } else {
  62. throw e;
  63. }
  64. }
  65. }
  66.  
  67. // 删除当前页面的磁力链接
  68. function deleteCurrentPageLinks(currentLinks) {
  69. var savedLinks = getSavedMagnetLinks();
  70. var updatedLinks = savedLinks.filter(link => !currentLinks.includes(link));
  71. localStorage.setItem('magnetLinks', JSON.stringify(updatedLinks));
  72. }
  73.  
  74. // 清除所有磁力链接
  75. function clearAllLinks() {
  76. localStorage.removeItem('magnetLinks');
  77. alert('已清除全部链接'); // 添加提醒
  78. }
  79.  
  80. // 更新文本框内容
  81. function updateTextBox() {
  82. var textBox = document.getElementById('magnetLinksBox');
  83. var savedLinks = getSavedMagnetLinks();
  84. textBox.value = savedLinks.map((link, index) => `${index + 1}. ${link}`).join('\n');
  85. }
  86.  
  87. // 创建文本框和悬浮按钮
  88. function createTextBoxAndButtons() {
  89. var textBox = document.createElement('textarea');
  90. textBox.id = 'magnetLinksBox';
  91. textBox.style.position = 'fixed';
  92. textBox.style.bottom = '200px';
  93. textBox.style.right = '10px';
  94. textBox.style.width = '300px';
  95. textBox.style.height = '200px';
  96. textBox.style.zIndex = '9999';
  97. textBox.placeholder = '提取的磁力链接将显示在这里...';
  98. textBox.readOnly = true; // 设置为只读
  99. document.body.appendChild(textBox);
  100.  
  101. var deleteCurrentButton = document.createElement('button');
  102. deleteCurrentButton.id = 'deleteCurrentLinksButton';
  103. deleteCurrentButton.title = '快捷键: Alt+W';
  104. deleteCurrentButton.style.position = 'fixed';
  105. deleteCurrentButton.style.bottom = '60px';
  106. deleteCurrentButton.style.right = '10px';
  107. deleteCurrentButton.style.width = '70px'; // 修改: 100px -> 70px
  108. deleteCurrentButton.style.height = '28px'; // 修改: 40px -> 28px
  109. deleteCurrentButton.style.zIndex = '9999';
  110. deleteCurrentButton.style.background = '#FF9800';
  111. deleteCurrentButton.style.color = 'white';
  112. deleteCurrentButton.style.border = 'none';
  113. deleteCurrentButton.style.borderRadius = '5px';
  114. deleteCurrentButton.style.cursor = 'pointer';
  115. deleteCurrentButton.style.fontSize = '10px'; // 修改: 14px -> 10px
  116. deleteCurrentButton.textContent = '删当前链接';
  117. deleteCurrentButton.addEventListener('click', function() {
  118. var currentLinks = extractMagnetLinks();
  119. deleteCurrentPageLinks(currentLinks);
  120. updateTextBox();
  121. });
  122. document.body.appendChild(deleteCurrentButton);
  123.  
  124. var clearAllButton = document.createElement('button');
  125. clearAllButton.id = 'clearAllLinksButton';
  126. clearAllButton.title = '快捷键: Alt+A';
  127. clearAllButton.style.position = 'fixed';
  128. clearAllButton.style.bottom = '160px';
  129. clearAllButton.style.right = '10px';
  130. clearAllButton.style.width = '70px'; // 修改: 100px -> 70px
  131. clearAllButton.style.height = '28px'; // 修改: 40px -> 28px
  132. clearAllButton.style.zIndex = '9999';
  133. clearAllButton.style.background = '#F44336';
  134. clearAllButton.style.color = 'white';
  135. clearAllButton.style.border = 'none';
  136. clearAllButton.style.borderRadius = '5px';
  137. clearAllButton.style.cursor = 'pointer';
  138. clearAllButton.style.fontSize = '10px'; // 修改: 14px -> 10px
  139. clearAllButton.textContent = '清除全部';
  140. clearAllButton.addEventListener('click', function() {
  141. clearAllLinks();
  142. updateTextBox();
  143. });
  144. document.body.appendChild(clearAllButton);
  145.  
  146. var copyButton = document.createElement('button');
  147. copyButton.id = 'copyLinksButton';
  148. copyButton.title = '快捷键: Alt+S';
  149. copyButton.style.position = 'fixed';
  150. copyButton.style.bottom = '110px';
  151. copyButton.style.right = '10px';
  152. copyButton.style.width = '70px'; // 修改: 100px -> 70px
  153. copyButton.style.height = '28px'; // 修改: 40px -> 28px
  154. copyButton.style.zIndex = '9999';
  155. copyButton.style.background = '#2196F3';
  156. copyButton.style.color = 'white';
  157. copyButton.style.border = 'none';
  158. copyButton.style.borderRadius = '5px';
  159. copyButton.style.cursor = 'pointer';
  160. copyButton.style.fontSize = '10px'; // 修改: 14px -> 10px
  161. copyButton.textContent = '一键复制';
  162. copyButton.addEventListener('click', function() {
  163. var savedLinks = getSavedMagnetLinks();
  164. GM_setClipboard(savedLinks.join('\n'), 'text');
  165. alert('已复制所有链接到剪贴板!');
  166. });
  167. document.body.appendChild(copyButton);
  168.  
  169. var toggleButton = document.createElement('button');
  170. toggleButton.id = 'toggleLinksBoxButton';
  171. toggleButton.title = '展开/关闭';
  172. toggleButton.style.position = 'fixed';
  173. toggleButton.style.bottom = '10px';
  174. toggleButton.style.right = '10px';
  175. toggleButton.style.width = '70px'; // 修改: 100px -> 70px
  176. toggleButton.style.height = '28px'; // 修改: 40px -> 28px
  177. toggleButton.style.zIndex = '9999';
  178. toggleButton.style.background = '#4CAF50';
  179. toggleButton.style.color = 'white';
  180. toggleButton.style.border = 'none';
  181. toggleButton.style.borderRadius = '5px';
  182. toggleButton.style.cursor = 'pointer';
  183. toggleButton.style.fontSize = '10px'; // 修改: 14px -> 10px
  184. toggleButton.textContent = '展开/关闭';
  185. toggleButton.addEventListener('click', function() {
  186. var textBox = document.getElementById('magnetLinksBox');
  187. if (textBox.style.display === 'none') {
  188. textBox.style.display = 'block';
  189. GM_setValue('textBoxVisible', true);
  190. } else {
  191. textBox.style.display = 'none';
  192. GM_setValue('textBoxVisible', false);
  193. }
  194. });
  195. document.body.appendChild(toggleButton);
  196. }
  197.  
  198. // 绑定快捷键
  199. function bindHotkeys() {
  200. document.addEventListener('keydown', function(event) {
  201. if (event.altKey) {
  202. switch (event.key.toLowerCase()) {
  203. case 'w':
  204. document.getElementById('deleteCurrentLinksButton').click();
  205. break;
  206. case 'a':
  207. document.getElementById('clearAllLinksButton').click();
  208. break;
  209. case 's':
  210. document.getElementById('copyLinksButton').click();
  211. break;
  212. }
  213. }
  214. });
  215. }
  216.  
  217. // 监听localStorage变化并更新文本框
  218. function setupStorageListener() {
  219. window.addEventListener('storage', function(event) {
  220. if (event.key === 'magnetLinks') {
  221. updateTextBox();
  222. }
  223. });
  224. }
  225.  
  226. // 自动获取链接的逻辑
  227. function autoExtractLinks() {
  228. var newMagnetLinks = extractMagnetLinks();
  229. saveMagnetLinks(newMagnetLinks);
  230. updateTextBox();
  231. }
  232.  
  233. // 监听窗口焦点变化
  234. function listenFocusEvents() {
  235. let lastFocusTime = Date.now();
  236. let isFocused = false;
  237.  
  238. window.addEventListener('focus', function() {
  239. isFocused = true;
  240. let currentTime = Date.now();
  241. if (currentTime - lastFocusTime > 2000) { // 超过2秒
  242. autoExtractLinks();
  243. }
  244. lastFocusTime = currentTime;
  245. });
  246.  
  247. window.addEventListener('blur', function() {
  248. isFocused = false;
  249. });
  250. }
  251.  
  252. // 检查当前页面是否在允许的网站列表中
  253. function isAllowedSite() {
  254. var allowAllSites = GM_getValue('allowAllSites', true);
  255. if (allowAllSites) {
  256. return true;
  257. }
  258. var allowedSites = GM_getValue('allowedSites', '').split('\n').map(site => site.trim()).filter(site => site !== '');
  259. var currentUrl = window.location.href;
  260. for (var site of allowedSites) {
  261. if (currentUrl.startsWith(site)) {
  262. return true;
  263. }
  264. }
  265. return false;
  266. }
  267.  
  268. // 油猴面板设置
  269. function setupSettings() {
  270. GM_registerMenuCommand('设置', function() {
  271. var hideButtons = GM_getValue('hideButtons', false);
  272. var version = GM_info.script.version;
  273. var author = GM_info.script.author;
  274. var allowedSites = GM_getValue('allowedSites', '');
  275. var allowAllSites = GM_getValue('allowAllSites', true);
  276.  
  277. var html = `
  278. <div style="padding: 30px; background-color: white; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 2px 30px rgba(0, 0, 0, 0.1); width: 400px; height: 300px; font-size: 18px;">
  279. <h2>设置</h2>
  280. <p>作者: ${author}</p>
  281. <p>版本: ${version}</p>
  282. <label style="display: flex; align-items: center;">
  283. <span style="margin-right: 10px;">隐藏悬浮按钮</span>
  284. <label class="switch">
  285. <input type="checkbox" id="hideButtonsCheckbox" ${hideButtons ? 'checked' : ''}>
  286. <span class="slider round"></span>
  287. </label>
  288. </label>
  289. <br>
  290. <label style="display: flex; align-items: center;">
  291. <span style="margin-right: 10px;">允许适用脚本于任何网站</span>
  292. <label class="switch">
  293. <input type="checkbox" id="allowAllSitesCheckbox" ${allowAllSites ? 'checked' : ''}>
  294. <span class="slider round"></span>
  295. </label>
  296. </label>
  297. <br>
  298. <label style="display: flex; align-items: center;">
  299. <span style="margin-right: 10px;">仅允许用该脚本的网站(每行一个URL)</span>
  300. <textarea id="allowedSitesTextarea" style="width: 300px; height: 100px;">${allowedSites}</textarea>
  301. </label>
  302. <br>
  303. <button id="saveSettingsButton" style="margin-top: 20px; padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;">保存</button>
  304. <button id="closeSettingsButton" style="margin-top: 10px; padding: 10px 20px; background-color: #F44336; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;">关闭</button>
  305. </div>
  306. `;
  307. var div = document.createElement('div');
  308. div.innerHTML = html;
  309. div.style.position = 'fixed';
  310. div.style.top = '50%';
  311. div.style.left = '50%';
  312. div.style.transform = 'translate(-50%, -50%)';
  313. div.style.zIndex = '10000';
  314. document.body.appendChild(div);
  315.  
  316. document.getElementById('saveSettingsButton').addEventListener('click', function() {
  317. var hideButtonsCheckbox = document.getElementById('hideButtonsCheckbox');
  318. GM_setValue('hideButtons', hideButtonsCheckbox.checked);
  319.  
  320. var allowAllSitesCheckbox = document.getElementById('allowAllSitesCheckbox');
  321. GM_setValue('allowAllSites', allowAllSitesCheckbox.checked);
  322.  
  323. var allowedSitesTextarea = document.getElementById('allowedSitesTextarea');
  324. GM_setValue('allowedSites', allowedSitesTextarea.value);
  325.  
  326. document.body.removeChild(div);
  327.  
  328. // 根据设置显示或隐藏悬浮按钮和文本框
  329. if (hideButtonsCheckbox.checked) {
  330. document.getElementById('magnetLinksBox').style.display = 'none';
  331. document.getElementById('toggleLinksBoxButton').style.display = 'none';
  332. document.getElementById('deleteCurrentLinksButton').style.display = 'none';
  333. document.getElementById('copyLinksButton').style.display = 'none';
  334. document.getElementById('clearAllLinksButton').style.display = 'none';
  335. document.getElementById('monitorCurrentLinksButton').style.display = 'none';
  336. } else {
  337. document.getElementById('magnetLinksBox').style.display = 'block';
  338. document.getElementById('toggleLinksBoxButton').style.display = 'block';
  339. document.getElementById('deleteCurrentLinksButton').style.display = 'block';
  340. document.getElementById('copyLinksButton').style.display = 'block';
  341. document.getElementById('clearAllLinksButton').style.display = 'block';
  342. document.getElementById('monitorCurrentLinksButton').style.display = 'block';
  343. }
  344. });
  345.  
  346. document.getElementById('closeSettingsButton').addEventListener('click', function() {
  347. document.body.removeChild(div);
  348. });
  349. });
  350. }
  351.  
  352. // 主逻辑
  353. if (isAllowedSite()) {
  354. createTextBoxAndButtons();
  355. bindHotkeys();
  356. setupStorageListener();
  357. listenFocusEvents();
  358. setupSettings(); // 恢复设置菜单
  359. autoExtractLinks(); // 初始加载时自动获取一次
  360.  
  361. // 根据设置显示或隐藏悬浮按钮和文本框
  362. if (GM_getValue('hideButtons', false)) {
  363. document.getElementById('magnetLinksBox').style.display = 'none';
  364. document.getElementById('toggleLinksBoxButton').style.display = 'none';
  365. document.getElementById('deleteCurrentLinksButton').style.display = 'none';
  366. document.getElementById('copyLinksButton').style.display = 'none';
  367. document.getElementById('clearAllLinksButton').style.display = 'none';
  368. document.getElementById('monitorCurrentLinksButton').style.display = 'none';
  369. } else {
  370. // 根据localStorage中的状态设置文本框的显示状态
  371. var textBox = document.getElementById('magnetLinksBox');
  372. var textBoxVisible = GM_getValue('textBoxVisible', true); // 默认展开
  373. textBox.style.display = textBoxVisible ? 'block' : 'none';
  374. }
  375. } else {
  376. console.log('当前网站不在允许的网站列表中,脚本不执行。');
  377. }
  378. })();