全球主机交流论坛增强

自动签到(访问空间 +22 积分)、屏蔽用户(黑名单)、屏蔽关键词(帖子标题)、回帖小尾巴、自动无缝翻页、快捷回到顶部(右键网页两侧空白处)、收起预览帖子(左键网页两侧空白处)、屏蔽投票贴、快速添加链接、屏蔽阅读权限 255 帖子、预览帖子快速回复带签名、显示是否在线、显示帖子内隐藏回复

სკრიპტის ინსტალაცია?
ავტორის შემოთავაზებული სკრიპტი

შეიძლება მოგეწონოს Github 增强 - 高速下载.

სკრიპტის ინსტალაცია
  1. // ==UserScript==
  2. // @name 全球主机交流论坛增强
  3. // @version 1.4.9
  4. // @author X.I.U
  5. // @description 自动签到(访问空间 +22 积分)、屏蔽用户(黑名单)、屏蔽关键词(帖子标题)、回帖小尾巴、自动无缝翻页、快捷回到顶部(右键网页两侧空白处)、收起预览帖子(左键网页两侧空白处)、屏蔽投票贴、快速添加链接、屏蔽阅读权限 255 帖子、预览帖子快速回复带签名、显示是否在线、显示帖子内隐藏回复
  6. // @match *://hostloc.com/*
  7. // @match *://91ai.net/*
  8. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABYUlEQVR4nM2VMUrFQBCG/xUbUz20EGwkIAjewMYreAabtLlKcgLP4BVsPEHEB0J4TeAJPuy0i42TsJP8byfgY/fvNplM9v92Ztb1fd9jgZxzpjhr2qMlPz+EjvUDcSgOtOO6rk2J9XeMSHQCTtdAyHHbtot+kOc5AKAsSwBTEtEJDDUgzpnjqqpmExRF4a2zLPPWTdPs3UA6BJjE+dfmZfb96vLWWwsRTYIpHQKs7wfnPx97E70+PwIAbu4eAExrgyk6AToHrM61uu0OwEhCK7k5MCEwvNC1sH6aTbC6vvfWUgtaQiQ5AvQ2/P58956fnF3NJrDGMaVHICTd76E4EYtPjwCbiOLo4vwUwNgV+sx1nMwFpugEgnNAJmK3eQMwOtMSp9o5639RdAKLN9Btd8FzPegG/lt0Duhu0LejvgOkK6xnL4pOgHbBJPCPBLvtRFbnougEzHcBm5AszqroBH4BBkemS0VRyL4AAAAASUVORK5CYII=
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_registerMenuCommand
  11. // @grant GM_unregisterMenuCommand
  12. // @grant GM_openInTab
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_notification
  16. // @grant unsafeWindow
  17. // @license GPL-3.0 License
  18. // @run-at document-end
  19. // @namespace https://greasyfork.org/scripts/414005
  20. // @supportURL https://github.com/XIU2/UserScript
  21. // @homepageURL https://github.com/XIU2/UserScript
  22. // ==/UserScript==
  23.  
  24. (function() {
  25. 'use strict';
  26. var menu_ALL = [
  27. ['menu_autoSignIn', '自动签到(22 积分)', '自动签到', true],
  28. ['menu_reAutoSignIn', '重新签到', '重新签到', ''],
  29. ['menu_customBlockUsers', '屏蔽用户(黑名单)', '屏蔽用户', []],
  30. ['menu_customBlockKeywords', '屏蔽关键词(帖子标题)', '屏蔽关键词', []],
  31. ['menu_customLittleTail', '回帖小尾巴', '回帖小尾巴', ''],
  32. ['menu_pageLoading', '自动无缝翻页(总开关)', '自动无缝翻页', true],
  33. ['menu_thread_pageLoading', '帖子内自动翻页', '帖子内自动翻页', true],
  34. ['menu_showhide', '显示帖内隐藏回复', '显示帖内隐藏回复', true],
  35. ['menu_delate255', '屏蔽阅读权限 255 帖子', '屏蔽阅读权限 255 帖子', true],
  36. ['menu_delatePolls', '屏蔽投票帖子', '屏蔽投票帖子', false]
  37. ], menu_ID = [];
  38. for (let i=0;i<menu_ALL.length;i++){ // 如果读取到的值为 null 就写入默认值
  39. if (GM_getValue(menu_ALL[i][0]) == null){GM_setValue(menu_ALL[i][0], menu_ALL[i][3])};
  40. }
  41. registerMenuCommand();
  42.  
  43. // 注册脚本菜单
  44. function registerMenuCommand() {
  45. if (menu_ID.length > menu_ALL.length){ // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单
  46. for (let i=0;i<menu_ID.length;i++){
  47. GM_unregisterMenuCommand(menu_ID[i]);
  48. }
  49. }
  50. for (let i=0;i<menu_ALL.length;i++){ // 循环注册脚本菜单
  51. menu_ALL[i][3] = GM_getValue(menu_ALL[i][0]);
  52. if (menu_ALL[i][0] === 'menu_reAutoSignIn') {
  53. menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function(){reAutoSignIn()});
  54. } else if (menu_ALL[i][0] === 'menu_customBlockUsers') {
  55. menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function(){customBlockUsers()});
  56. } else if (menu_ALL[i][0] === 'menu_customBlockKeywords') {
  57. menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function(){customBlockKeywords()});
  58. } else if (menu_ALL[i][0] === 'menu_customLittleTail') {
  59. if (menu_value(menu_ALL[i][0]).length === 0) {GM_setValue(menu_ALL[i][0], '')} // 修改旧版类型
  60. menu_ID[i] = GM_registerMenuCommand(`#️⃣ ${menu_ALL[i][1]}`, function(){customLittleTail()});
  61. } else {
  62. menu_ID[i] = GM_registerMenuCommand(`${menu_ALL[i][3]?'✅':'❌'} ${menu_ALL[i][1]}`, function(){menu_switch(`${menu_ALL[i][3]}`,`${menu_ALL[i][0]}`,`${menu_ALL[i][2]}`)});
  63. }
  64. }
  65. menu_ID[menu_ID.length] = GM_registerMenuCommand('💬 反馈 & 建议', function () {window.GM_openInTab('https://github.com/XIU2/UserScript#xiu2userscript', {active: true,insert: true,setParent: true});window.GM_openInTab('https://greasyfork.org/zh-CN/scripts/414005/feedback', {active: true,insert: true,setParent: true});});
  66. }
  67.  
  68. // 菜单开关
  69. function menu_switch(menu_status, Name, Tips) {
  70. if (menu_status == 'true'){
  71. GM_setValue(`${Name}`, false);
  72. GM_notification({text: `已关闭 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function(){location.reload();}});
  73. }else{
  74. GM_setValue(`${Name}`, true);
  75. GM_notification({text: `已开启 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function(){location.reload();}});
  76. }
  77. registerMenuCommand(); // 重新注册脚本菜单
  78. };
  79.  
  80. // 返回菜单值
  81. function menu_value(menuName) {
  82. for (let menu of menu_ALL) {
  83. if (menu[0] == menuName) {
  84. return menu[3]
  85. }
  86. }
  87. }
  88.  
  89. // 检查是否登陆
  90. var loginStatus = false;
  91. if (document.getElementById('um')){
  92. loginStatus = true;
  93. } else {
  94. if (typeof discuz_uid != 'undefined') loginStatus = (discuz_uid != '0' ? true : false);
  95. }
  96.  
  97. // 默认 ID 为 0
  98. var curSite = {SiteTypeID: 0};
  99.  
  100. // 自动翻页规则
  101. let DBSite = {
  102. forum: {
  103. SiteTypeID: 1
  104. },
  105. thread: {
  106. SiteTypeID: 2,
  107. pager: {
  108. nextLink: 'a.nxt',
  109. pageElement: 'div#postlist > div[id^="post_"]',
  110. HT_insert: ['div#postlist', 2],
  111. replaceE: '#ct > .pgs',
  112. }
  113. },
  114. search: {
  115. SiteTypeID: 3,
  116. pager: {
  117. nextLink: 'a.nxt',
  118. pageElement: 'div#threadlist > ul',
  119. HT_insert: ['div#threadlist', 2],
  120. replaceE: 'div.pg'
  121. }
  122. },
  123. guide: {
  124. SiteTypeID: 4,
  125. pager: {
  126. nextLink: 'a.nxt',
  127. pageElement: 'div#threadlist div.bm_c table > tbody',
  128. HT_insert: ['div#threadlist div.bm_c table', 2],
  129. replaceE: 'div.pg',
  130. }
  131. },
  132. youreply: {
  133. SiteTypeID: 5,
  134. pager: {
  135. nextLink: 'a.nxt',
  136. pageElement: 'tbody > tr:not(.th)',
  137. HT_insert: ['tbody', 2],
  138. replaceE: 'div.pg',
  139. }
  140. }
  141. };
  142.  
  143. // 用于脚本内部判断当前 URL 类型
  144. let SiteType = {
  145. FORUM: DBSite.forum.SiteTypeID, // 各板块帖子列表
  146. THREAD: DBSite.thread.SiteTypeID, // 帖子内
  147. GUIDE: DBSite.guide.SiteTypeID, // 导读帖子列表
  148. SEARCH: DBSite.search.SiteTypeID // 搜索结果列表
  149. };
  150.  
  151. // URL 匹配正则表达式
  152. let patt_thread = /\/thread-\d+-\d+\-\d+.html/,
  153. patt_forum = /\/forum-\d+-\d+\.html/
  154.  
  155. // URL 判断
  156. if (patt_thread.test(location.pathname) || location.search.indexOf('mod=viewthread') > -1) { // 帖子内
  157. if (menu_value('menu_thread_pageLoading')) {
  158. curSite = DBSite.thread;
  159. hidePgbtn(); // 隐藏帖子内的 [下一页] 按钮
  160. }
  161. showPosts(); // 自动显示帖子内被隐藏的回复
  162. blockUsers('thread'); // 屏蔽用户(黑名单)
  163. onlineStatus(); // 显示是否在线
  164. replyCustom('thread'); // 回复自定义
  165. } else if (patt_forum.test(location.pathname) || location.search.indexOf('mod=forumdisplay') > -1) { // 各板块帖子列表
  166. curSite = DBSite.forum;
  167. collapsedNowPost(); // 收起当前帖子预览(左键左右两侧空白处)
  168. delate255(); // 屏蔽 255 权限帖子
  169. delatePolls(); // 屏蔽投票贴子
  170. blockUsers('forum'); // 屏蔽用户(黑名单)
  171. blockKeywords(); // 屏蔽关键词(帖子标题)
  172. vfastpostDOMNodeInserted(); // 监听插入事件(预览快速回复带签名)
  173. replyCustom('forum'); // 回复自定义
  174. if (patt_forum.test(location.pathname)) blockDOMNodeInserted(); //监听插入事件(有新的回复主题,点击查看)
  175. }else if (location.search.indexOf('mod=guide') > -1) { // 导读帖子列表
  176. curSite = DBSite.guide;
  177. } else if(location.pathname === '/search.php') { // 搜索结果列表
  178. curSite = DBSite.search;
  179. blockUsers('search'); // 屏蔽用户(黑名单)
  180. } else if(location.pathname === '/home.php' && location.search.indexOf('mod=space&do=notice&view=mypost') > -1) { // 消息(帖子/点评/提到)
  181. blockUsers('notice'); // 屏蔽用户(黑名单)
  182. } else if(location.pathname === '/home.php' && location.search.indexOf('mod=space&do=pm') > -1) { // 消息(私人聊天)
  183. blockUsers('pm'); // 屏蔽用户(黑名单)
  184. } else if(location.search.indexOf('mod=space') > -1 && location.search.indexOf('&view=me') > -1) { // 别人的主题/回复
  185. curSite = DBSite.youreply;
  186. } else if(location.pathname === '/forum.php' && location.search.indexOf('mod=post&action=reply') > -1 || location.pathname === '/forum.php' && location.search.indexOf('mod=post&action=newthread') > -1) { // 回复:高级回复
  187. replyCustom('reply'); // 回复自定义
  188. }
  189.  
  190. curSite.pageUrl = ""; // 下一页URL
  191. pageLoading(); // 自动翻页
  192. backToTop(); // 回到顶部(右键点击左右两侧空白处)
  193. if(menu_value('menu_autoSignIn')) autoSignIn(); // 自动签到(访问空间 10 次 = 20 积分)
  194. //replyIntervalDOMNodeInserted(); // 监听插入事件(回帖间隔)
  195.  
  196.  
  197. // 自动签到(访问空间 10 次 = 20 积分 + 当天首次访问论坛 2 积分)
  198. function autoSignIn() {
  199. if (!loginStatus) return
  200. let timeNow = new Date().getFullYear() + "/" + (new Date().getMonth() + 1) + "/" + new Date().getDate(),
  201. timeOld = GM_getValue('menu_signInTime');
  202. if (!timeOld || timeOld != timeNow) { // 是新的一天
  203. GM_setValue('menu_signInTime', timeNow); // 写入签到时间以供后续比较
  204. GM_notification({text: '请不要关闭/刷新本页!耐心等待 60 秒~\n在此期间可以在 "其他标签页" 浏览论坛!', timeout: 10000});
  205. let url_list = [],
  206. url = 0;
  207. // 随机生成 12 个空间地址(2 个冗余)
  208. for(let i = 0;i < 12;i++){url_list[i] = "https://" + location.host + "/space-uid-" + Math.floor(Math.random()*(50000-10000+1)+10000) + ".html";}
  209. // 每 5 秒访问一次(避免触发网站防御机制,而且还可以适当浏览论坛)
  210. let signIn = setInterval(function(){
  211. GM_xmlhttpRequest({
  212. url: url_list[url++],
  213. method: 'GET',
  214. timeout: 4000
  215. });
  216. console.log(`[全球主机交流论坛 增强] 积分 +2 (${url_list[url]})`);
  217. if (url === 11) { // 次数够了就取消定时循环
  218. clearInterval(signIn);
  219. console.log('[全球主机交流论坛 增强] 签到完成!');
  220. GM_notification({text: '签到完成!积分 +22 ~', timeout: 3500});
  221. }
  222. }, 5000);
  223. }
  224. }
  225.  
  226.  
  227. // 重新签到
  228. function reAutoSignIn() {
  229. GM_setValue('menu_signInTime', '1970/1/1'); // 设置为比当前日期更早
  230. location.reload(); // 刷新网页
  231. }
  232.  
  233.  
  234. // 自定义屏蔽用户
  235. function customBlockUsers() {
  236. let nowBlockUsers = '';
  237. GM_getValue('menu_customBlockUsers').forEach(function(item){nowBlockUsers += '|' + item})
  238. let newBlockUsers = prompt('编辑 [自定义屏蔽用户],刷新网页后生效\n(不同用户名之间使用 "|" 分隔,\n(例如:用户A|用户B|用户C,如果只有一个就不需要 "|" 了。', nowBlockUsers.replace('|',''));
  239. if (newBlockUsers === '') {
  240. GM_setValue('menu_customBlockUsers', []);
  241. registerMenuCommand(); // 重新注册脚本菜单
  242. } else if (newBlockUsers != null) {
  243. GM_setValue('menu_customBlockUsers', newBlockUsers.split('|'));
  244. registerMenuCommand(); // 重新注册脚本菜单
  245. }
  246. };
  247.  
  248.  
  249. // 屏蔽用户
  250. function blockUsers(type) {
  251. if (!menu_value('menu_customBlockUsers') || menu_value('menu_customBlockUsers').length < 1) return
  252. switch(type) {
  253. case 'thread': // 帖子内
  254. blockUsers_('[id^="post_"]', 'a[href^="space-uid"]');
  255. blockUsers_('[id^="comment_"] > div', 'a.xi2.xw1'); // 点评
  256. blockUsers_('.quote', 'a[href*="&ptid="]:not([id])>font', 1); // 回复引用
  257. break;
  258. case 'forum': // 各版块帖子列表
  259. blockUsers_('[id^="normalthread_"]', 'a[href^="space-uid"]');
  260. blockUsers_vfastpost(); // 预览帖子中的回复
  261. break;
  262. case 'search': // 搜索结果
  263. blockUsers_('.pbw', 'a[href^="space-uid"]');
  264. break;
  265. case 'notice': // 消息
  266. blockUsers_('dl.cl', '.ntc_body a[href^="space-uid"]');
  267. break;
  268. case 'pm': // 私人聊天
  269. blockUsers_('dl[id^="pmlist_"]', '.ptm.pm_c a[href^="space-uid"]');
  270. break;
  271. }
  272.  
  273. function blockUsers_(list1, list2, type) {
  274. document.querySelectorAll(list1).forEach(function(item){ // 遍历所有帖子
  275. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  276. let itemName = item.querySelector(list2); // 寻找用户名
  277. if (itemName) {
  278. if (type && type === 1 && itemName.textContent.split(' ')[0] === item1) { // 回复引用
  279. console.log(`屏蔽用户:${item1}`);
  280. item.hidden = true; // 隐藏
  281. } else if (itemName.textContent === item1) {
  282. console.log(`屏蔽用户:${item1}`);
  283. item.hidden = true; // 隐藏
  284. }
  285. }
  286. })
  287. })
  288. }
  289.  
  290. function blockUsers_vfastpost() {
  291. let vfastpost = e => {
  292. if (e.target.nodeType == 1 && e.target.outerHTML && e.target.outerHTML.indexOf('class="fastpreview"') > -1) {
  293. e.target.querySelectorAll('.bm_c > [id^="post_"]').forEach(function(item){ // 遍历所有回复
  294. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  295. let itemName = item.querySelector('a.xi2'); // 寻找用户名
  296. if (itemName && itemName.textContent === item1) {
  297. console.log(`屏蔽用户:${item1}`);
  298. item.hidden = true; // 隐藏
  299. }
  300. itemName = item.querySelector('.quote>blockquote>font:first-child'); // 寻找用户名(回复引用)
  301. if (itemName && itemName.textContent.split(' ')[0] === item1) {
  302. console.log(`屏蔽用户:${item1}`);
  303. item.querySelector('.quote').hidden = true; // 隐藏
  304. }
  305. })
  306. })
  307. }
  308. }
  309. document.addEventListener('DOMNodeInserted', vfastpost); // 监听插入事件
  310. }
  311. }
  312.  
  313.  
  314. // 自定义屏蔽关键词(帖子标题)
  315. function customBlockKeywords() {
  316. let nowBlockKeywords = '';
  317. GM_getValue('menu_customBlockKeywords').forEach(function(item){nowBlockKeywords += '|' + item})
  318. let newBlockKeywords = prompt('编辑 [自定义屏蔽关键词],刷新网页后生效\n(不同关键词之间使用 "|" 分隔,\n(例如:助力|互助|互点,如果只有一个就不需要 "|" 了。', nowBlockKeywords.replace('|',''));
  319. if (newBlockKeywords === '') {
  320. GM_setValue('menu_customBlockKeywords', []);
  321. registerMenuCommand(); // 重新注册脚本菜单
  322. } else if (newBlockKeywords != null) {
  323. GM_setValue('menu_customBlockKeywords', newBlockKeywords.split('|'));
  324. registerMenuCommand(); // 重新注册脚本菜单
  325. }
  326. };
  327.  
  328.  
  329. // 屏蔽关键词(帖子标题)
  330. function blockKeywords() {
  331. if (!menu_value('menu_customBlockKeywords') || menu_value('menu_customBlockKeywords').length < 1) return
  332. document.querySelectorAll('[id^="normalthread_"]').forEach(function(item){ // 遍历所有帖子标题
  333. menu_value('menu_customBlockKeywords').forEach(function(item1){ // 遍历关键词
  334. let itemName = item.querySelector('a.s.xst'); // 寻找帖子标题
  335. if (itemName && itemName.textContent.toLowerCase().indexOf(item1.toLowerCase()) > -1) {
  336. console.log(`屏蔽关键词:[${item1}]`, `,帖子标题:[${itemName.textContent}]`);
  337. item.hidden = true; // 删除帖子
  338. }
  339. })
  340. })
  341. }
  342.  
  343.  
  344. // 监听插入事件(有新的回复主题,点击查看)
  345. function blockDOMNodeInserted() {
  346. let block = e => {
  347. if (e.target.nodeType == 1 && e.target.textContent && e.target.textContent.indexOf('newthread') > -1) {
  348. setTimeout(function () {
  349. blockUsers('forum'); // 屏蔽用户(黑名单)
  350. blockKeywords(); // 屏蔽关键词(帖子标题)
  351. }, 100)
  352. }
  353. }
  354. document.addEventListener('DOMNodeInserted', block); // 监听插入事件
  355. }
  356.  
  357.  
  358. // 监听插入事件(预览快速回复带签名)
  359. function vfastpostDOMNodeInserted() {
  360. let vfastpost = e => {
  361. if (e.target.nodeType == 1 && e.target.innerHTML && e.target.innerHTML.indexOf('id="vfastpost"') > -1) {
  362. e.target.getElementsByTagName('form')[0].insertAdjacentHTML('afterbegin', `<input type="hidden" name="usesig" value="1">`);
  363. }
  364. }
  365. document.addEventListener('DOMNodeInserted', vfastpost); // 监听插入事件
  366. }
  367.  
  368.  
  369. // 自定义小尾巴内容
  370. function customLittleTail() {
  371. let newLittleTail = prompt('编辑 [自定义小尾巴内容],刷新网页后生效(换行请使用 \\n\n提示①:记得在小尾巴前面加上几个 \\n 换行,用来分隔开回帖内容~\n提示②:建议使用 [align=right] 标签来使小尾巴居右~\n提示③:支持论坛富文本标签(建议先找个回复编辑预览好~\n示例:\\n\\n\\n\\n[align=right]第一行内容~\\n第二行内容~[/align]', GM_getValue('menu_customLittleTail'));
  372. if (newLittleTail === '') {
  373. GM_setValue('menu_customLittleTail', '');
  374. registerMenuCommand(); // 重新注册脚本菜单
  375. } else if (newLittleTail != null) {
  376. GM_setValue('menu_customLittleTail', newLittleTail);
  377. registerMenuCommand(); // 重新注册脚本菜单
  378. }
  379. };
  380.  
  381.  
  382. // 回复自定义
  383. function replyCustom(type) {
  384. switch(type) {
  385. case 'forum': // 各版块帖子列表的预览帖子
  386. replyCustom_0(); // 预览帖子 快速回复(底部)
  387. replyCustom_1(); // 预览帖子 回复(悬浮)
  388. break;
  389. case 'thread': // 帖子内
  390. replyCustom_1(); // 快速回复(悬浮)
  391. replyCustom_2(); // 回复框(底部)
  392. break;
  393. case 'reply': // 高级回复
  394. replyCustom_3();
  395. break;
  396. }
  397.  
  398. function replyCustom_0() {
  399. let vfastpost = e => {
  400. if (e.target.nodeType == 1 && e.target.innerHTML && e.target.innerHTML.indexOf('id="vfastpost"') > -1) {
  401. let message = e.target.querySelector('input[name="message"]'), id = message.id.match(/\d+/g)[0];
  402. message.parentNode.innerHTML = `<textarea type="text" name="message" id="vmessage_${id}" style="width: 99.8%;height: 30px;border: none;outline: none;font-size: 14px;overflow-y: hidden;"></textarea>`
  403. document.getElementById(`vreplysubmit_${id}`).onclick = function(){
  404. if (GM_getValue('menu_customLittleTail')) document.getElementById(`vmessage_${id}`).value += GM_getValue('menu_customLittleTail').replaceAll('\\n', '\n');
  405. }
  406. }
  407. }
  408. document.addEventListener('DOMNodeInserted', vfastpost); // 监听插入事件
  409. }
  410.  
  411. function replyCustom_1() {
  412. let floatlayout_reply = e => {
  413. if (e.target.nodeType == 1 && e.target.innerHTML && e.target.innerHTML.indexOf('id="floatlayout_reply"') > -1) {
  414. // 快速回复(悬浮)中添加 URL 按钮
  415. document.querySelector('#floatlayout_reply .fbld').insertAdjacentHTML('afterend', `<a href="javascript:;" title="点击给选中文字添加 url 标签(可正常显示为 URL)" class="flnk" style="filter: hue-rotate(83deg);" onclick="seditor_insertunit('post', '[url][i]', '[/i][/url]');doane(event);">URL</a>`);
  416. document.getElementById('postsubmit').onclick = function(){
  417. if (GM_getValue('menu_customLittleTail')) document.getElementById('postmessage').value += GM_getValue('menu_customLittleTail').replaceAll('\\n', '\n');
  418. }
  419. }
  420. }
  421. document.addEventListener('DOMNodeInserted', floatlayout_reply); // 监听插入事件
  422. // 快速发帖(各版块帖子列表底部)中添加 URL 按钮
  423. document.querySelector('#fastposteditor .fbld').insertAdjacentHTML('afterend', `<a href="javascript:;" title="点击给选中文字添加 url 标签(可正常显示为 URL)" class="flnk" style="filter: hue-rotate(83deg);" onclick="seditor_insertunit('post', '[url][i]', '[/i][/url]');doane(event);">URL</a>`);
  424. }
  425.  
  426. function replyCustom_2() { // 帖子底部的回复框
  427. document.getElementById('fastpostsubmit').onclick = function(){
  428. if (GM_getValue('menu_customLittleTail')) document.getElementById('fastpostmessage').value += GM_getValue('menu_customLittleTail').replaceAll('\\n', '\n');
  429. }
  430. }
  431.  
  432. function replyCustom_3() {
  433. let postsubmit = document.getElementById('postsubmit');
  434. if (postsubmit && postsubmit.textContent === '\n参与/回复主题\n' || postsubmit && postsubmit.textContent === '\n发表帖子\n') {
  435. postsubmit.onclick = function(){
  436. if (GM_getValue('menu_customLittleTail')) document.getElementById('e_textarea').value += GM_getValue('menu_customLittleTail').replaceAll('\\n', '\n');
  437. }
  438. }
  439. }
  440. }
  441.  
  442.  
  443. // 监听插入事件(回帖间隔)
  444. /*function replyIntervalDOMNodeInserted() {
  445. let replyInterval = e => {
  446. if (e.target.nodeType == 1 && e.target.innerHTML && e.target.textContent.indexOf('发表回复 金钱+1') > -1) {
  447. setTimeout(function () {GM_notification({text: '过去 60 秒了,可以回帖了~', timeout: 3500});}, 60000)
  448. }
  449. }
  450. document.addEventListener('DOMNodeInserted', replyInterval); // 监听插入事件
  451. }*/
  452.  
  453.  
  454. // 自动显示帖子内被隐藏的回复
  455. function showPosts() {
  456. if(menu_value('menu_showhide')){
  457. let showposts = document.querySelector('#hiddenpoststip a');
  458. if (showposts){ // 如果存在
  459. showposts.click();
  460. }
  461. }
  462. }
  463.  
  464.  
  465. // 隐藏帖子内的 [下一页] 按钮
  466. function hidePgbtn() {
  467. document.lastChild.appendChild(document.createElement('style')).textContent = '.pgbtn {display: none;}';
  468. }
  469.  
  470.  
  471. // 快捷回到顶部(右键左右两侧空白处)
  472. function backToTop() {
  473. document.body.oncontextmenu = function(event){
  474. if (event.target == this) {
  475. event.preventDefault();
  476. window.scrollTo(0,0)
  477. }
  478. }
  479. }
  480.  
  481.  
  482. // 收起帖子预览(左键左右两侧空白处)
  483. function collapsedNowPost() {
  484. document.body.onclick = function(event){
  485. if (event.target == this) {
  486. document.querySelectorAll('[id^="threadPreviewTR_"] .closeprev').forEach(function (el) {
  487. if (!el.parentElement.querySelector('[name="message"]') || el.parentElement.querySelector('[name="message"]').value === '' && !document.getElementById('fwin_reply')) { // 避免快速回复过程中误点收起了
  488. let parentElement = el.parentElement.parentElement.parentElement.parentElement.parentElement,
  489. top = parentElement.offsetTop + parentElement.offsetParent.offsetTop + parentElement.offsetParent.offsetParent.offsetTop; // 元素距离顶部的高度
  490. if (top < document.documentElement.scrollTop) window.scrollTo(0,top) // 帖子标题在上面时才会滚动到该帖子处
  491. el.click()
  492. }
  493. });
  494. }
  495. }
  496. }
  497.  
  498.  
  499. // 显示在线状态
  500. function onlineStatus() {
  501. document.querySelectorAll('[id^="favatar"]').forEach(function(item){ // 遍历所有帖子
  502. if (item.querySelector('[id^="userinfo"] > .i.y em')) {
  503. let icon = (item.querySelector('[id^="userinfo"] > .i.y em').textContent === '当前在线') ? '🌝' : '🌚';
  504. let divStatus = document.createElement('div');
  505. divStatus.style = 'position: absolute;margin: -8px 0 0 8px;padding: 0 1px 1.2px;background-color: #ffffff;border-radius: 50%;';
  506. divStatus.textContent = icon;
  507. let mochu = item.querySelector('.avatar');
  508. mochu.parentNode.insertBefore(divStatus,mochu);
  509. }
  510. })
  511. }
  512.  
  513.  
  514. // 屏蔽阅读权限 255 的帖子
  515. function delate255() {
  516. if (!menu_value('menu_delate255')) return
  517. if (patt_forum.test(location.pathname) || location.search.indexOf('mod=forumdisplay') > -1){
  518. document.querySelectorAll('tbody[id^="normalthread_"] .xw1').forEach(function (_this) {
  519. if (_this.textContent === '255') {
  520. _this.parentNode.parentNode.parentNode.hidden = true;
  521. }
  522. })
  523. }
  524. }
  525.  
  526.  
  527. // 屏蔽投票贴
  528. function delatePolls() {
  529. if (!menu_value('menu_delatePolls')) return
  530. if (patt_forum.test(location.pathname) || location.search.indexOf('mod=forumdisplay') > -1){
  531. document.querySelectorAll('tbody[id^="normalthread_"] .icn>a>img[alt="投票"]').forEach(function (_this) {
  532. _this.parentNode.parentNode.parentNode.parentNode.hidden = true;
  533. })
  534. }
  535. }
  536.  
  537.  
  538. // 自动翻页
  539. function pageLoading() {
  540. if (!menu_value('menu_pageLoading')) return
  541. if (curSite.SiteTypeID > 0){
  542. windowScroll(function (direction, e) {
  543. if (direction === 'down') { // 下滑才准备翻页
  544. let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
  545. if (document.documentElement.scrollHeight <= document.documentElement.clientHeight + scrollTop + 999) {
  546. if (curSite.SiteTypeID === SiteType.FORUM) { // 如果是各版块帖子列表则直接点下一页就行了
  547. let autopbn = document.querySelector('#autopbn');
  548. if (autopbn && autopbn.textContent === "下一页 »"){ // 如果已经在加载中了,就忽略
  549. autopbn.click();
  550. let timer = setInterval(function(){ // 在下一页加载完成后
  551. if (document.querySelector('#autopbn').textContent === '下一页 »') {
  552. delate255(); // 屏蔽 255 权限帖子
  553. delatePolls(); // 屏蔽投票贴子
  554. blockUsers('forum'); // 屏蔽用户(黑名单)
  555. blockKeywords(); // 屏蔽关键词(帖子标题)
  556. clearInterval(timer);
  557. }
  558. }, 10);
  559. }
  560. } else {
  561. ShowPager.loadMorePage();
  562. }
  563. }
  564. }
  565. });
  566. }
  567. }
  568.  
  569.  
  570. // 滚动条事件
  571. function windowScroll(fn1) {
  572. var beforeScrollTop = document.documentElement.scrollTop,
  573. fn = fn1 || function () {};
  574. setTimeout(function () { // 延时执行,避免刚载入到页面就触发翻页事件
  575. window.addEventListener('scroll', function (e) {
  576. var afterScrollTop = document.documentElement.scrollTop,
  577. delta = afterScrollTop - beforeScrollTop;
  578. if (delta == 0) return false;
  579. fn(delta > 0 ? 'down' : 'up', e);
  580. beforeScrollTop = afterScrollTop;
  581. }, false);
  582. }, 1000)
  583. }
  584.  
  585.  
  586. // 修改自 https://greasyfork.org/scripts/14178 , https://github.com/machsix/Super-preloader
  587. var ShowPager = {
  588. getFullHref: function (e) {
  589. if (e != null && e.nodeType === 1 && e.href && e.href.slice(0,4) === 'http') return e.href;
  590. return '';
  591. },
  592. createDocumentByString: function (e) {
  593. if (e) {
  594. if ('HTML' !== document.documentElement.nodeName) return (new DOMParser).parseFromString(e, 'application/xhtml+xml');
  595. var t;
  596. try { t = (new DOMParser).parseFromString(e, 'text/html');} catch (e) {}
  597. if (t) return t;
  598. if (document.implementation.createHTMLDocument) {
  599. t = document.implementation.createHTMLDocument('ADocument');
  600. } else {
  601. try {((t = document.cloneNode(!1)).appendChild(t.importNode(document.documentElement, !1)), t.documentElement.appendChild(t.createElement('head')), t.documentElement.appendChild(t.createElement('body')));} catch (e) {}
  602. }
  603. if (t) {
  604. var r = document.createRange(),
  605. n = r.createContextualFragment(e);
  606. r.selectNodeContents(document.body);
  607. t.body.appendChild(n);
  608. for (var a, o = { TITLE: !0, META: !0, LINK: !0, STYLE: !0, BASE: !0}, i = t.body, s = i.childNodes, c = s.length - 1; c >= 0; c--) o[(a = s[c]).nodeName] && i.removeChild(a);
  609. return t;
  610. }
  611. } else console.error('没有找到要转成 DOM 的字符串');
  612. },
  613. loadMorePage: function () {
  614. if (curSite.pager) {
  615. let curPageEle = document.querySelector(curSite.pager.nextLink);
  616. var url = this.getFullHref(curPageEle);
  617. if(url === '') return;
  618. if(curSite.pageUrl === url) return;// 不会重复加载相同的页面
  619. curSite.pageUrl = url;
  620. // 读取下一页的数据
  621. curSite.pager.startFilter && curSite.pager.startFilter();
  622. GM_xmlhttpRequest({
  623. url: url,
  624. method: 'GET',
  625. timeout: 5000,
  626. onload: function (response) {
  627. try {
  628. var newBody = ShowPager.createDocumentByString(response.responseText);
  629. let pageElems = getAllCSS(curSite.pager.pageElement, newBody),
  630. toElement = getAllCSS(curSite.pager.HT_insert[0])[0];
  631. if (pageElems.length >= 0) {
  632. let addTo = "beforeend";
  633. if (curSite.pager.HT_insert[1] == 1) addTo = 'beforebegin';
  634. // 插入新页面元素
  635. pageElems.forEach(function (one) {toElement.insertAdjacentElement(addTo, one);});
  636. // 屏蔽用户(黑名单)
  637. if (patt_thread.test(location.pathname) || location.search.indexOf('mod=viewthread') > -1) {blockUsers('thread');} else if (location.pathname === '/search.php') {blockUsers('search');}
  638. delate255(); // 屏蔽 255 权限帖子
  639. delatePolls(); // 屏蔽投票贴子
  640. // 替换待替换元素
  641. try {
  642. let oriE = getAllCSS(curSite.pager.replaceE),
  643. repE = getAllCSS(curSite.pager.replaceE, newBody);
  644. if (oriE.length === repE.length) {
  645. for (var i = 0; i < oriE.length; i++) {
  646. oriE[i].outerHTML = repE[i].outerHTML;
  647. }
  648. }
  649. } catch (e) {
  650. console.log(e);
  651. }
  652. }
  653. } catch (e) {
  654. console.log(e);
  655. }
  656. }
  657. });
  658. }
  659. },
  660. };
  661. function getAllCSS(css, contextNode = document) {
  662. return [].slice.call(contextNode.querySelectorAll(css));
  663. }
  664. })();