// ==UserScript== // @name 福利吧小助手 // @namespace https://greasyfork.org/zh-CN/users/860681-aoguai // @version 1.0.0 // @description 一个用于增强福利吧功能的油猴脚本,提供链接提取、界面美化、编解码等功能。 // @author aoguai // @match *://fulibus.net/* // @match *://fuliba20[0-9][0-9].net/* // @match *://fuliba[0-9][0-9].net/* // @match *://f.uliba.net/* // @match *://*.wnflb20[0-9][0-9].com/* // @match *://*.wnflb[0-9][0-9].com/* // @require https://gcore.jsdelivr.net/npm/arrive@2.4.1/minified/arrive.min.js // @require https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.min.js // @require https://greasyfork.org/scripts/403716-gm-config-cn/code/GM_config_CN.js // @connect pan.baidu.com // @connect keyfc.net // @connect fuliba123.com // @grant GM_info // @grant GM_setClipboard // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_xmlhttpRequest // @grant GM_addStyle // @run-at document-start // @noframes // @license GNU General Public License v3.0 or later // ==/UserScript== (function () { 'use strict'; if (typeof GM_config == 'undefined') { console.error( '福利吧小助手:\nGM_config 库文件加载失败,脚本无法正常工作,请尝试刷新网页以重新加载。', ); } else if (typeof document.arrive == 'undefined') { console.error( '福利吧小助手:\narrive 库文件加载失败,脚本可能无法正常工作,请尝试刷新网页以重新加载。', ); } else if (typeof CryptoJS == 'undefined') { console.warn( '福利吧小助手:\nCryptoJS 库文件加载失败,BASE64 编解码功能无法使用。', ); } else { console.debug('福利吧小助手:\n脚本工作环境正常。'); } const icon = { settings: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/settings.svg)', codeGray: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/code_gray.svg)', codeBlue: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/code_blue.svg)', modeNight: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/mode_night.svg)', modeDay: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/mode_day.svg)', signatureAdd: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/signature_add.svg)', signatureMinus: 'url(https://cdn.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/signature_minus.svg)', collapsedYes: 'static/image/common/collapsed_yes.gif', collapsedNo: 'static/image/common/collapsed_no.gif', }; const style = { // 设置面板样式 settings: ` #myGoodBoyConfig { --primary-color: #4A90E2; --text-color: #333; --border-color: #E5E5E5; --hover-color: #2D74C4; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } #myGoodBoyConfig input, #myGoodBoyConfig button { cursor: pointer; transition: all 0.2s ease; } #myGoodBoyConfig button:hover { background: var(--hover-color); } #myGoodBoyConfig input[type="checkbox"] { width: 18px; height: 18px; } #myGoodBoyConfig .reset_holder { float: left; position: relative; bottom: -3vh; } #myGoodBoyConfig .section_header { padding: 12px; background: var(--primary-color); border-radius: 4px; } #myGoodBoyConfig .section_header a { color: #FFF; text-decoration: none; font-weight: 500; transition: color 0.2s; } #myGoodBoyConfig .section_header a:hover { color: #E5E5E5; } `, // 代码面板样式 codePanel: ` #myCodePanel { --panel-width: 600px; --panel-height: 430px; --border-radius: 8px; width: var(--panel-width) !important; height: var(--panel-height) !important; border-radius: var(--border-radius); box-shadow: 0 2px 12px rgba(0,0,0,0.15); } #myCodePanel input, #myCodePanel button { cursor: pointer; transition: all 0.2s; } #myCodePanel button { padding: 6px 12px; border-radius: 4px; border: 1px solid var(--border-color); } #myCodePanel button:hover { background: var(--hover-color); color: white; } #myCodePanel .reset_holder { float: left; position: relative; bottom: -1vh; } #myCodePanel .nav-tabs { text-align: center; border-bottom: 1px solid var(--border-color); } #myCodePanel .nav-tabs > div { padding: 8px 20px; transition: background-color 0.2s; } #myCodePanel #myCodePanel_saveBtn { display: none; } #myCodePanel #myCodePanel_resetLink { text-decoration: underline; color: var(--primary-color); } #myCodePanel textarea { width: 96%; padding: 8px; border-radius: 4px; border: 1px solid var(--border-color); resize: vertical; } `, // 夜间模式样式 night: ` html, body, .bm, .bdl, .bdl dt, .bdl dd.bdl_a a, .tb .a a, .pn, .fl .bm_h, .ct2_a, .ct3_a, .t_table, table.plhin { background-color: #282A36 !important; background-blend-mode: multiply; } .bdl dl.a, .tl .th, .tl .ts th, .tl .ts td, .pg a, .pg strong, .pgb a, .pg label, .bml .bm_h, #scrolltop a, .bmn, .bm_h, td.pls, .ad td.plc, div.exfm, .tb a, .tb_h, .ttp li.a a, div.uo a, input#addsubmit_btn, #gh .bm .bm_h, .jump_bdl li, .newthread tr th, .newthread tr td, .tl .threadpre td, .tl .threadpre:hover td, .nfl .f_c, #myCodePanel { background-color: #282A36 !important; } #nv, .card_gender_0, .card .o a, .tbn li.a, #p_btn a, #p_btn i { background: #40444D !important; } #toptb, .tedt .bar, .edt .bar, .edt .bbar, #post_extra_tb label.a, #extcreditmenu.a, #g_upmine.a, .tl #forumnewshow, .jump_bdl .a a, .jump_bdl .a a:hover, .psth, .pl .quote, .pm_tac, .pm .c, .pml .hover, #uhd, #flw_header .bar, .ttp a, .ttp strong, .bmw .bm_h, .GzList ul li a, .m_c, .m_c .o, .dt th, .section_header_holder p, #fx_checkin_menu,#fx_checkin_menub, .pl .blockcode ol li:hover { background-color: #40444D !important; } #nv li a:hover, #nv li.hover a, #nv li.hover a:hover, #nv > a { background: #1A1A1A !important; background-blend-mode: multiply; } .p_pop, .p_pof, .sllt, .tl #forumnewshow a:hover, #autopbn:hover, .pgbtn a:hover, #hiddenpoststip { background-color: #1A1A1A !important; } #threadlist > div > table > tbody > tr:hover > *, #threadlist > div > form > table > tbody > tr:not(.threadpre):hover > *, div.tl > form > table > tbody > tr:hover > * { background-color: #1A1A1A !important; } .p_pop a:hover { background: #3D3D3D !important; } a, #um, #um a, body, input, button, select, textarea, .xi2, .xi2 a, .pg a, .pg strong, .pgb a, .pg label, .jump_bdl a, div#forum_rules_37 font { color: #C0C0C0 !important; } .tps a, .chart em { color: #666 !important; } .GzList ul li a { color: #000 !important !important; } .tedt .pt, .px, .pt, .ps, select, input, #myCodePanel textarea, #myCodePanel button { background-color: #38383D !important; } .pl .blockcode { background: #38383D !important; } ul.cl.nav li a, ul.cl.nav li a:hover { background-repeat: no-repeat !important; background-position: 50% 5px !important; } #fastpostsmilie_88_td, #fx_checkin_topb, #hd h2 a,#newspecial, #newspecialtmp, #post_reply, #post_replytmp, .ico_fall, .ico_increase, .o img, fieldset legend, div.ac1 { mix-blend-mode: multiply; } .p_pop a, .tl #forumnewshow a { filter: brightness(.7); } #category_36 tbody td p>a, .bm_c tbody h2>a, .common font, .fl .bm_h h2 a, .tl th a, .xw0.xi1, .y.xg1 font { mix-blend-mode: color-dodge; } .ignore_notice { right: -3px !important; top: -53px !important; } .tps a:hover { background-color: #C0C0C0 !important; } `, // 基础样式 basic: ` .my_good_boy_div_float { position: absolute; max-width: 430px; padding: 16px 20px; margin-left: 962px; margin-top: -170px; border: 2px solid #CDCDCD; border-radius: 8px; background: white; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .my_good_boy_div_basic { margin-top: 16px; } .my_good_boy_p { color: #FF4D4F; font-size: 15px; margin: 8px 0; } .my_good_boy_p_float { margin-left: 0 !important; } .my_good_boy_li { list-style-type: disc; white-space: nowrap; margin: 8px 0; } .my_good_boy_a { display: inline; font-size: 15px; white-space: nowrap; color: var(--primary-color); text-decoration: none; transition: color 0.2s; } .my_good_boy_a:hover { color: var(--hover-color); } .my_good_boy_a_copy { display: inline-block; font-size: 15px; margin-left: 20px; text-decoration: underline; cursor: pointer; } .a_copy_completed { color: #FF6600 !important; animation: fadeIn 0.3s; } .link_faild { color: #999 !important; text-decoration: line-through !important; } .show_more_link { text-decoration: underline; color: var(--primary-color); cursor: pointer; } #settingsIcon { display: block; float: right; cursor: pointer; margin-top: 5px; width: 23px; height: 18px; background-image: ${icon.settings}; background-repeat: no-repeat; background-size: 16px auto; background-position: center; transition: transform 0.2s; } #settingsIcon:hover { transform: rotate(45deg); } .expand_box, .expand_box_h { bottom: 0; height: 60px; position: fixed; right: -6vw; transition: all 0.3s ease; width: 12vw; z-index: 999; } .expand_box_h { height: 120px; } .show_expand_box { right: 0; width: 6vw; } #myCodeSpan, #myNightSpan, #myNightSpan_2 { background-repeat: no-repeat; background-size: 32px auto; background-position: center; border-radius: 50%; color: #FFF; cursor: pointer; display: block; height: 38px; width: 38px; position: absolute; right: 1vw; transition: all 0.3s ease; } #myCodeSpan { background-image: ${icon.codeGray}; background-color: #787878; bottom: 10px; } #myCodeSpan:hover { box-shadow: 0 0 10px rgba(0,255,0,0.5); background-image: ${icon.codeBlue}; transform: scale(1.1); } #myNightSpan, #myNightSpan_2 { background-color: #00A1D6; } #myNightSpan { bottom: 10px; } #myNightSpan_2 { bottom: 60px; } #myNightSpan:hover, #myNightSpan_2:hover { box-shadow: 0 0 10px rgba(0,255,0,0.5); transform: scale(1.1); } .signature_switch_div { width: 16px; height: 16px; display: block; position: relative; top: -5px; cursor: pointer; background-image: ${icon.signatureMinus}; background-size: 16px auto; background-repeat: no-repeat; background-position: center; transition: all 0.2s; } .signature_switch_div:hover { transform: scale(1.1); } .signature_switch_close { background-image: ${icon.signatureAdd}; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } `, }; // 定义网站地址常量 const SITE_URLS = { HOME: '', FORUM: '', }; const reg = { url: /^[\S\s]*?(magnet:\?xt=urn:btih:(?:[a-z0-9]{40}|[a-z0-9]{32})|ftp:\/\/\S*|ed2k:\/\/\S*|thunder:\/\/\S*|flashget:\/\/\S*|qqdl:\/\/\S*|xfplay:\/\/\S*|https?:\/\/[\w零一二三四五六七八九壹贰叁肆伍陆柒捌玖-]*\.?[\w零一二三四五六七八九壹贰叁肆伍陆柒捌玖-]+\.+\w+\S*)/i, download: /^[\S\s]*?(magnet:\?xt=urn:btih:(?:[a-z0-9]{40}|[a-z0-9]{32})|ed2k:\/\/\S*|thunder:\/\/\S*)/i, www: /^[\S\s]*?(www\.[\w-]+\.[a-z]+[\w#=%+?/-]*)/i, baidupan: /^https?:\/\/pan\.baidu\.com\/s(?:hare)?\/[\w=?&-]+$/i, baidupanIncludeCode: /^https?:\/\/pan\.baidu\.com\/s(?:hare)?\/[\w=?#&-]+$/i, code: /(?:提取)+[^a-z0-9解压]*([a-z0-9]{4})[^a-z0-9]*/i, baidupanCode: /^(?:(?:下载)?链接\S+\s+)?(?:[^解压]+\s+)?[^a-z0-9解压]*([a-z0-9]{4})[^a-z0-9]*(?:app)?[^a-z0-9]*$/i, singleCharCode: /^[a-z0-9]$/i, missingHeaderBaidupan: /^[\S\s]*?[^/\w-]?((? [v, k]), ); // 预编译正则表达式 const MAGNET_PREFIX_REGEX = /^magnet:\?xt=urn:btih:/; const TRIM_REGEX = /^\s+|\s+$/g; const HTTP_PROTOCOL_REGEX = /^https?\/\//i; const URL_PROTOCOL_REGEX = /^(https?:\/\/|ed2k:\/\/)/; // 常量配置 const CONFIG = { DEFAULT_ACCESS_NUM: 90, MAX_ACCESS_NUM: 90, LEVEL_ACCESS_MAP: { '-1': 0, '0': 5, }, }; // 获取最新地址并设置常量 function initSiteUrls() { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: 'https://fuliba123.com/', timeout: 10000, onload: function (response) { if (response.status === 200) { try { const parser = new DOMParser(); const doc = parser.parseFromString( response.responseText, 'text/html', ); // 获取所有链接元素 const linkElements = doc.querySelectorAll('a.card.no-c'); // 遍历链接元素设置常量 linkElements.forEach((element) => { const titleElement = element.querySelector('strong'); if (titleElement) { const title = titleElement.textContent.trim(); const url = element.href || element.getAttribute('data-url'); if (title === '福利吧') { SITE_URLS.HOME = url; } else if (title === '福利吧论坛') { SITE_URLS.FORUM = url; } } }); if (SITE_URLS.HOME && SITE_URLS.FORUM) { console.debug('福利吧小助手:\n网站地址初始化成功'); console.debug('首页地址:', SITE_URLS.HOME); console.debug('论坛地址:', SITE_URLS.FORUM); resolve(SITE_URLS); } else { reject(new Error('未找到所需的链接')); } } catch (error) { reject(error); } } else { reject(new Error(`请求失败,状态码:${response.status}`)); } }, onerror: function (error) { reject(new Error('网络请求错误:' + error)); }, ontimeout: function () { reject(new Error('请求超时')); }, }); }); } const status = { nightEnable: GM_config.getValue('nightEnable', false), collapsedGwwzEnable: GM_config.getValue('collapsedGwwzEnable', false), accessNum: GM_config.getValue('accessNumber', 90), nightStyleDom: null, checkDate: GM_config.getValue('checkDate', '2000-1-1'), oldUrl: location.href, timer1: null, timer2: null, timer3: null, timer4: null, }; class Good_Boy { constructor(config, linkArray = []) { this.config = config; this.floatEnable = this.isMobilePage() ? false : config.get('displayPosition') == '右侧'; this.linkArray = linkArray; this.totalCount = linkArray.length; this.currentCount = 0; this.showMoreStatus = false; this.insertUlStatus = false; this.ulNode = document.createElement('ul'); } insertLinkItem(linkArray = []) { this.linkArray = this.linkArray.concat(linkArray); this.totalCount = this.linkArray.length; const maxLinkNumber = this.config.get('maxLinkNumber'); for ( let i = this.currentCount; i < this.totalCount && i < maxLinkNumber; i++ ) { const tempA = this.createLink(this.linkArray[i]); tempA && this.ulNode.appendChild(tempA); } this.currentCount = Math.min(this.totalCount, maxLinkNumber); if (maxLinkNumber > -1 && this.totalCount > maxLinkNumber) { const message = `[共提取到 ${this.totalCount} 个链接,仅显示前 ${maxLinkNumber} 个]:`; const pElement = this.ulNode.getElementsByTagName('p')[0]; pElement && (pElement.textContent = message); if (!this.showMoreStatus) { this.ulNode.appendChild(this.showMoreLink()); this.showMoreStatus = true; } } else { const message = `[共提取到 ${this.totalCount} 个链接]:`; const pElement = this.ulNode.getElementsByTagName('p')[0]; pElement && (pElement.textContent = message); } } isMobilePage() { return /android|webos|iphone|ipod|blackberry/i.test(navigator.userAgent); } getCutLinkText(linkText) { if (this.isMobilePage()) { return linkText.length >= 35 ? linkText.slice(0, 15) + ' ... ' + linkText.slice(-10) : linkText; } else if (this.floatEnable) { return linkText.length >= 50 ? linkText.slice(0, 25) + ' ... ' + linkText.slice(-15) : linkText; } return linkText.length >= 80 ? linkText.slice(0, 45) + ' ... ' + linkText.slice(-25) : linkText; } managePrefixCode(inputLink) { const { prefixCode, prefixHash, prefixReplace, prefixUrl, redircdn } = reg; if (prefixCode.test(inputLink)) { return inputLink.replace(prefixReplace, ''); } else if (prefixHash.test(inputLink)) { return inputLink.replace(prefixReplace, 'magnet:?xt=urn:btih:'); } else if (prefixUrl.test(inputLink)) { return inputLink.replace(prefixReplace, 'http://'); } else if (redircdn.test(inputLink)) { return inputLink.replace(redircdn, '$1').replace('______', '.'); } return inputLink; } createLink(linkHref) { const { baidupanIncludeCode } = reg; if (linkHref.length > 2000) { return null; } const linkLi = document.createElement('li'); linkLi.className = 'my_good_boy_li'; const linkA = document.createElement('a'); linkA.title = '点击访问'; linkHref = this.managePrefixCode(linkHref); linkA.className = 'my_good_boy_a'; linkA.href = encodeURI(linkHref); linkA.target = '_blank'; linkA.textContent = this.getCutLinkText(linkHref); linkA.style.color = this.config.get('linkColor'); linkLi.appendChild(linkA); if (this.config.get('copyEnable')) { const copyA = document.createElement('a'); copyA.className = 'my_good_boy_a_copy'; copyA.title = '复制链接'; copyA.href = 'javascript:;'; copyA.target = '_self'; copyA.textContent = '复制'; copyA.style.color = this.config.get('linkColor'); copyA.addEventListener('click', function () { GM_setClipboard(linkHref, 'text'); this.classList.add('a_copy_completed'); this.title = '复制成功'; status.timer1 && clearTimeout(status.timer1); status.timer1 = setTimeout(() => { this.classList.remove('a_copy_completed'); this.title = '复制链接'; }, 2000); }); linkLi.appendChild(copyA); if ( baidupanIncludeCode.test(linkHref) && /(?:#|\?pwd=)[a-z0-9]{4}$/i.test(linkHref) ) { const codeValue = /#([a-z0-9]{4})$/i.exec(linkHref)[1]; const codeCopyA = document.createElement('a'); codeCopyA.className = 'my_good_boy_a_copy'; codeCopyA.title = '复制提取码'; codeCopyA.href = 'javascript:;'; codeCopyA.target = '_self'; codeCopyA.textContent = '复制提取码'; codeCopyA.style.color = this.config.get('linkColor'); codeCopyA.addEventListener('click', function () { GM_setClipboard(codeValue, 'text'); this.classList.add('a_copy_completed'); this.title = '复制成功'; status.timer2 && clearTimeout(status.timer2); status.timer2 = setTimeout(() => { this.classList.remove('a_copy_completed'); this.title = '复制提取码'; }, 2000); }); linkLi.appendChild(codeCopyA); } } this.config.get('checkEnable') && baidupanIncludeCode.test(linkHref) && this.checkBaidupan(linkHref, linkA); return linkLi; } showMoreLink() { const linkLi = document.createElement('li'); linkLi.className = 'my_good_boy_li'; const linkA = document.createElement('a'); linkA.className = 'my_good_boy_a show_more_link'; linkA.href = 'javascript:;'; linkA.title = '显示全部提取链接'; linkA.textContent = '显示全部'; linkA.target = '_self'; linkA.style.color = this.config.get('linkColor'); linkA.addEventListener( 'click', () => { this.ulNode.removeChild(linkLi); for (; this.currentCount < this.totalCount; this.currentCount++) { const tempA = this.createLink(this.linkArray[this.currentCount]); tempA && this.ulNode.appendChild(tempA); } this.ulNode.getElementsByTagName('p')[0].textContent = '[共提取到 ' + this.totalCount + ' 个链接]:'; this.showMoreStatus = false; }, false, ); linkLi.appendChild(linkA); return linkLi; } createGoodBoyFrame(container, linkArray = []) { if (this.insertUlStatus) { this.insertLinkItem(linkArray); } else { const goodBoyDiv = document.createElement('div'); goodBoyDiv.className = this.floatEnable ? 'my_good_boy_div_float' : 'my_good_boy_div_basic'; const goodBoyP = document.createElement('p'); goodBoyP.className = this.floatEnable ? 'my_good_boy_p my_good_boy_p_float' : 'my_good_boy_p'; this.ulNode.appendChild(goodBoyP); this.insertLinkItem(linkArray); goodBoyDiv.appendChild(this.ulNode); container.appendChild(goodBoyDiv); this.insertUlStatus = true; } } createGoodBoyElement(container, linkObj, textObj, nodeTextArray) { const backLinkArray = this.autoEvent( container, linkObj.linkObjArray, linkObj.baiduObjArray, linkObj.linksArray, textObj.hideTextArray, textObj.showTextArray, nodeTextArray, ); backLinkArray.length > 0 && this.createGoodBoyFrame(container, backLinkArray); } managePrefix(inputLinkArray) { const { prefixLinkMagnet, prefixLinkMagnetReplace } = reg; const returnLinkArray = []; inputLinkArray.forEach((item) => { returnLinkArray.push( prefixLinkMagnet.test(item) ? item.replace(prefixLinkMagnetReplace, '') : item, ); }); return returnLinkArray; } pickUpMagnet(item) { const { url, download, hash, md5 } = reg; let tempLink = ''; const item1 = item.replace(/[^a-z0-9:=?/\\.&%|-]/gi, ''); if (download.test(item1)) { tempLink = download.exec(item1)[1]; } else { const item2 = item.replace(/[^a-z0-9:=?/\\.,,。|\s+-]/gi, ''); if (!md5.test(item2) && hash.test(item2) && !url.test(item2)) { const tempHash = hash.exec(item2)[1]; if (!/^(?:[a-z]+|[0-9]+)$/i.test(tempHash)) { tempLink = 'magnet:?xt=urn:btih:' + tempHash; } } } return tempLink; } manageText(textArray) { const { url, download, www, missingHeaderBaidupan, missingHeaderBaidupanTest, pan, hash, md5, } = reg; const tempArray = []; textArray.forEach((item) => { let tempLink = ''; if (pan.test(item)) { tempLink = 'https://' + pan.exec(item)[1]; } else if (/magnet:|ed2k:|thunder:/i.test(item)) { if (download.test(item)) { tempLink = download.exec(item)[1]; } } else if (url.test(item)) { tempLink = url.exec(item)[1]; } else if (www.test(item)) { tempLink = 'http://' + www.exec(item)[1]; } else if (missingHeaderBaidupan.test(item)) { const linkMissValue = missingHeaderBaidupan.exec(item)[1]; tempLink = /^\//i.test(linkMissValue) ? 'https://pan.baidu.com' + linkMissValue : 'https://pan.baidu.com/' + linkMissValue; } else if (missingHeaderBaidupanTest.test(item)) { tempLink = 'https://pan.baidu.com/s/' + missingHeaderBaidupanTest.exec(item)[1]; } else if (!md5.test(item) && hash.test(item)) { tempLink = 'magnet:?xt=urn:btih:' + hash.exec(item)[1]; } else if (item.length > 32) { tempLink = this.pickUpMagnet(item); } filterLink(tempLink) && tempArray.push(tempLink); }); return this.managePrefix(tempArray); } decodeLink(inputLinkArray) { const { url } = reg; inputLinkArray.forEach((item, index) => { if (url.test(item)) { inputLinkArray[index] = decodeURI(item); } }); return inputLinkArray; } pickUpBaidupanCode(textArray) { const { code, baidupanCode, singleCharCode } = reg; const codeArray = []; const charArray = []; textArray.forEach((item) => { let tempValue = ''; if (code.test(item)) { tempValue = code.exec(item)[1]; } else if (baidupanCode.test(item)) { tempValue = baidupanCode.exec(item)[1]; } else if (singleCharCode.test(item)) { charArray.push(item); } if ( tempValue && !/\d{4}/i.test(tempValue) && codeArray.indexOf(tempValue) === -1 ) { codeArray.push(tempValue); } }); while (charArray.length > 0 && charArray.length % 4 === 0) { const tempCode = charArray.splice(0, 4); const charValue = tempCode.join(''); if (!/\d{4}/i.test(charValue) && codeArray.indexOf(charValue) === -1) { codeArray.push(charValue); } } return codeArray; } manageRepeatArray(inputLinkArray) { const outputLinkArray = []; for (let i = 0, l = inputLinkArray.length; i < l; i++) { for (let j = i + 1; j < l; j++) { if ( getPureLink(inputLinkArray[i]) === getPureLink(inputLinkArray[j]) ) { ++i; j = i; } } outputLinkArray.push(inputLinkArray[i]); } return outputLinkArray; } splitWrap(textArray) { let tempArray = []; textArray.forEach((text) => { if (text) { tempArray = tempArray.concat(text.split('\n').filter((v) => v)); } }); return tempArray; } autoEvent( container, linkObjArray, baiduObjArray, _linksArray, hideTextArray, showTextArray, nodeTextArray, ) { const { url, baidupan, hash, md5 } = reg; const linkArray = []; const linkTextArray = []; linkObjArray.forEach((item) => { linkArray.push(item.eleValue); linkTextArray.push(item.eleContainer); }); if (hideTextArray.length > 0) { hideTextArray = this.splitWrap(hideTextArray); } if (showTextArray.length > 0) { showTextArray = this.splitWrap(showTextArray); } if (nodeTextArray.length > 0) { nodeTextArray = this.splitWrap(nodeTextArray); } const concatTextArray = this.manageRepeatArray( this.decodeLink(hideTextArray), ); let concatLinkArray = this.manageRepeatArray( this.decodeLink(this.manageText(linkArray.concat(concatTextArray))), ); const generalTextArray = showTextArray.concat( nodeTextArray.concat(linkTextArray), ); const indexA = []; const codeB = this.pickUpBaidupanCode(concatTextArray); let codeC = []; if (codeB.length > 0) { for (let j = 0; j < concatLinkArray.length; j++) { if (baidupan.test(concatLinkArray[j])) { indexA.push(j); } } if (codeB.length === indexA.length) { for (let k = 0; k < indexA.length; k++) { if (!/\?pwd=/.test(concatLinkArray[indexA[k]])) { concatLinkArray[indexA[k]] += '?pwd=' + codeB[k]; } } } else if (codeB.length === baiduObjArray.length) { for (let l = 0; l < baiduObjArray.length; l++) { if (!/\?pwd=/.test(baiduObjArray[l].ele.href)) { baiduObjArray[l].ele.textContent = baiduObjArray[l].eleContainer + '?pwd=' + codeB[l]; baiduObjArray[l].ele.href = baiduObjArray[l].eleValue + '?pwd=' + codeB[l]; } } } } else { codeC = this.pickUpBaidupanCode(generalTextArray); if (codeC.length > 0) { for (let j = 0; j < concatLinkArray.length; j++) { if (baidupan.test(concatLinkArray[j])) { indexA.push(j); } } if (codeC.length === indexA.length) { for (let k = 0; k < indexA.length; k++) { concatLinkArray[indexA[k]] += '?pwd=' + codeC[k]; } } else if (codeC.length === baiduObjArray.length) { for (let l = 0; l < baiduObjArray.length; l++) { baiduObjArray[l].ele.textContent = baiduObjArray[l].eleContainer + '?pwd=' + codeC[l]; baiduObjArray[l].ele.href = baiduObjArray[l].eleValue + '?pwd=' + codeC[l]; } } } } let hashArray = []; generalTextArray.forEach((item) => { if (!url.test(item)) { if (!md5.test(item) && hash.test(item)) { hashArray.push('magnet:?xt=urn:btih:' + hash.exec(item)[1]); } else if (item.length > 32) { let temp_link = this.pickUpMagnet(item); temp_link && hashArray.push(temp_link); } } }); hashArray = this.decodeLink(hashArray); concatLinkArray = this.manageRepeatArray( concatLinkArray.concat(hashArray), ); if (this.config.get('checkEnable')) { for (let p of baiduObjArray) { this.checkBaidupan(p.eleValue, p.ele); } } const hideCodeTextArray = this.decodeCoreValues( container, hideTextArray.concat(generalTextArray), ); if (hideCodeTextArray.length > 0) { hideCodeTextArray.forEach((item, index) => { if (!url.test(item)) { if (!md5.test(item) && hash.test(item)) { hideCodeTextArray[index] = 'magnet:?xt=urn:btih:' + hash.exec(item)[1]; } else if (item.length > 32) { const tempLink = this.pickUpMagnet(item); if (tempLink) { hideCodeTextArray[index] = tempLink; } } } }); concatLinkArray = this.manageRepeatArray( concatLinkArray.concat(hideCodeTextArray), ); } concatLinkArray = concatLinkArray .map((item) => { if (generalTextArray.includes(item)) { return null; } return item; }) .filter((v) => v); return concatLinkArray; } foyuPromise(encoded) { return new Promise(function (resolve, _reject) { GM_xmlhttpRequest({ method: 'POST', url: 'https://keyfc.net/bbs/tools/tudou.aspx', data: 'orignalMsg=' + encoded.replace(/\s/g, '') + '&action=Decode', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, onload: function (res) { if (res.status == 200 && res.readyState == 4) { resolve( res.responseText.replace(/^<\/Message><\/BUDDHIST>$/g, ''), ); } else { console.warn('福利吧小助手:\n自动解码出错!'); resolve(''); } }, onerror: function () { console.error('福利吧小助手:\n网络链接出错!'); resolve(''); }, }); }); } async foyuDecode(container, encoded) { await this.foyuPromise(encoded).then((data) => { data && this.createGoodBoyFrame(container, [data]); }); } decodeCoreValues(container, textArray) { const { core, baijia, foyu } = reg; const decodeArray = []; textArray.forEach((item) => { if (core.test(item)) { decodeArray.push(coreValuesDecode(core.exec(item)[1])); } else if (baijia.test(item)) { decodeArray.push(baijiaDecode(baijia.exec(item)[1])); } else if (foyu.test(item)) { this.foyuDecode(container, foyu.exec(item)[1]); } }); return decodeArray; } checkBaidupan(linkValue, linkDom) { GM_xmlhttpRequest({ url: linkValue, method: 'GET', headers: { 'Content-type': 'application/x-www-form-urlencoded', }, onload: function (res) { if (res.status === 200) { if ( res.responseText.indexOf('此链接分享内容可能因为涉及侵权') !== -1 || res.responseText.indexOf('你所访问的页面不存在了') !== -1 || res.responseText.indexOf('分享的文件已经被取消了') !== -1 ) { linkDom.classList.add('link_faild'); linkDom.title = '链接资源已经失效!'; } else { linkDom.title = '链接资源正常。'; } } else { console.warn( '福利吧小助手:\n请求返回状态码异常:', res.status, ); } }, onerror: function (err) { console.warn( '福利吧小助手:\n网络连接失败。\n', linkValue, err, ); }, ontimeout: function () { console.warn('福利吧小助手:\n请求超时。\n', linkValue); }, }); } } function randBin() { return Math.random() >= 0.5; } function str2Utf8(str) { const ENCODED_CHARS = /[A-Za-z0-9\-_.!~*'()]/g; return Array.from(str) .map((char) => { if (ENCODED_CHARS.test(char)) { ENCODED_CHARS.lastIndex = 0; return char.codePointAt(0).toString(16); } const code = char.charCodeAt(0); if (code < 128) { return code.toString(16).padStart(2, '0'); } if (code < 2048) { return ( ((code >> 6) | 0xc0).toString(16) + ((code & 0x3f) | 0x80).toString(16) ); } return ( ((code >> 12) | 0xe0).toString(16) + (((code >> 6) & 0x3f) | 0x80).toString(16) + ((code & 0x3f) | 0x80).toString(16) ); }) .join('') .toUpperCase(); } function hex2Duo(hexs) { const duo = new Array(hexs.length * 2); let index = 0; const len = hexs.length; for (let i = 0; i < len; i++) { const n = hexs[i] >= 'a' ? hexs.charCodeAt(i) - 87 : hexs[i] >= 'A' ? hexs.charCodeAt(i) - 55 : hexs.charCodeAt(i) - 48; if (n < 10) { duo[index++] = n; } else { if (randBin()) { duo[index++] = 10; duo[index++] = n - 10; } else { duo[index++] = 11; duo[index++] = n - 6; } } } return duo.slice(0, index); } function utf82Str(utfs) { const len = utfs.length * 2; const arr = new Array(len); for (let i = 0, j = 0; i < utfs.length; i++) { arr[j++] = '%'; arr[j++] = utfs[i]; } return decodeURIComponent(arr.join('')); } function duo2Hex(duo) { const l = duo.length; const result = new Array(l); let pos = 0; for (let i = 0; i < l; i++) { const curr = duo[i]; if (curr < 10) { result[pos++] = curr.toString(16).toUpperCase(); } else if (curr === 10) { result[pos++] = (duo[++i] + 10).toString(16).toUpperCase(); } else { result[pos++] = (duo[++i] + 6).toString(16).toUpperCase(); } } return result.slice(0, pos).join(''); } function duo2Values(duo) { return duo.map((d) => coreValues[2 * d] + coreValues[2 * d + 1]).join(''); } function coreValuesEncode(str) { return duo2Values(hex2Duo(str2Utf8(str))); } function coreValuesDecode(encoded) { const duo = []; for (let c of encoded) { let i = coreValues.indexOf(c); if (i === -1) { continue; } else if (i & 1) { continue; } else { duo.push(i >> 1); } } const hexs = duo2Hex(duo); let str; try { str = utf82Str(hexs); } catch (e) { throw e; } return str; } function isFloat(str) { return str == '右侧'; } function baijiaEncode(str) { const cleaned = str.replace(TRIM_REGEX, ''); const value = cleaned.replace(MAGNET_PREFIX_REGEX, ''); return Array.from(value) .map((char) => reverseMap.get(char) || '') .join(''); } function baijiaDecode(encoded) { const decoded = Array.from(encoded) .map((char) => baijiaValues.get(char) || '') .join(''); if (HTTP_PROTOCOL_REGEX.test(decoded)) { return decoded.replace(/^(https?)/, '$1:'); } if (URL_PROTOCOL_REGEX.test(decoded)) { return decoded; } return `magnet:?xt=urn:btih:${decoded}`; } function convertChineseNumber(textString) { return textString.replace( /[零一二三四五六七八九壹贰叁肆伍陆柒捌玖]/gi, (arg0) => { let index = '零一二三四五六七八九'.indexOf(arg0); if (index === -1) { index = '壹贰叁肆伍陆柒捌玖'.indexOf(arg0) + 1; } return index; }, ); } function filterLink(inputLink) { let status = true; if (inputLink) { for (let i in filterReg) { if (filterReg[i].test(inputLink)) { status = false; break; } } } else { status = false; } return status; } function getPureLink(inputLink, depthBoolean) { const { baidupanIncludeCode } = reg; let outputLink = inputLink; if (depthBoolean) { if (baidupanIncludeCode.test(outputLink)) { if (/#[a-z0-9]{4}$/i.test(outputLink)) { outputLink = outputLink.replace(/#[a-z0-9]{4}$/i, ''); } } else if ( /^https?:\/\/www\.bilibili\.com\/video\/av\d+\?from=search/i.test( outputLink, ) ) { outputLink = outputLink.replace(/\?from=search.*/, ''); } } let returnLink = outputLink .replace( /(^(?:\s+)?(?:\[url\])?(?:\s+)?(?:https?:\/\/)?|(?:\/+)?(?:\s+)?(?:\[\/url\])?$|%C2%A0$)/gi, '', ) .replace(/%C2%A0/gi, '%20'); try { returnLink = decodeURI(returnLink); } catch (e) { console.warn( '福利吧小助手:\n出现编码转换错误。', outputLink, ); console.warn(e); returnLink = outputLink .replace( /(^(?:\s+)?(?:\[url\])?(?:\s+)?(?:https?:\/\/)?|(?:\/+)?(?:\s+)?(?:\[\/url\])?$|%C2%A0$)/gi, '', ) .replace(/%C2%A0/gi, '%20'); } return returnLink; } function contrastTextAndLink(textValue, linkValue) { let sta = true; textValue = getPureLink(textValue, true); linkValue = getPureLink(linkValue, true); if (/\s...\s/i.test(textValue)) { sta = false; } else if (textValue === linkValue) { sta = false; } return sta; } function findLink(container) { const { baidupan } = reg; const linkA = container.getElementsByTagName('a'); const tempObj = { linkObjArray: [], baiduObjArray: [], linksArray: [], }; const tempBaiduArray = []; for (let i = 0; i < linkA.length; i++) { if (linkA[i].closest('div.aimg_tip')) { continue; } const tempLink = linkA[i].href; if (filterLink(tempLink)) { const tempImg = linkA[i].querySelectorAll('img'); if ( tempImg.length === 0 || (tempImg.length > 0 && tempImg[0].src !== tempLink && tempImg[0].getAttribute('file') !== tempLink) ) { const tempText = linkA[i].innerText.replace(/^\s+|\s+$/gi, ''); if (contrastTextAndLink(tempText, tempLink)) { const linkObj = { eleValue: tempLink, eleContainer: tempText, ele: linkA[i], }; tempObj.linkObjArray.push(linkObj); } else if (baidupan.test(tempLink)) { const baiduObj = { eleValue: tempLink, eleContainer: tempText, ele: linkA[i], }; if (tempBaiduArray.indexOf(tempLink) === -1) { tempBaiduArray.push(tempLink); tempObj.baiduObjArray.push(baiduObj); } } } tempObj.linksArray.indexOf(tempLink) === -1 && tempObj.linksArray.push(tempLink); } } return tempObj; } // 定义常量,提高可读性和性能 const GRAY_THRESHOLD = 192; const OPACITY_THRESHOLD = 0.2; const GRAY_COEFFICIENTS = { R: 0.299, G: 0.587, B: 0.114, }; function judgeColor(color) { // 使用一个正则表达式同时匹配 rgb 和 rgba const matches = color.match( /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d*\.?\d+))?\)/i, ); if (!matches) return false; const [, r, g, b, a = 1] = matches.map((val) => +val); // 如果是 rgba 且透明度低于阈值,直接返回 if (a <= OPACITY_THRESHOLD) return true; // 计算灰度值 const grayLevel = r * GRAY_COEFFICIENTS.R + g * GRAY_COEFFICIENTS.G + b * GRAY_COEFFICIENTS.B; return grayLevel > GRAY_THRESHOLD; } // 优化后的 rgb 转 rgba 函数 function rgb2Rgba(colorString) { const matches = colorString.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/i); if (!matches) return colorString; const [, r, g, b] = matches; return `rgba(${r}, ${g}, ${b}, 1)`; } function display_Text(container, newTextColor, newTextBackgroundColor) { const { url } = reg; const textFont = container.getElementsByTagName('font'); const tempObj = { hideTextArray: [], showTextArray: [], }; for (let i = 0; i < textFont.length; i++) { if ( textFont[i].closest('.quote') || textFont[i].getElementsByClassName('aimg_tip').length !== 0 ) { continue; } const tempText = textFont[i].innerText.replace(/^\s+|\s+$/gi, ''); if (!/^\s*$/i.test(tempText)) { const textColor = window.getComputedStyle(textFont[i]).color; const textBackgroundColor = window.getComputedStyle( textFont[i], ).backgroundColor; if (judgeColor(textColor) && judgeColor(textBackgroundColor)) { textFont[i].style.color = newTextColor; tempObj.hideTextArray.push(tempText); } else if (rgb2Rgba(textBackgroundColor) === rgb2Rgba(textColor)) { textFont[i].style.backgroundColor = newTextBackgroundColor; textFont[i].style.color = newTextColor; tempObj.hideTextArray.push(tempText); } else if (!judgeColor(textBackgroundColor) && !judgeColor(textColor)) { textFont[i].style.backgroundColor = newTextBackgroundColor; textFont[i].style.color = newTextColor; tempObj.hideTextArray.push(tempText); } else if ( textFont[i].childNodes.length === 1 && textFont[i].childNodes[0].nodeType === 3 ) { if (GM_config.get('extractEnable')) { if (url.test(tempText)) { textFont[i].innerHTML = textFont[i].innerHTML.replace( url, (_arg0, arg1) => { return ( '' + convertChineseNumber(arg1) + '' ); }, ); } } !tempObj.showTextArray.includes(tempText) && tempObj.showTextArray.push(tempText); } else if (textFont[i].childNodes.length > 1) { const tFont = textFont[i].childNodes; for (let child_index in tFont) { analysisText(tFont[child_index]); } !tempObj.showTextArray.includes(tempText) && tempObj.showTextArray.push(tempText); } } } const tempTable = container.getElementsByTagName('table'); for (let j = 0; j < tempTable.length; j++) { if ( !judgeColor(tempTable[j].style.backgroundColor) && !judgeColor(tempTable[j].style.color) ) { tempTable[j].style.backgroundColor = newTextBackgroundColor; } else if ( judgeColor(tempTable[j].style.color) && judgeColor(tempTable[j].style.backgroundColor) ) { tempTable[j].style.color = newTextColor; } } return tempObj; } function text2A(node) { const { url } = reg; const tempSpan = document.createElement('span'); tempSpan.innerHTML = node.nodeValue.replace(url, (arg0, arg1) => { if (arg1.length > 2000) { return arg0; } return arg0.replace( arg1, '' + convertChineseNumber(arg1) + '', ); }); node.parentNode.replaceChild(tempSpan, node); } function analysisText(domPoint) { const { url } = reg; const nodeList = domPoint.childNodes; const nodeTextArray = []; for (let i in nodeList) { if (nodeList[i].nodeType === 3) { const tempText = nodeList[i].nodeValue.replace(/^\s+|\s+$/gi, ''); if (!/^\s*$/i.test(tempText)) { if (GM_config.get('extractEnable')) { if (url.test(tempText)) { text2A(nodeList[i]); } } nodeTextArray.push(tempText); } } else if ( nodeList[i].nodeType === 1 && !nodeList[i].className.includes('quote') && !nodeList[i].className.includes('pstatus') && !nodeList[i].className.includes('aimg_tip') && !nodeList[i].className.includes('blockcode') && nodeList[i].nodeName !== 'FONT' && nodeList[i].nodeName !== 'A' && nodeList[i].nodeName !== 'SCRIPT' && nodeList[i].childNodes.length > 0 ) { const recursiveArray = analysisText(nodeList[i]); for (let j in recursiveArray) { nodeTextArray.push(recursiveArray[j]); } } } return nodeTextArray; } function isMobilePage() { return /android|webos|iphone|ipod|blackberry/i.test(navigator.userAgent); } function getNowDate() { const now = new Date(); return now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate(); } function getUpdateTime(unixTime) { if (!unixTime) return ''; const formatter = new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false, }); return ` (更新时间: ${formatter.format(new Date(unixTime)).replace(/\//g, '-')})`; } // 用户权限相关的纯函数 function calculateUserAccess(level) { if (level in CONFIG.LEVEL_ACCESS_MAP) { return CONFIG.LEVEL_ACCESS_MAP[level]; } return level >= 1 && level <= 8 ? level * 10 : CONFIG.DEFAULT_ACCESS_NUM; } // 样式处理相关的纯函数 function getPostStyle(type, color = '') { const styles = { blocked: 'color: #999; font-weight: bold; text-decoration-line: line-through; text-decoration-color: #000000;', restricted: 'color: #999; font-weight: bold;', highlighted: `font-weight: bold; color: ${color};`, }; return styles[type] || ''; } // 数字提取工具函数 function extractNumber(text) { if (!text) return 0; return Number(text.replace('+', '')); } // 获取最大点赞数 function getMaxAgreeCount(fontElements) { return Array.from(fontElements) .map((el) => extractNumber(el.textContent)) .reduce((max, current) => Math.max(max, current), 0); } function highlightPost() { // 确保DOM已经加载 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => initHighlight()); } else { initHighlight(); } } // 初始化高亮功能 function initHighlight() { try { updateUserAccessLevel(); initializePostHighlighting(); } catch (error) { console.warn('福利吧小助手:\n执行出错:', error.message); } } // 更新用户访问权限 function updateUserAccessLevel() { try { const upMineElement = document.getElementById('g_upmine'); if (!upMineElement) return; const levelMatch = /LV\.(-?[0-9])/.exec(upMineElement.textContent); if (!levelMatch) return; const newAccessNum = calculateUserAccess(levelMatch[1]); if (status.accessNum !== newAccessNum) { status.accessNum = newAccessNum; GM_config.setValue('accessNumber', newAccessNum); } } catch (error) { console.warn( '福利吧小助手:\n识别用户阅读权限出错,将使用存储中记录的用户阅读权限。', ); } console.debug( '福利吧小助手:\n用户阅读权限:', status.accessNum, ); } // 初始化帖子高亮 function initializePostHighlighting() { // 缓存选择器字符串,避免重复创建字符串 const THREADLIST_SELECTOR = '#threadlisttableid'; // 立即检查目标元素 const threadlist = document.querySelector(THREADLIST_SELECTOR); if (threadlist) { processThreadList(threadlist); return; } // 创建单个共享的 MutationObserver 配置对象 const observerConfig = { childList: true, subtree: true, }; // 使用函数声明提升性能,避免在回调中重复创建函数 function threadlistCallback(mutations, obs) { const threadlist = document.querySelector(THREADLIST_SELECTOR); if (threadlist) { processThreadList(threadlist); obs.disconnect(); } } function bodyCallback(mutations, obs) { if (document.body) { obs.disconnect(); const observer = new MutationObserver(threadlistCallback); observer.observe(document.body, observerConfig); } } // 主逻辑 if (document.body) { const observer = new MutationObserver(threadlistCallback); observer.observe(document.body, observerConfig); } else { const bodyObserver = new MutationObserver(bodyCallback); bodyObserver.observe(document.documentElement, { childList: true, }); } } // 处理帖子列表 function processThreadList(tbody) { const items = tbody.querySelectorAll('.common, .new, .lock'); items.forEach(processPostItem); } // 处理单个帖子 function processPostItem(item) { const titleElement = item.querySelector('.xst'); if (!titleElement) return; // 如果已经是加粗样式,跳过处理 if (titleElement.style.fontWeight === '700') return; const readNum = extractNumber(item.querySelector('.xw1')?.textContent); // 处理阅读权限 if (readNum > CONFIG.MAX_ACCESS_NUM) { titleElement.setAttribute('style', getPostStyle('blocked')); return; } if (readNum > status.accessNum) { titleElement.setAttribute('style', getPostStyle('restricted')); return; } // 处理点赞数 const agreeNum = getMaxAgreeCount(item.querySelectorAll('font')); if (agreeNum >= GM_config.get('agreeThreshold')) { titleElement.setAttribute( 'style', getPostStyle('highlighted', GM_config.get('agreeColor')), ); return; } // 处理回复数 const replyNum = extractNumber( item.parentNode.querySelector('td.num a')?.textContent, ); if (replyNum >= GM_config.get('replyTHreshold')) { titleElement.setAttribute( 'style', getPostStyle('highlighted', GM_config.get('replyColor')), ); } } function createSettingsIcon() { const iconSpan = document.createElement('span'); iconSpan.id = 'settingsIcon'; iconSpan.title = '打开福利吧小助手设置'; iconSpan.addEventListener('click', () => { GM_config.open(); }); return iconSpan; } function operateCode(inputId, outputId, callback, waitStr = '') { const str = document.getElementById(inputId).value; if (str) { document.getElementById(outputId).value = waitStr; const result = callback(str, outputId); if (result) { document.getElementById(outputId).value = result; } } } function copyCode(copyBtn, resultId) { const copyStr = document.getElementById(resultId).value; if (copyStr) { GM_setClipboard(copyStr, 'text'); copyBtn.title = '复制成功'; copyBtn.classList.add('a_copy_completed'); status.timer3 && clearTimeout(status.timer3); status.timer3 = setTimeout(() => { copyBtn.classList.remove('a_copy_completed'); copyBtn.title = '将输出的结果复制到剪贴板中'; }, 2000); } } function createSwitchSpan(keyValue, domArray) { const switchSpan = document.createElement('span'); switchSpan.className = 'o'; const switchImg = document.createElement('img'); switchImg.id = keyValue + '_user_img'; switchImg.title = '收起/展开'; switchImg.alt = '收起/展开'; if (status[keyValue]) { domArray.forEach(function (item) { item.classList.add('collapsed_hide'); }); switchImg.src = icon.collapsedYes; } else { switchImg.src = icon.collapsedNo; } switchImg.addEventListener('click', () => { if (status[keyValue]) { domArray.forEach((item) => { item.classList.remove('collapsed_hide'); }); switchImg.src = icon.collapsedNo; status[keyValue] = false; } else { domArray.forEach((item) => { item.classList.add('collapsed_hide'); }); switchImg.src = icon.collapsedYes; status[keyValue] = true; } GM_config.setValue(keyValue, status[keyValue]); }); switchSpan.appendChild(switchImg); return switchSpan; } function createSignatureSwitch(signature, switchStatus = true) { const switchDiv = document.createElement('div'); switchDiv.className = 'signature_switch_div'; if (switchStatus) { switchDiv.title = '收起'; } else { switchDiv.title = '展开'; switchDiv.classList.add('signature_switch_close'); signature.classList.add('signature_hide'); } switchDiv.addEventListener( 'click', () => { if (switchStatus) { switchStatus = false; switchDiv.title = '展开'; switchDiv.classList.add('signature_switch_close'); signature.classList.add('signature_hide'); } else { switchStatus = true; switchDiv.title = '收起'; switchDiv.classList.remove('signature_switch_close'); signature.classList.remove('signature_hide'); } }, false, ); return switchDiv; } function mobileInit() { const { checkDate, oldUrl } = status; if (GM_config.get('highlightEnable')) { if ( oldUrl.indexOf('mod=forumdisplay') !== -1 || /forum-\d+-\d+\.html/i.test(oldUrl) ) { document.body.arrive( '.threadlist li', { fireOnAttributesModification: true, existing: true }, function () { let replyNum = this.querySelector( 'span.num.icon.iconfont', ).textContent; if (replyNum) { replyNum = Number(/\d+/.exec(replyNum)[0]); if (replyNum >= GM_config.get('replyTHreshold')) { this.querySelector('div.thread-item-sub').setAttribute( 'style', 'font-weight: bold; color: ' + GM_config.get('replyColor') + ';', ); } } }, ); } } if ( oldUrl.indexOf('mod=viewthread') !== -1 || /thread-\d+-\d+(?:-\d+)?\.html/i.test(oldUrl) ) { const phoneBackgroundColor = window.getComputedStyle( document.body, ).backgroundColor; const messageDom = document.querySelectorAll('.message'); for (let messageEle of messageDom) { const textObj = display_Text( messageEle, GM_config.get('textColor'), phoneBackgroundColor, ); const textArray = analysisText(messageEle); const linkObj = findLink(messageEle); const goodBoyObj = new Good_Boy(GM_config); goodBoyObj.createGoodBoyElement( messageEle, linkObj, textObj, textArray, ); } } if (GM_config.get('autoCheckInEnable')) { document.body.arrive( '.bg > a', { onceOnly: true, existing: true }, function (item) { if (item.textContent === '签到领奖') { const nowDate = getNowDate(); if (nowDate !== checkDate) { GM_config.setValue('checkEnable', nowDate); setTimeout(() => { item.click(); }, 2000); console.info('福利吧小助手:\n完成自动签到。'); } } }, ); } } function pcInit() { const { baseImage } = reg; const { oldUrl } = status; if ( oldUrl.indexOf('mod=forumdisplay') !== -1 || /forum-\d+-\d+\.html/i.test(oldUrl) ) { if (oldUrl.indexOf('fid=37') !== -1 || /forum-37-/i.test(oldUrl)) { document.arrive( 'div.bm_h.cl', { fireOnAttributesModification: true, onceOnly: true, existing: true, }, function () { if (this.querySelectorAll('span.y').length === 0) { const themeArray = []; themeArray.push(this.nextElementSibling); this.insertBefore( createSwitchSpan('collapsedGwwzEnable', themeArray), this.childNodes[0], ); } }, ); } GM_config.get('highlightEnable') && highlightPost(); if (GM_config.get('visitedEnable')) { const visitedStyle = '.tl th a.s.xst:visited, .tl td.fn a:visited { color: ' + GM_config.get('visitedColor') + ' !important; }'; GM_addStyle(visitedStyle); console.debug( '福利吧小助手:\n完成注入自定义己访问帖子的样式。', ); } } if ( oldUrl.indexOf('mod=viewthread') !== -1 || /thread-\d+-\d+(?:-\d+)?\.html/i.test(oldUrl) ) { document.addEventListener( 'DOMContentLoaded', () => { const tFImg = document.querySelectorAll('td.t_f img'); for (let imgEle of tFImg) { let baseSrc = imgEle.getAttribute('file'); if (baseImage.test(baseSrc)) { baseSrc = baseSrc.replace(baseImage, '$1'); imgEle.setAttribute('file', baseSrc); imgEle.src = baseSrc; } } const zoomImg = document.querySelectorAll('.t_f img.zoom'); for (let zoomEle of zoomImg) { zoomEle.removeAttribute('height'); } const htmlBackgroundColor = window.getComputedStyle( document.body, ).backgroundColor; const tFDom = document.querySelectorAll('td.t_f'); for (let domEle of tFDom) { const goodBoyObj = new Good_Boy(GM_config); if (isFloat(GM_config.get('displayPosition'))) { const favatarBtn = domEle .closest('table.plhin') .querySelector('div.favatar'); const textObj = display_Text( domEle, GM_config.get('textColor'), htmlBackgroundColor, ); const textArray = analysisText(domEle); const linkObj = findLink(domEle); goodBoyObj.createGoodBoyElement( favatarBtn, linkObj, textObj, textArray, ); } else { const mainBtn = domEle.closest('div.pcb').querySelector('div.t_fsz') || domEle.closest('div.pcb').querySelector('div.pcbs'); const textObj = display_Text( domEle, GM_config.get('textColor'), htmlBackgroundColor, ); const textArray = analysisText(domEle); const linkObj = findLink(domEle); goodBoyObj.createGoodBoyElement( mainBtn, linkObj, textObj, textArray, ); } } const signA = document.querySelectorAll('div.sign a'); for (let signEle of signA) { if (/member\.php\?mod=logging&action=logout/i.test(signEle.href)) { signEle.style.display = 'none'; } } if (GM_config.get('signatureEnable')) { const sign = document.querySelectorAll('div.sign'); const signStatus = GM_config.get('signatureSwitch') == '展开'; for (let signItem of sign) { signItem.insertAdjacentElement( 'beforebegin', createSignatureSwitch(signItem, signStatus), ); } } }, false, ); } if (GM_config.get('autoCheckInEnable')) { document.arrive( '#fx_checkin_topb', { fireOnAttributesModification: true, onceOnly: true, existing: true }, function () { if (this.getElementsByTagName('img')[0].alt !== '已签到') { if (typeof fx_checkin === 'function') { this.click(); } else { setTimeout(() => { this.click(); }, 2000); } console.info('福利吧小助手:\n自动签到完成。'); } }, ); } if (GM_config.get('codeEnable') || GM_config.get('nightBtnEnable')) { document.addEventListener('DOMContentLoaded', function () { const expandBox = document.createElement('div'); expandBox.className = 'expand_box'; if (GM_config.get('codeEnable') && GM_config.get('nightBtnEnable')) { expandBox.className = 'expand_box_h'; } expandBox.onmouseenter = function () { this.classList.add('show_expand_box'); }; expandBox.onmouseleave = function () { this.classList.remove('show_expand_box'); }; if (GM_config.get('codeEnable')) { // 创建和初始化面板的函数 const createCodePanel = () => { // 使用 DocumentFragment 减少DOM重排 const fragment = document.createDocumentFragment(); const codeFrame = document.createElement('div'); fragment.appendChild(codeFrame); // 提取共用的field配置 const createTextField = (label, section = null) => ({ label: label, section: section, type: 'textarea', labelPos: 'above', placeholder: '请输入内容', default: '', save: false, }); const createButtonField = (label, title, clickHandler) => ({ label: label, title: title, type: 'button', click: clickHandler, }); // 创建编解码处理器工厂 const createCodeHandler = (inputId, outputId, processor, processingMsg) => () => operateCode(inputId, outputId, processor, processingMsg); // 提取重复的URL配置 const links = { baijia: `${SITE_URLS.HOME}/anhao.html`, coreValues: 'https://github.com/sym233/core-values-encoder', yflc: 'http://keyfc.net/bbs/tools/tudoucode.aspx', }; // 优化与佛论禅的网络请求处理 const createYflcProcessor = (action) => (str, resultId) => { const handleResponse = (res) => { const outputEl = document.getElementById(resultId); if (res.status === 200 && res.readyState === 4) { outputEl.value = res.responseText.replace( /^<\/Message><\/BUDDHIST>$/g, '', ); } else { outputEl.value = `${action}出现错误!`; } }; GM_xmlhttpRequest({ method: 'POST', url: 'https://keyfc.net/bbs/tools/tudou.aspx', data: `orignalMsg=${action === '编码' ? encodeURIComponent(str) : str.replace(/\s/g, '')}&action=${action}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, onload: handleResponse, onerror: () => (document.getElementById(resultId).value = '网络连接出错!'), }); return false; }; // 配置面板 const codePanel = new GM_configStruct({ id: 'myCodePanel', title: '编解码工具', isTabs: true, skin: 'tab', frame: codeFrame, css: style.codePanel, fields: { // 百家姓 bjxInput: { ...createTextField('输入:', [ '百家姓', GM_config.create('a', { textContent: '百家姓编码原示例地址', title: '点击跳转到百家姓编码示例', target: '_blank', href: links.baijia, }), ]), }, bjxEncodeBtn: createButtonField( '编码 >>>', '使用"百家姓"进行编码', createCodeHandler( 'myCodePanel_field_bjxInput', 'myCodePanel_field_bjxOutput', baijiaEncode, '编码中...', ), ), bjxDecodeBtn: createButtonField( '解码 >>>', '对"百家姓"的编码进行解码', createCodeHandler( 'myCodePanel_field_bjxInput', 'myCodePanel_field_bjxOutput', baijiaDecode, '解码中...', ), ), bjxOutput: createTextField('输出:'), bjxCopyBtn: createButtonField( '复制结果', '将输出的结果复制到剪贴板中', function () { copyCode(this, 'myCodePanel_field_bjxOutput'); }, ), // 社会主义核心价值观 coreValuesInput: { ...createTextField('输入:', [ '社会主义核心价值观', GM_config.create('a', { textContent: '社会主义核心价值观编码项目地址', title: '点击跳转到社会主义核心价值观编码项目', target: '_blank', href: links.coreValues, }), ]), }, coreValuesEncodeBtn: createButtonField( '编码 >>>', '使用"社会主义核心价值观"进行编码', createCodeHandler( 'myCodePanel_field_coreValuesInput', 'myCodePanel_field_coreValuesOutput', coreValuesEncode, '编码中...', ), ), coreValuesDecodeBtn: createButtonField( '解码 >>>', '对"社会主义核心价值观"的编码进行解码', createCodeHandler( 'myCodePanel_field_coreValuesInput', 'myCodePanel_field_coreValuesOutput', coreValuesDecode, '解码中...', ), ), coreValuesOutput: createTextField('输出:'), coreValuesCopyBtn: createButtonField( '复制结果', '将输出的结果复制到剪贴板中', function () { copyCode(this, 'myCodePanel_field_coreValuesOutput'); }, ), // 与佛论禅 yflcInput: { ...createTextField('输入:', [ '与佛论禅', GM_config.create('a', { textContent: '与佛论禅编码原工具地址', title: '点击跳转到与佛论禅编码工具', target: '_blank', href: links.yflc, }), ]), }, yflcEncodeBtn: createButtonField( '编码 >>>', '使用"与佛论禅"进行编码', createCodeHandler( 'myCodePanel_field_yflcInput', 'myCodePanel_field_yflcOutput', createYflcProcessor('编码'), '联网进行编码中...', ), ), yflcDecodeBtn: createButtonField( '解码 >>>', '对"与佛论禅"的编码进行解码', createCodeHandler( 'myCodePanel_field_yflcInput', 'myCodePanel_field_yflcOutput', createYflcProcessor('解码'), '联网进行解码中...', ), ), yflcOutput: createTextField('输出:'), yflcCopyBtn: createButtonField( '复制结果', '将输出的结果复制到剪贴板中', function () { copyCode(this, 'myCodePanel_field_yflcOutput'); }, ), // BASE64 base64Input: { ...createTextField('输入:', [ 'BASE64', GM_config.create('a', { textContent: 'crypto-js 项目地址', title: '点击跳转到 crypto-js 项目', target: '_blank', href: 'https://github.com/brix/crypto-js', }), ]), }, base64EncodeBtn: createButtonField( '编码 >>>', '使用"BASE64"进行编码', createCodeHandler( 'myCodePanel_field_base64Input', 'myCodePanel_field_base64Output', (str) => { if (!window.CryptoJS) return 'crypto-js 库文件不存在!'; const words = CryptoJS.enc.Utf8.parse(str); return CryptoJS.enc.Base64.stringify(words); }, '编码中...', ), ), base64DecodeBtn: createButtonField( '解码 >>>', '对"BASE64"的编码进行解码', createCodeHandler( 'myCodePanel_field_base64Input', 'myCodePanel_field_base64Output', (str) => { if (!window.CryptoJS) return 'crypto-js 库文件不存在!'; const words = CryptoJS.enc.Base64.parse(str); return words.toString(CryptoJS.enc.Utf8); }, '解码中...', ), ), base64Output: createTextField('输出:'), base64CopyBtn: createButtonField( '复制结果', '将输出的结果复制到剪贴板中', function () { copyCode(this, 'myCodePanel_field_base64Output'); }, ), }, events: { open: function (doc) { const config = this; const closeBtn = doc.getElementById(config.id + '_closeBtn'); const resetLink = doc.getElementById( config.id + '_resetLink', ); if (closeBtn) closeBtn.title = '关闭面板'; if (resetLink) { resetLink.textContent = '清空内容'; resetLink.title = '清空所有内容'; } }, }, }); // 创建打开面板的按钮 const codeSpan = document.createElement('span'); codeSpan.id = 'myCodeSpan'; codeSpan.title = '打开编解码工具'; codeSpan.addEventListener('click', () => codePanel.open(), { passive: true, }); // 一次性添加所有DOM元素 document.body.appendChild(fragment); expandBox.appendChild(codeSpan); return codePanel; }; // 初始化面板 createCodePanel(); } if (GM_config.get('nightBtnEnable')) { const nightBtnSpan = document.createElement('span'); nightBtnSpan.id = 'myNightSpan'; if (GM_config.get('codeEnable')) { nightBtnSpan.id = 'myNightSpan_2'; } if (status.nightEnable) { nightBtnSpan.style.backgroundImage = icon.modeNight; nightBtnSpan.title = '切换到日间模式'; } else { nightBtnSpan.style.backgroundImage = icon.modeDay; nightBtnSpan.title = '切换到夜间模式'; } nightBtnSpan.addEventListener( 'click', () => { if (status.nightEnable) { status.nightStyleDom && status.nightStyleDom.parentNode.removeChild( status.nightStyleDom, ); status.nightEnable = false; GM_config.setValue('nightEnable', status.nightEnable); nightBtnSpan.title = '切换到夜间模式'; nightBtnSpan.style.backgroundImage = icon.modeDay; } else { status.nightStyleDom = GM_addStyle(style.night); status.nightEnable = true; GM_config.setValue('nightEnable', status.nightEnable); nightBtnSpan.title = '切换到日间模式'; nightBtnSpan.style.backgroundImage = icon.modeNight; } }, false, ); expandBox.appendChild(nightBtnSpan); } document.body.appendChild(expandBox); }); } document.arrive( '#sslct', { fireOnAttributesModification: true, onceOnly: true, existing: true }, (item) => { item.after(createSettingsIcon()); }, ); document.arrive( '.site-nav.site-navbar', { fireOnAttributesModification: true, onceOnly: true, existing: true }, (nav) => { // 在搜索按钮前插入设置图标 const searchLi = nav.querySelector('.navto-search'); if (searchLi) { nav.insertBefore(createSettingsIcon(), searchLi); } else { nav.appendChild(createSettingsIcon()); } }, ); } function aInit() { try { GM_registerMenuCommand('福利吧小助手 - 设置', () => { GM_config.open(); }); } catch (e) { console.error('福利吧小助手:\n在扩展中注册菜单项出错!'); console.error(e); } GM_addStyle(style.basic); if (isMobilePage()) { console.info('福利吧小助手:\n当前页面为移动端页面。'); document.addEventListener('DOMContentLoaded', () => { mobileInit(); }); } else { if (document.head) { if (document.head.querySelector('title')) { if (status.nightEnable) { status.nightStyleDom = GM_addStyle(style.night); } pcInit(); } else { document.addEventListener('DOMContentLoaded', function () { console.warn( '福利吧小助手:\n网页加载失败。即将自动刷新重载。', ); status.timer4 && clearTimeout(status.timer4); status.timer4 = setTimeout(() => { location.reload(); }, 2000); }); } } else { if (status.nightEnable) { status.nightStyleDom = GM_addStyle(style.night); } pcInit(); } } if ( location.hostname.includes('fulibus.net') || location.hostname.includes('fuliba') || location.hostname.includes('f.uliba.net') ) { // 简化首页 removeElements(); adjustStyles(); simplifyNavigation(); removePromotions(); // 处理正文内容 document.addEventListener('DOMContentLoaded', () => { processText(); }); } } // 移除多余元素 function removeElements() { ELEMENTS_TO_REMOVE.forEach((selector) => { const element = document.querySelector(selector); element?.parentNode.removeChild(element); }); } // 调整样式 function adjustStyles() { const header = document.querySelector('.header'); if (header) header.style.padding = '20px 0'; const content = document.querySelector('.content'); if (content) content.style.marginRight = '0'; } // 优化导航栏 function simplifyNavigation() { const nav = document.querySelector('ul.site-nav.site-navbar'); if (!nav) return; function shouldKeepSpecific(element) { const text = element.textContent.trim(); return KEEP_KEYWORDS.some((keyword) => text.includes(keyword)); } function shouldBlock(element) { const text = element.textContent.toLowerCase(); const link = element.querySelector('a')?.href.toLowerCase() || ''; return BLOCK_KEYWORDS.some( (keyword) => text.includes(keyword.toLowerCase()) || link.includes(keyword.toLowerCase()), ); } function shouldKeep(element) { const text = element.textContent; const isSearch = element.classList.contains('navto-search'); const isSpecificItem = shouldKeepSpecific(element); return ( isSpecificItem || isSearch || ((text.includes('福') || text.includes('关于')) && !shouldBlock(element)) ); } function processNavItems(parent) { Array.from(parent.children).forEach((item) => { if (item.tagName.toLowerCase() === 'li') { const subMenu = item.querySelector('.sub-menu'); if (subMenu) { processNavItems(subMenu); } // 如果子菜单为空且父项不是特定保留项,则删除父项 if ( subMenu && subMenu.children.length === 0 && !shouldKeepSpecific(item) ) { item.remove(); } // 如果不应保留,则删除 else if (!shouldKeep(item)) { item.remove(); } } }); } processNavItems(nav); } // 移除推广内容 function removePromotions() { const content = document.querySelector('.content'); if (!content) return; Array.from(content.querySelectorAll('article')).forEach((article) => { const likeCount = parseInt( article.querySelector('.post-like span')?.textContent, ); if (likeCount > 100) article.remove(); }); } // 处理正文内容 function processText() { const paragraphs = document.querySelectorAll('p'); paragraphs.forEach((p) => { const text = p.innerText; // 处理百家姓编码 const surnameMatches = findSurnameEncoding(text); if (surnameMatches.length > 0) { let newText = text; surnameMatches.forEach((match) => { const decoded = processSurnameEncoding(match); if (decoded) { // 创建新的链接元素 const link = document.createElement('a'); link.href = decoded; link.textContent = decoded; link.target = '_blank'; link.className = 'my_good_boy_a'; // 使用原有的链接样式类 // 替换原文本 newText = newText.replace(match, ''); p.innerHTML = newText; p.appendChild(document.createElement('br')); p.appendChild(link); // 添加复制按钮 if (GM_config.get('copyEnable')) { const copyBtn = document.createElement('a'); copyBtn.className = 'my_good_boy_a_copy'; copyBtn.title = '复制链接'; copyBtn.href = 'javascript:;'; copyBtn.textContent = '复制'; copyBtn.addEventListener('click', function () { GM_setClipboard(decoded, 'text'); this.classList.add('a_copy_completed'); this.title = '复制成功'; status.timer1 && clearTimeout(status.timer1); status.timer1 = setTimeout(() => { this.classList.remove('a_copy_completed'); this.title = '复制链接'; }, 2000); }); p.appendChild(copyBtn); } } }); } // 处理YouTube链接 if (text.includes('watch?v=')) { const videoId = text.split('?v=')[1]?.split(/[\s&]/)[0]; if (videoId) { const link = document.createElement('a'); link.href = `https://www.youtube.com/watch?v=${videoId}`; link.textContent = '油管链接'; link.target = '_blank'; link.className = 'my_good_boy_a'; p.appendChild(link); } } }); } // 查找百家姓编码 function findSurnameEncoding(text) { // 使用原有的 reg.baijia 正则表达式 const matches = reg.baijia.exec(text); return matches ? [matches[1]] : []; } // 处理百家姓编码 function processSurnameEncoding(encodedText) { try { // 使用原有的 baijiaDecode 函数解码 const decoded = baijiaDecode(encodedText); // 验证解码结果是否是有效的链接 if (isValidDecodedLink(decoded)) { return decoded; } return null; } catch (e) { console.warn('福利吧小助手:\n百家姓解码出错:', e); return null; } } // 验证解码结果 function isValidDecodedLink(decoded) { // 验证是否是磁力链接 if (decoded.startsWith('magnet:?xt=urn:btih:')) { const hash = decoded.replace('magnet:?xt=urn:btih:', ''); return /^[a-fA-F0-9]{40}$/i.test(hash); } // 验证是否是http/https链接 if (decoded.startsWith('http://') || decoded.startsWith('https://')) { try { new URL(decoded); return true; } catch (e) { return false; } } // 验证是否是其他支持的协议链接 const supportedProtocols = [ 'ed2k://', 'thunder://', 'flashget://', 'qqdl://', 'xfplay://', 'ftp://', ]; return supportedProtocols.some((protocol) => decoded.startsWith(protocol)); } GM_config.init({ id: 'myGoodBoyConfig', title: GM_config.create('a', { textContent: '福利吧小助手-设置 ver.' + GM_info.script.version, title: '点击跳转到脚本页面' + getUpdateTime(GM_info.script.lastModified), target: '_blank', href: 'https://sleazyfork.org/zh-CN/scripts/381494', }), skin: 'tab', css: style.settings, frameStyle: { width: '400px', height: '720px', }, fields: { autoCheckInEnable: { label: '自动签到', title: '进入论坛后自动点击签到按钮', labelPos: 'right', type: 'checkbox', default: true, section: GM_config.create('a', { textContent: '作者: aoguai', title: '点击反馈问题', target: '_blank', href: location.origin + '/home.php?mod=spacecp&ac=pm&op=showmsg&touid=90713', }), }, nightBtnEnable: { label: '显示切换夜间模式的悬浮按钮', title: '将鼠标移至网页右下角弹出 (仅支持电脑端页面)', labelPos: 'right', type: 'checkbox', default: true, }, codeEnable: { label: '显示编解码工具的悬浮按钮', title: '将鼠标移至网页右下角弹出 (仅支持电脑端页面)', labelPos: 'right', type: 'checkbox', default: false, }, copyEnable: { label: '显示复制按钮', title: '在所提取链接后显示复制按钮', labelPos: 'right', type: 'checkbox', default: true, }, extractEnable: { label: '识别文字中的网址并转换为超链接', title: '将帖子中网址文字转换为可点击访问的超链接', labelPos: 'right', type: 'checkbox', default: true, }, checkEnable: { label: '自动检测百度网盘链接有效性', title: '检测并标记出已经失效的百度网盘链接', labelPos: 'right', type: 'checkbox', default: false, }, displayPosition: { label: '自定义提取链接的显示位置: ', title: '指定所提取链接的显示位置 (仅支持电脑端页面)', labelPos: 'left', type: 'select', options: ['底部', '右侧'], default: '底部', }, maxLinkNumber: { label: '所提取链接的最大显示数量: ', title: '每个楼层所提取链接的默认最大显示数量值 (-1 表示无限制)', labelPos: 'left', type: 'int', size: 18, default: 5, }, linkColor: { label: '自定义提取链接的文字颜色: ', title: '设定所提取链接显示的文字颜色', labelPos: 'left', type: 'text', size: 18, default: '#369', }, textColor: { label: '自定义隐藏文字的高亮颜色: ', title: '设定将隐藏文字高亮的颜色', labelPos: 'left', type: 'text', size: 18, default: '#FF33CC', }, signatureEnable: { label: '显示签名档折叠图标', title: '在签名档的左上方显示一个折叠图标', labelPos: 'right', type: 'checkbox', default: true, line: 'start', }, signatureSwitch: { label: '签名档的默认折叠状态: ', title: '自定义签名档默认的折叠状态', labelPos: 'left', type: 'select', options: ['展开', '收起'], default: '展开', line: 'end', }, highlightEnable: { label: '启用热帖高亮功能', title: '在帖子列表页面开启热帖高亮 (移动端页面只支持回复高亮)', labelPos: 'right', type: 'checkbox', default: true, line: 'start', }, agreeThreshold: { label: '按分享值高亮的阈值: ', title: '分享值>=阈值时高亮', labelPos: 'left', type: 'unsigned int', size: 18, default: 20, }, agreeColor: { label: '按分享值高亮的颜色: ', title: '优化级高', labelPos: 'left', type: 'text', size: 18, default: '#EE1B2E', }, replyTHreshold: { label: '按回复数高亮的阈值: ', title: '回复数>=阈值时高亮', labelPos: 'left', type: 'unsigned int', size: 18, default: 50, }, replyColor: { label: '按回复数高亮的颜色: ', title: '优化级低', labelPos: 'left', type: 'text', size: 18, default: '#2B65B7', line: 'end', }, visitedEnable: { label: '标记已打开过的帖子', title: '允许将已打开过的帖子设置成自定义的颜色', labelPos: 'right', type: 'checkbox', default: false, line: 'start', }, visitedColor: { label: '自定义已打开过的帖子的颜色', title: '优先级最高', labelPos: 'left', type: 'text', size: 18, default: '#666', line: 'end', }, }, events: { init: async () => { console.debug('福利吧小助手:\n配置信息读取完成。'); try { // 等待获取网站地址 await initSiteUrls(); // 继续执行其他初始化 aInit(); } catch (error) { console.error('福利吧小助手:\n获取网站地址失败:', error); // 即使获取地址失败也继续执行其他初始化 aInit(); } }, save: () => { location.reload(); }, }, }); })();