// ==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();
},
},
});
})();