JS practice for S1

JS练习脚本

  1. // ==UserScript==
  2. // @name JS practice for S1
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.214
  5. // @description JS练习脚本
  6. // @author Lery
  7. // @include *://*.saraba1st.com/2b/*
  8. // @include *://*.stage1st.com/2b/*
  9. // @include *://stage1st.com/2b/*
  10. // @include *://*.stage1.cc/2b/*
  11. // @grant GM_xmlhttpRequest
  12. // @grant GM_addStyle
  13. // @require https://cdnjs.cloudflare.com/ajax/libs/store.js/1.3.20/store.min.js
  14. // ==/UserScript==
  15.  
  16. // 1. 自动对旧链接进行修改跳转
  17. const oldUrlPattern = /^([^.]+\\.)?(saraba1st|stage1(st)?)\\.(com|cc)\/2b\/read/;
  18. if (oldUrlPattern.test(location.href)) {
  19. const tid = location.href.split("tid-")[1].split(".html")[0];
  20. location.href = `https://${location.hostname}/2b/thread-${tid}-1-1.html`;
  21. }
  22.  
  23. // 2. 修改网页标题后缀
  24. const titlePattern = /^(.+?)(?:论坛)?(?:\s*-\s*Stage1st)?\s*-\s*stage1\/s1\s+游戏动漫论坛$/;
  25. if (titlePattern.test(document.title)) {
  26. document.title = document.title.replace(titlePattern, '$1') + " - STAGE1ₛₜ";
  27. }
  28.  
  29. // 3. 自动签到
  30. const signLink = document.querySelector('a[href*="study_daily_attendance-daily_attendance.html"]');
  31. if (signLink) {
  32. const pipeSeparator = signLink.nextElementSibling?.classList.contains('pipe')
  33. ? signLink.nextElementSibling
  34. : null;
  35.  
  36. // 异步处理避免阻塞主线程
  37. setTimeout(() => {
  38. if (typeof ajaxget === 'function') {
  39. ajaxget(signLink.href);
  40. }
  41.  
  42. pipeSeparator?.remove();
  43. signLink.remove();
  44. }, 100);
  45. }
  46.  
  47. // 4. 点击更换漫区随机图
  48. const randomPic = document.querySelector('img[src^="https://ac.stage3rd.com/S1_ACG_randpic.asp"]');
  49. if (randomPic) {
  50. randomPic.addEventListener('click', function() {
  51. this.src = `https://ac.stage3rd.com/S1_ACG_randpic.asp?t=${Date.now()}`;
  52. });
  53.  
  54. // 添加视觉反馈
  55. randomPic.style.cursor = 'pointer';
  56. randomPic.title = '点击更换图片';
  57. }
  58.  
  59. // 5. 滚动位置记录(节流优化)
  60. let scrollTimer = null;
  61. window.addEventListener('scroll', () => {
  62. clearTimeout(scrollTimer);
  63. scrollTimer = setTimeout(() => {
  64. // 添加滚动事件处理逻辑
  65. }, 500);
  66. });
  67.  
  68. // 6. 自定义快捷入口函数
  69. function createLink(name, addr) {
  70. const node = document.createElement("li");
  71. const link = document.createElement("a");
  72.  
  73. if (`${location.pathname}${location.search}` === `/2b/${addr}`) {
  74. node.className = "a";
  75. }
  76.  
  77. link.href = addr;
  78. link.hideFocus = true;
  79. link.textContent = name;
  80. node.appendChild(link);
  81.  
  82. return node;
  83. }
  84.  
  85. // 7. 重构导航栏更新逻辑
  86. const navList = document.getElementById("nv")?.querySelector("ul");
  87. if (navList) {
  88. // 获取论坛跳转数据
  89. GM_xmlhttpRequest({
  90. method: "GET",
  91. url: `https://${location.hostname}/2b/forum.php?mod=ajax&action=forumjump`,
  92. onload: function(response) {
  93. try {
  94. const match = response.responseText.match(/<div id="flsrchdiv">[\s\S]+?(?=<script)/);
  95. if (!match) return;
  96.  
  97. const parser = new DOMParser();
  98. const doc = parser.parseFromString(match[0], "text/html");
  99. const forumItems = doc.querySelectorAll('.jump_bdl li:nth-child(3) p a');
  100.  
  101. // 清空现有导航
  102. while (navList.firstChild) {
  103. navList.removeChild(navList.firstChild);
  104. }
  105.  
  106. // 添加收藏板块
  107. if (forumItems.length) {
  108. const namePattern = /.*?(?=论坛|$)/;
  109. forumItems.forEach(item => {
  110. const nameMatch = item.textContent.match(namePattern);
  111. const name = nameMatch ? nameMatch[0] : item.textContent;
  112. navList.appendChild(createLink(name, item.href));
  113. });
  114. }
  115.  
  116. // 添加默认快捷入口
  117. [
  118. ["抹布", "home.php?mod=space&do=friend&view=blacklist"],
  119. ["客户端", "thread-1486168-1-1.html"],
  120. ["我的回复", "home.php?mod=space&do=thread&view=me&type=reply"]
  121. ].forEach(([name, url]) => {
  122. navList.appendChild(createLink(name, url));
  123. });
  124.  
  125. } catch (error) {
  126. console.error('导航更新失败:', error);
  127. }
  128. },
  129. onerror: function(error) {
  130. console.error('请求论坛数据失败:', error);
  131. }
  132. });
  133. }
  134.  
  135. // 8. 阅读记录系统(优化存储和显示逻辑)
  136. const forumPattern = /forum\.php\?mod=(forumdisplay|viewthread)|(forum|thread)(-[0-9]+)+\.html/;
  137. if (forumPattern.test(location.href) && store.enabled) {
  138. const lasttime = store.get('lasttime') || {};
  139. const lastread = store.get('lastread') || {};
  140. const lastrc = store.get('lastrc') || {};
  141.  
  142. // 帖内浏览处理
  143. if (unsafeWindow.tid) {
  144. // 记录浏览时间
  145. const now = new Date();
  146. const hoursSinceEpoch = now.getTime() / 3600000 + now.getTimezoneOffset() / 60;
  147. lasttime[unsafeWindow.tid] = hoursSinceEpoch || 1;
  148. store.set('lasttime', lasttime);
  149.  
  150. // 记录当前回复数
  151. GM_xmlhttpRequest({
  152. method: "GET",
  153. url: `https://${location.hostname}/2b/api/mobile/index.php?module=viewthread&tid=${unsafeWindow.tid}`,
  154. onload: function(response) {
  155. try {
  156. const json = JSON.parse(response.responseText);
  157. const replies = json.Variables?.thread?.replies || 1;
  158. lastrc[unsafeWindow.tid] = replies;
  159. store.set('lastrc', lastrc);
  160. } catch (e) {
  161. console.error('解析回复数失败:', e);
  162. }
  163. }
  164. });
  165.  
  166. // 记录当前页码
  167. const pageEl = document.querySelector('#pgt > div > div > strong');
  168. lastread[unsafeWindow.tid] = pageEl?.textContent || 1;
  169. store.set('lastread', lastread);
  170.  
  171. }
  172. // 主题列表处理
  173. else {
  174. const table = document.querySelector('form[name="moderate"] table');
  175. if (table) {
  176. const tbodys = table.querySelectorAll('tbody[id^="normalthread_"]');
  177.  
  178. tbodys.forEach(tbody => {
  179. const [, tid] = tbody.id.split('_');
  180. if (!tid) return;
  181.  
  182. const page = lastread[tid];
  183. if (!page) return;
  184.  
  185. // 计算时间差颜色
  186. const currentHours = new Date().getTime() / 3600000 + new Date().getTimezoneOffset() / 60;
  187. const hoursDiff = currentHours - (lasttime[tid] || 0);
  188. const fcolor = getTimeBasedColor(hoursDiff);
  189.  
  190. // 创建回页链接
  191. const pageLink = createPageLink(tid, page, fcolor);
  192.  
  193. // 检查新回复
  194. const replyEl = tbody.querySelector('tr > .num > .xi2');
  195. const currentReplies = parseInt(replyEl?.textContent) || 0;
  196. const oldReplies = lastrc[tid] || 0;
  197.  
  198. if (currentReplies > oldReplies) {
  199. const newReplies = currentReplies - oldReplies;
  200. const badge = createReplyBadge(newReplies, fcolor);
  201. pageLink.style.borderRadius = '4px 0 0 4px';
  202. tbody.querySelector('tr > th').append(pageLink, badge);
  203. } else {
  204. pageLink.style.borderRadius = '4px';
  205. tbody.querySelector('tr > th').append(pageLink);
  206. }
  207. });
  208. }
  209. }
  210. }
  211.  
  212. // 辅助函数:根据时间差获取颜色
  213. function getTimeBasedColor(hours) {
  214. if (hours <= 1) return 'rgb(192,51,34)';
  215. if (hours <= 24) return `rgb(${192 - hours}, ${51 + hours/4}, ${34 + hours/2})`;
  216. if (hours <= 168) return `rgb(${168 - (hours-24)*5/9}, ${57 + (hours-24)/6}, ${46 + (hours-24)/4})`;
  217. return 'rgb(85,83,83)';
  218. }
  219.  
  220. // 辅助函数:创建页码链接
  221. function createPageLink(tid, page, color) {
  222. const link = document.createElement('a');
  223. link.textContent = `回第${page}页`;
  224. link.style.cssText = `
  225. color: ${color};
  226. font-weight: bold;
  227. padding: 1px 3px;
  228. border: 1px solid ${color};
  229. margin-left: 5px;
  230. display: inline-block;
  231. `;
  232.  
  233. const currentPage = document.querySelector('#pgt > div > strong')?.textContent || 1;
  234. const isOldUrl = document.querySelector(`#normalthread_${tid} a`)?.href.includes("forum.php");
  235.  
  236. link.href = isOldUrl
  237. ? `forum.php?mod=viewthread&tid=${tid}&extra=page%3D${currentPage}&page=${page}`
  238. : `thread-${tid}-${page}-${currentPage}.html`;
  239.  
  240. return link;
  241. }
  242.  
  243. // 辅助函数:创建新回复标记
  244. function createReplyBadge(count, color) {
  245. const badge = document.createElement('span');
  246. badge.textContent = `+${count}`;
  247. badge.style.cssText = `
  248. color: #F6F7EB;
  249. background: ${color};
  250. font-weight: bold;
  251. padding: 1px 3px;
  252. border: 1px solid ${color};
  253. border-radius: 0 4px 4px 0;
  254. display: inline-block;
  255. `;
  256. return badge;
  257. }

QingJ © 2025

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