// ==UserScript==
// @name 片源网:智能高亮 + 自动复制磁链
// @namespace http://yourwebsite.com
// @version 2.2
// @description 智能高亮 + 自动复制磁链
// @author JSSM
// @license MIT
// @match https://pianyuan.org/m_*
// @match https://pianyuan.org/r_*
// @match https://pianyuan.cc/m_*
// @match https://pianyuan.cc/r_*
// @grant GM_setClipboard
// @grant GM_addStyle
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 1. 注入高亮样式
const styles = `
.qwen-hl-gold { background-color: #fff8e1 !important; color: #e65100 !important; border: 1px solid #ff9800 !important; padding: 1px 4px !important; border-radius: 3px !important; font-weight: 700 !important; margin: 0 1px !important; display: inline-block !important; }
.qwen-hl-orange { background-color: #fff3e0 !important; color: #ef6c00 !important; border: 1px solid #fb8c00 !important; padding: 1px 4px !important; border-radius: 3px !important; font-weight: 700 !important; margin: 0 1px !important; display: inline-block !important; }
.qwen-hl-green { background-color: #e8f5e9 !important; color: #1b5e20 !important; border: 1px solid #4caf50 !important; padding: 1px 4px !important; border-radius: 3px !important; font-weight: 700 !important; margin: 0 1px !important; display: inline-block !important; }
.qwen-hl-blue { background-color: #e3f2fd !important; color: #0d47a1 !important; border: 1px solid #2196f3 !important; padding: 1px 4px !important; border-radius: 3px !important; font-weight: 700 !important; margin: 0 1px !important; display: inline-block !important; }
.qwen-hl-purple { background-color: #f3e5f5 !important; color: #4a148c !important; border: 1px solid #9c27b0 !important; padding: 1px 4px !important; border-radius: 3px !important; font-weight: 700 !important; margin: 0 1px !important; display: inline-block !important; }
.qwen-hl-red { background-color: #ffebee !important; color: #b71c1c !important; border: 1px solid #f44336 !important; padding: 1px 4px !important; border-radius: 3px !important; font-weight: 700 !important; margin: 0 1px !important; display: inline-block !important; text-decoration: line-through !important; opacity: 0.9 !important; }
`;
const styleSheet = document.createElement("style");
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
// 2. 定义关键词规则
const highlightRules = [
// --- 金色:完整未删减/特别版 ---
['INTEGRAL+CUT', 'qwen-hl-gold', 2],
['EXTENDED+CUT', 'qwen-hl-gold', 2],
['DIRECTOR+S+CUT', 'qwen-hl-gold', 3],
['DIRECTOR+CUT', 'qwen-hl-gold', 2],
['Extend+Edtion', 'qwen-hl-orange', 2],
['UNCUT', 'qwen-hl-gold', 1],
['CRITERION', 'qwen-hl-gold', 1],
['CC', 'qwen-hl-gold', 1],
['RESTORED', 'qwen-hl-gold', 1],
['REMASTERED', 'qwen-hl-gold', 1],
['COMPLETE', 'qwen-hl-gold', 1],
['PROPER', 'qwen-hl-gold', 1],
['MULTI', 'qwen-hl-gold', 1],
['DIY', 'qwen-hl-gold', 1],
['EXTENDED', 'qwen-hl-gold', 1], // 单独出现的 Extended 也高亮
['THEATRICAL', 'qwen-hl-orange', 1],
// --- 橙色:国际版/剧场版 ---
['INTERNATIONAL+VERSION', 'qwen-hl-orange', 2],
['THEATRICAL+VERSION', 'qwen-hl-orange', 2],
['EXTENDED+VERSION', 'qwen-hl-gold', 2],
// --- 绿色:原盘/高画质 ---
['REMUX', 'qwen-hl-green', 1],
['BLURAY', 'qwen-hl-green', 1],
['BLU-RAY', 'qwen-hl-green', 1],
['BDREMUX', 'qwen-hl-green', 1],
['UHD', 'qwen-hl-green', 1],
['2160P', 'qwen-hl-green', 1],
['4K', 'qwen-hl-green', 1],
['1080P', 'qwen-hl-green', 1],
['1080I', 'qwen-hl-green', 1],
['720P', 'qwen-hl-green', 1],
['AVC', 'qwen-hl-green', 1],
['MPEG-2', 'qwen-hl-green', 1],
['MPEG2', 'qwen-hl-green', 1],
['LPCM', 'qwen-hl-green', 1],
// --- 蓝色:编码/音效/HDR ---
['X265', 'qwen-hl-blue', 1],
['H265', 'qwen-hl-blue', 1],
['HEVC', 'qwen-hl-blue', 1],
['X264', 'qwen-hl-blue', 1],
['H264', 'qwen-hl-blue', 1],
['AV1', 'qwen-hl-blue', 1],
['10BIT', 'qwen-hl-blue', 1],
['8BIT', 'qwen-hl-blue', 1],
['HDR', 'qwen-hl-blue', 1],
['DV', 'qwen-hl-blue', 1],
['DOVI', 'qwen-hl-blue', 1],
['DOLBY+VISION', 'qwen-hl-blue', 2],
['DTSHD', 'qwen-hl-blue', 1],
['DTS+HD', 'qwen-hl-blue', 2],
['TRUEHD', 'qwen-hl-blue', 1],
['ATMOS', 'qwen-hl-blue', 1],
['SDR', 'qwen-hl-blue', 1],
['AAC', 'qwen-hl-blue', 1],
['FLAC', 'qwen-hl-blue', 1],
['OPUS', 'qwen-hl-blue', 1],
['DTS', 'qwen-hl-blue', 1],
['MA', 'qwen-hl-blue', 1],
['DDP', 'qwen-hl-blue', 1],
['DD', 'qwen-hl-blue', 1],
// --- 紫色:发布组 ---
['SWTYBLZ', 'qwen-hl-purple', 1],
['FGT', 'qwen-hl-purple', 1],
['B0MBARDIERS', 'qwen-hl-purple', 1],
['BOMBARDIERS', 'qwen-hl-purple', 1],
['NAHOM', 'qwen-hl-purple', 1],
['SONYHD', 'qwen-hl-purple', 1],
['WIKI', 'qwen-hl-purple', 1],
['FRAMESTOR', 'qwen-hl-purple', 1],
['DON', 'qwen-hl-purple', 1],
['LIME', 'qwen-hl-purple', 1],
['TERMINAL', 'qwen-hl-purple', 1],
['TERMINAL', 'qwen-hl-purple', 1], // 兼容大小写
['DREAMHD', 'qwen-hl-purple', 1],
['PANAM', 'qwen-hl-purple', 1],
['DDR', 'qwen-hl-purple', 1],
['DTONE', 'qwen-hl-purple', 1],
['CHDBITS', 'qwen-hl-purple', 1],
['HDCHINA', 'qwen-hl-purple', 1],
['YELLOWBEAST', 'qwen-hl-purple', 1],
['GRYM', 'qwen-hl-purple', 1],
['CTRLHD', 'qwen-hl-purple', 1],
['OFT', 'qwen-hl-purple', 1],
['WPI', 'qwen-hl-purple', 1],
['NOWYS', 'qwen-hl-purple', 1],
['CMCT', 'qwen-hl-purple', 1],
['HDBITS', 'qwen-hl-purple', 1],
['BEAST', 'qwen-hl-purple', 1],
['HDS', 'qwen-hl-purple', 1],
['EUREKA', 'qwen-hl-purple', 1],
// --- 红色:低质 ---
['CREEPERS+VERSION', 'qwen-hl-red', 2],
['CAM', 'qwen-hl-red', 1],
['TS', 'qwen-hl-red', 1],
['SCR', 'qwen-hl-red', 1],
['HC', 'qwen-hl-red', 1],
['WORKPRINT', 'qwen-hl-red', 1]
];
// 辅助函数:清理片段以便匹配 (去除所有非字母数字,转大写)
function normalizeSegment(seg) {
return seg.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
}
// 3. 高亮执行函数
function applyHighlights() {
const links = document.querySelectorAll('div.related.allres table.data tr td a');
if (links.length === 0) return;
links.forEach(link => {
if (link.querySelector('[class^="qwen-hl-"]')) return;
const originalText = link.innerText;
// 【关键修改】分词正则:同时支持 空格、点号、连字符
// 这样 "Extended-Cut", "Extended.Cut", "Extended Cut" 都会变成 ["Extended", "Cut"]
let segments = originalText.split(/[\s.\-]+/);
segments = segments.filter(s => s.trim() !== '');
// 检测原始主要分隔符,用于非高亮部分的重建 (虽然高亮块内部我们统一用空格)
let separator = '.';
if (originalText.includes(' ') && !originalText.includes('.')) {
separator = ' ';
} else if ((originalText.match(/\s+/g) || []).length > (originalText.match(/\./g) || []).length) {
separator = ' ';
}
let skip = new Array(segments.length).fill(false);
let htmlParts = new Array(segments.length).fill(null);
// --- 第一步:优先匹配多段组合词 ---
for (const [ruleKey, className, segmentCount] of highlightRules) {
if (segmentCount === 1) continue;
const ruleParts = ruleKey.split('+');
for (let i = 0; i <= segments.length - segmentCount; i++) {
if (skip[i]) continue;
let occupied = false;
for (let k = 1; k < segmentCount; k++) {
if (skip[i+k]) { occupied = true; break; }
}
if (occupied) continue;
let match = true;
for (let k = 0; k < segmentCount; k++) {
if (normalizeSegment(segments[i+k]) !== ruleParts[k]) {
match = false;
break;
}
}
if (match) {
let combinedHtml = [];
for (let k = 0; k < segmentCount; k++) {
skip[i+k] = true;
// 高亮块内部统一用空格连接,看起来更整洁,也解决了原分隔符混乱的问题
if (k > 0) combinedHtml.push(' ');
combinedHtml.push(segments[i+k]);
}
htmlParts[i] = `${combinedHtml.join('')}`;
}
}
}
// --- 第二步:匹配单段词 ---
for (let i = 0; i < segments.length; i++) {
if (skip[i]) continue;
const seg = segments[i];
const cleanSeg = normalizeSegment(seg);
let matchedClass = null;
for (const [ruleKey, className, segmentCount] of highlightRules) {
if (segmentCount !== 1) continue;
if (cleanSeg === ruleKey) {
matchedClass = className;
break;
}
}
if (matchedClass) {
htmlParts[i] = `${seg}`;
} else {
htmlParts[i] = seg;
}
}
// --- 第三步:组装 ---
let finalHtmlParts = [];
for (let i = 0; i < segments.length; i++) {
if (htmlParts[i] !== null) {
finalHtmlParts.push(htmlParts[i]);
}
}
// 非高亮部分之间使用检测到的分隔符,高亮块内部已经是完整的 span 了
// 注意:因为 split 丢弃了所有分隔符,这里 join 会把原本可能是 "-" 的地方变成 "." 或 " "
// 为了视觉一致性,这是可接受的妥协。
link.innerHTML = finalHtmlParts.join(separator);
});
}
// 4. 自动复制磁链
function copyMagnets() {
if (!window.location.pathname.startsWith('/r_')) return;
var magnets = document.querySelectorAll('a.btn-primary.btn-sm');
magnets.forEach(function(magnetElement) {
if (magnetElement.getAttribute('data-copied') === 'true') return;
var magnetText = magnetElement.getAttribute('href');
if (!magnetText) return;
var match = magnetText.match(/magnet:\?xt=urn:btih:[a-zA-Z0-9]+/i);
if (match && match[0]) {
GM_setClipboard(match[0], 'text');
magnetElement.innerHTML = magnetElement.innerHTML.replace('点击使用磁力下载', '磁力已复制到剪贴板');
magnetElement.setAttribute('data-copied', 'true');
}
});
}
// 5. 初始化
function init() {
const path = window.location.pathname;
if (path.startsWith('/m_')) setTimeout(applyHighlights, 300);
if (path.startsWith('/r_')) setTimeout(copyMagnets, 300);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();