米游社刷新提醒工具

用于米游社电脑网页的甲板、候车室、酒馆、咖啡馆、律所、学园、大别野等模块的最新发帖页面自动页内刷新的工具,可以检索关键词并发声提醒你,在最新发帖页刷新页面即可启用脚本,用于获得最新一手的消息进行回复或处理。可以设置正则表达式检索和刷新时间间隔,正则表达式检索到结果后,可以进行一键复制。

  1. // ==UserScript==
  2. // @name 米游社刷新提醒工具
  3. // @namespace https://gf.qytechs.cn/users/1345081
  4. // @version 0.2.2
  5. // @description 用于米游社电脑网页的甲板、候车室、酒馆、咖啡馆、律所、学园、大别野等模块的最新发帖页面自动页内刷新的工具,可以检索关键词并发声提醒你,在最新发帖页刷新页面即可启用脚本,用于获得最新一手的消息进行回复或处理。可以设置正则表达式检索和刷新时间间隔,正则表达式检索到结果后,可以进行一键复制。
  6. // @icon data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABMLAAATCwAAAAAAAAAAAAD/2FkI/9hZSv/YV5P/3W+19cOaxvzv6NX////g///+6v///vL///74///+/P/////////+///+6v///Yn//vkT/9hZfP/YWe7/2Ff//tx7//XFpv/++vj////////////////////////////////////////////////6///9kP/YWej/2Fn//9lY//zXiP/2zrf///////zw6f/649b////////////////////////////////////////+/e3/2Fn9/9hZ///ZWv/6043/99PB///////2zLT/99C5/////////////////////////////////////v/42Mb+/9hZ///YWf//2Fj//NiJ//XIrv///f3//fPt//759v////////////328f/52sn///79///////76d7/87yY///YWf3/2Fn//9lb//7ikf/3zbD/+NfE///9/P/////////////////53c3/9MOn///////++/r/9cOl//vXkf3/2Fn7/9hX//7cdP/1w5z/9cWm//XIrf/2zLX//PDq/////v///////vn2//749f//////+d3P//fGkf//3Wn6/9hZ9//YWP/82IP/9suu//vWo//1w6H/+daq//XCmf/2y7P/+uHT//zv6P/99fH/++zk//TBoP/92n7//9hX9f/YWfL/2Vn/+9OK//jSt///7Lz/9cWk//3bfv//3G//+9iZ//XEp//0wqb/9cen//bEmv/7147//9pe///YWe//2Fnr/9pb//nPiv/52sf//vLa//XFof/+23L//9lX//vVjv/1wqH/9cKY//jSrv//4H///9lb///YWP//2Fnn/9hZ4//aW//5zon/+dzN//739P/2xZz//9tr///aX//4y5T/+t7C//7nuP/1xKP//tt4///YV///2Fn//9hZ3f/YWdb/2Fj//NaB//XIrf/76eH/9sSZ///baP//22P/98iX//zkyv/+7Mb/9sen//7cdf//2Ff//9hZ///YWdD/2Fm4/9hY///aY//60oz/9L2Z//fIlP//22P//9tk//fImP/87eP//vfv//bHo///3HH//9hX///YWf//2Fm+/9hZaf/YWff/2Fj//9pe//7bdf/+23D//9hZ///bYf/3ypb/++ng//759v/1xqH//9xx///YV///2Fn//9hZof/YWQz/2Fl5/9hZ1v/YWfH/2Ff8/9hY///YWf//2Vr/+9WM//XIr//76N7/9cOd///ccv//2Ff//9hZ8//YWVv/2FkA/9hZAv/YWRz/2FlD/9hZav/YWY3/2Fmr/9hYxf/ca9n50prp9L+f9ffJnf3/3Gn9/9hY5f/YWXz/2FkKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA==
  7. // @author zhangqiang
  8. // @license MIT
  9. // @match https://www.miyoushe.com/ys/home/26?type=2
  10. // @match https://www.miyoushe.com/bh2/home/30?type=2
  11. // @match https://www.miyoushe.com/bh3/home/1?type=2
  12. // @match https://www.miyoushe.com/sr/home/52?type=2
  13. // @match https://www.miyoushe.com/wd/home/37?type=2
  14. // @match https://www.miyoushe.com/zzz/home/57?type=2
  15. // @match https://www.miyoushe.com/dby/home/54?type=2
  16. // @match https://www.miyoushe.com/dby/home/35?type=2
  17. // @match https://www.miyoushe.com/dby/home/34?type=2
  18. // @grant none
  19. // ==/UserScript==
  20.  
  21. (function() {
  22. 'use strict';
  23.  
  24. // 音效URL
  25. const soundUrl = "https://uploadstatic.mihoyo.com/ys-obc/2022/05/12/8797197/429281fded26a537aa7c33319fa6e388_172369884487879995.mp3";
  26.  
  27. // 创建设置表单的容器
  28. const settingsContainer = document.createElement('div');
  29. settingsContainer.style.position = 'fixed';
  30. settingsContainer.style.right = '20px';
  31. settingsContainer.style.bottom = '50px';
  32. settingsContainer.style.backgroundColor = 'white';
  33. settingsContainer.style.padding = '10px';
  34. settingsContainer.style.borderRadius = '5px';
  35. settingsContainer.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
  36. settingsContainer.style.zIndex = '9999'; // 确保表单在顶层
  37. settingsContainer.style.width = '200px'; // 调整容器宽度
  38. document.body.appendChild(settingsContainer);
  39.  
  40. // 创建表单
  41. const settingsForm = document.createElement('form');
  42. settingsForm.style.display = 'flex'; // 使用Flexbox布局
  43. settingsForm.style.flexDirection = 'column'; // 垂直排列子元素
  44. settingsContainer.appendChild(settingsForm);
  45.  
  46. // 创建关键词输入框
  47. const keywordInput = document.createElement('input');
  48. keywordInput.type = 'text';
  49. keywordInput.placeholder = '输入关键词,用逗号分隔';
  50. keywordInput.style.width = '100%'; // 使输入框宽度适应容器
  51. keywordInput.style.marginBottom = '10px';
  52. settingsForm.appendChild(keywordInput);
  53.  
  54. // 创建时间间隔输入框
  55. const intervalInput = document.createElement('input');
  56. intervalInput.type = 'number';
  57. intervalInput.placeholder = '10 second';
  58. intervalInput.style.width = '90px';
  59. intervalInput.style.marginBottom = '10px';
  60. settingsForm.appendChild(intervalInput);
  61.  
  62. // 创建正则表达式勾选框和标签
  63. const regexContainer = document.createElement('div');
  64. regexContainer.style.display = 'flex';
  65. regexContainer.style.alignItems = 'center';
  66.  
  67. const regexCheckbox = document.createElement('input');
  68. regexCheckbox.type = 'checkbox';
  69. regexCheckbox.id = 'regexCheckbox';
  70. regexCheckbox.style.marginRight = '5px';
  71.  
  72. const regexLabel = document.createElement('label');
  73. regexLabel.htmlFor = 'regexCheckbox';
  74. regexLabel.textContent = '使用正则表达式';
  75.  
  76. regexContainer.appendChild(regexCheckbox);
  77. regexContainer.appendChild(regexLabel);
  78. settingsForm.appendChild(regexContainer); // 将整个容器添加到表单中
  79.  
  80. // 创建复制到剪贴板勾选框和标签
  81. const copyContainer = document.createElement('div');
  82. copyContainer.style.display = 'flex';
  83. copyContainer.style.alignItems = 'center';
  84. copyContainer.style.marginTop = '10px'; // 稍微留点空间
  85.  
  86. const copyCheckbox = document.createElement('input');
  87. copyCheckbox.type = 'checkbox';
  88. copyCheckbox.id = 'copyCheckbox';
  89. copyCheckbox.style.marginRight = '5px';
  90.  
  91. const copyLabel = document.createElement('label');
  92. copyLabel.htmlFor = 'copyCheckbox';
  93. copyLabel.textContent = '启用复制到剪贴板';
  94.  
  95.  
  96. copyContainer.appendChild(copyCheckbox);
  97. copyContainer.appendChild(copyLabel);
  98. settingsForm.appendChild(copyContainer); // 将整个容器添加到表单中
  99.  
  100. let enableCopyToClipboard = false; // 默认不启用复制到剪贴板
  101.  
  102. // 创建关键词高亮勾选框和标签
  103. const highlightContainer = document.createElement('div');
  104. highlightContainer.style.display = 'flex';
  105. highlightContainer.style.alignItems = 'center';
  106. highlightContainer.style.marginTop = '10px';
  107.  
  108. const highlightCheckbox = document.createElement('input');
  109. highlightCheckbox.type = 'checkbox';
  110. highlightCheckbox.id = 'highlightCheckbox';
  111. highlightCheckbox.style.marginRight = '5px';
  112.  
  113. const highlightLabel = document.createElement('label');
  114. highlightLabel.htmlFor = 'highlightCheckbox';
  115. highlightLabel.textContent = '启用关键词高亮';
  116.  
  117. highlightContainer.appendChild(highlightCheckbox);
  118. highlightContainer.appendChild(highlightLabel);
  119. settingsForm.appendChild(highlightContainer); // 将整个容器添加到表单中
  120.  
  121. let enableHighlight = false; // 默认不启用关键词高亮
  122.  
  123.  
  124. // 添加一个用于高亮文本的函数
  125. const highlightText = (bodyText, keywords, useRegex) => {
  126. const tempDiv = document.createElement('div');
  127. tempDiv.innerHTML = bodyText;
  128. const walker = document.createTreeWalker(
  129. tempDiv,
  130. NodeFilter.SHOW_TEXT,
  131. {
  132. acceptNode: function(node) {
  133. return NodeFilter.FILTER_ACCEPT;
  134. }
  135. },
  136. false
  137. );
  138.  
  139. let currentNode;
  140. while ((currentNode = walker.nextNode())) {
  141. let text = currentNode.textContent;
  142. for (const keyword of keywords) {
  143. let regexPattern = useRegex ? new RegExp(keyword.trim(), 'gi') : new RegExp(keyword.trim(), 'gi');
  144. let match;
  145. while ((match = regexPattern.exec(text)) !== null) {
  146. let matchText = match[0];
  147. let span = document.createElement('span');
  148. span.style.backgroundColor = 'yellow'; // 设置为黄色高亮
  149. span.textContent = matchText;
  150.  
  151. // 使用range和surroundContents替换文本节点
  152. let range = document.createRange();
  153. range.setStart(currentNode, match.index);
  154. range.setEnd(currentNode, match.index + matchText.length);
  155. let frag = range.extractContents();
  156. span.appendChild(frag);
  157. range.insertNode(span);
  158.  
  159. // 由于已经修改了DOM,需要更新text和index
  160. text = currentNode.textContent;
  161. regexPattern.lastIndex = 0; // 重置lastIndex
  162. }
  163. }
  164. }
  165.  
  166. // 将修改后的HTML内容设置回body(这里可能需要更复杂的逻辑来处理实际页面结构)
  167. // 这里为了简化,我们假设可以直接替换body的innerHTML(实际使用时可能需要更精细的控制)
  168. document.body.innerHTML = tempDiv.innerHTML;
  169. };
  170.  
  171.  
  172. // 创建删除footer勾选框和标签
  173. const removeFooterContainer = document.createElement('div');
  174. removeFooterContainer.style.display = 'flex';
  175. removeFooterContainer.style.alignItems = 'center';
  176. removeFooterContainer.style.marginTop = '10px';
  177.  
  178. const removeFooterCheckbox = document.createElement('input');
  179. removeFooterCheckbox.type = 'checkbox';
  180. removeFooterCheckbox.id = 'removeFooterCheckbox';
  181. removeFooterCheckbox.style.marginRight = '5px';
  182.  
  183. const removeFooterLabel = document.createElement('label');
  184. removeFooterLabel.htmlFor = 'removeFooterCheckbox';
  185. removeFooterLabel.textContent = '隐藏页面底部(footer)';
  186.  
  187. removeFooterContainer.appendChild(removeFooterCheckbox);
  188. removeFooterContainer.appendChild(removeFooterLabel);
  189. settingsForm.appendChild(removeFooterContainer); // 将整个容器添加到表单中
  190.  
  191. let removeFooter = false; // 默认不删除footer
  192.  
  193.  
  194. // 监听复选框的变化
  195. removeFooterCheckbox.addEventListener('change', function() {
  196. if (this.checked) {
  197. // 删除footer
  198. const footerElements = document.querySelectorAll('.footer');
  199. footerElements.forEach(footer => {
  200. footer.remove();
  201. });
  202.  
  203. // 如果需要,在这里添加代码来隐藏或删除复选框和标签
  204. // 例如,隐藏整个容器
  205. removeFooterContainer.style.display = 'none';
  206.  
  207. // 或者从DOM中移除整个容器
  208. // settingsForm.removeChild(removeFooterContainer);
  209. }
  210.  
  211. });
  212.  
  213. // 创建复制关键词到剪贴板的按钮
  214. const copyButton = document.createElement('button');
  215. copyButton.type = 'button';
  216. copyButton.textContent = '复制关键词';
  217. copyButton.style.width = '100%';
  218. copyButton.style.backgroundColor = '#28a745';
  219. copyButton.style.color = 'white';
  220. copyButton.style.padding = '10px';
  221. copyButton.style.border = 'none';
  222. copyButton.style.borderRadius = '5px';
  223. copyButton.style.cursor = 'pointer';
  224. copyButton.style.display = 'none'; // 默认不显示
  225. copyButton.id = 'copyButton'; // 设置ID
  226. copyButton.classList.add('copy-button'); // 设置类名
  227. settingsForm.appendChild(copyButton); // 将按钮添加到表单中
  228.  
  229. // 自动点击复制关键词按钮的函数
  230. function autoClickCopyButton() {
  231. // 使用延迟执行,确保DOM元素已经加载完成
  232. setTimeout(function() {
  233. const button = document.getElementById('copyButton');
  234. if (button) {
  235. button.click(); // 触发点击事件
  236. }
  237. }, 1000); // 等待1秒后执行点击
  238. }
  239.  
  240.  
  241. // 监听复制到剪贴板勾选框的变化
  242. copyCheckbox.addEventListener('change', function() {
  243. if (this.checked) {
  244. copyButton.style.display = 'block'; // 勾选时显示按钮
  245. } else {
  246. copyButton.style.display = 'none'; // 未勾选时隐藏按钮
  247. }
  248. });
  249.  
  250. // 复制按钮的点击事件
  251. copyButton.addEventListener('click', function() {
  252. // 假设我们有一个全局变量或方法来获取当前页面中的文本
  253. // 这里为了示例,我们直接使用document.body.textContent
  254. // 在实际应用中,你可能需要更精确地定位到包含关键词的文本部分
  255. const bodyText = document.body.textContent;
  256. const copied = checkKeywords(bodyText); // 调用checkKeywords函数并尝试复制
  257.  
  258. });
  259.  
  260.  
  261. // 创建开始按钮
  262. const startButton = document.createElement('button');
  263. startButton.type = 'button';
  264. startButton.textContent = '开始自动刷新';
  265. startButton.style.width = '100%';
  266. startButton.style.backgroundColor = '#007bff';
  267. startButton.style.color = 'white';
  268. startButton.style.padding = '10px';
  269. startButton.style.border = 'none';
  270. startButton.style.borderRadius = '5px';
  271. startButton.style.cursor = 'pointer';
  272. startButton.id = 'startButton';
  273. settingsForm.appendChild(startButton);
  274.  
  275. // 检查startButton的文字,并更改样式
  276. function checkStartButtonTextChange() {
  277. const startButton = document.getElementById('startButton');
  278. if (startButton.textContent.trim() === '开始自动刷新') {
  279. startButton.style.backgroundColor = '#007bff'; // 更改背景颜色为蓝色
  280. //autoClickCopyButton();
  281. } else if (startButton.textContent.trim() === '停止自动刷新') {
  282. startButton.style.backgroundColor = 'red'; // 更改背景颜色为红色
  283. }
  284. }
  285.  
  286. // 定义一个定时器来定期检查startButton的文字
  287. //let buttonTextCheckInterval = setInterval(checkStartButtonTextChange, 1000); // 每秒检查一次
  288.  
  289.  
  290. let intervalId = null;
  291. let isRunning = false;
  292. let keywords = [];
  293. let intervalTime = 10000; // 默认时间间隔为10秒
  294. let useRegex = false; // 默认不使用正则表达式
  295.  
  296. // 更新设置
  297. const updateSettings = () => {
  298. keywords = keywordInput.value.split(',');
  299. intervalTime = parseInt(intervalInput.value, 10) * 1000 || 10000;
  300. useRegex = regexCheckbox.checked;
  301. enableCopyToClipboard = copyCheckbox.checked; // 更新是否启用复制到剪贴板
  302. };
  303.  
  304.  
  305.  
  306. // 检查关键词是否存在(根据是否使用正则表达式)
  307. const checkKeywords = (bodyText) => {
  308. for (const keyword of keywords) {
  309. let matchText = '';
  310. if (useRegex) {
  311. const regexPattern = new RegExp(keyword.trim(), 'gi');
  312. let match;
  313. while ((match = regexPattern.exec(bodyText)) !== null) {
  314. matchText = match[0];
  315. break;
  316. }
  317. if (matchText) {
  318. // 找到了关键词,返回 true 表示需要停止刷新
  319. return { stop: true, keyword: matchText };
  320. }
  321. } else {
  322. if (bodyText.includes(keyword.trim())) {
  323. // 找到了关键词,返回 true 表示需要停止刷新
  324. return { stop: true, keyword: keyword.trim() };
  325. }
  326. }
  327. }
  328. return { stop: false, keyword: '' };
  329. };
  330.  
  331.  
  332.  
  333. // 复制文本到剪贴板
  334. const copyToClipboard = (text) => {
  335. if (!enableCopyToClipboard) return; // 如果未启用复制到剪贴板,则直接返回
  336.  
  337. const textarea = document.createElement('textarea');
  338. textarea.value = text;
  339. document.body.appendChild(textarea);
  340. textarea.select();
  341.  
  342. try {
  343. document.execCommand('copy');
  344. console.log('关键词已复制到剪贴板!');
  345. } catch (err) {
  346. console.error('无法复制文本: ', err);
  347. }
  348.  
  349. document.body.removeChild(textarea);
  350. };
  351.  
  352. // 复制按钮的点击事件
  353. copyButton.addEventListener('click', function() {
  354. // 获取当前页面中的文本
  355. const bodyText = document.body.textContent;
  356.  
  357. // 调用checkKeywords函数并尝试复制
  358. const { stop, keyword } = checkKeywords(bodyText);
  359.  
  360. if (stop) {
  361. copyToClipboard(keyword); // 直接调用复制函数
  362. } else {
  363. copyToClipboard(keyword);
  364. }
  365. });
  366.  
  367.  
  368. // 确保页面加载完成后再检查关键词
  369. const waitForPageLoadAndCheckKeywords = () => {
  370. setTimeout(() => {
  371. const bodyText = document.body.textContent;
  372. const { stop, keyword } = checkKeywords(bodyText);
  373. if (stop) {
  374. clearInterval(intervalId);
  375. isRunning = false;
  376. startButton.textContent = '开始自动刷新';
  377.  
  378. // 播放音效
  379. const audio = new Audio(soundUrl);
  380. audio.play();
  381.  
  382. // 复制关键词到剪贴板
  383. autoClickCopyButton();
  384. copyToClipboard(keyword);
  385. }
  386. }, 500); // 假设页面加载需要最多3秒
  387. };
  388.  
  389. startButton.addEventListener('click', function() {
  390. updateSettings();
  391.  
  392. if (isRunning) {
  393. clearInterval(intervalId);
  394. startButton.textContent = '开始自动刷新';
  395. isRunning = false;
  396. } else {
  397. intervalId = setInterval(() => {
  398. const latestPostButton = document.querySelector('.mhy-tab__label');
  399. if (latestPostButton && latestPostButton.textContent === '最新发帖') {
  400. latestPostButton.click();
  401. waitForPageLoadAndCheckKeywords(); // 页面加载完成后检查关键词
  402. }
  403. }, intervalTime);
  404. startButton.textContent = '停止自动刷新';
  405. isRunning = true;
  406. }
  407. });
  408. })();

QingJ © 2025

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