Filtering "Incomplete" for PterClub

支持“非完结”种子主副标题过滤 + 精确识别制作组(仅匹配以 - 开头并出现在标题结尾的情况)

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Filtering "Incomplete" for PterClub
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  支持“非完结”种子主副标题过滤 + 精确识别制作组(仅匹配以 - 开头并出现在标题结尾的情况)
// @author       @Zuoans
// @match        https://pterclub.com/torrents.php* 
// @license      MIT
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    // ====================== 样式定义 ======================
    GM_addStyle(`
        :root {
            --blue-start: rgba(51, 160, 200, 0.6);
            --blue-mid: rgba(51, 160, 200, 0.1);
            --purple-start: rgba(147, 112, 219, 0.5);
            --purple-mid: rgba(147, 112, 219, 0.1);
        }

        /* incomplete样式 */
        table.torrentname > tbody > tr.tm-incomplete:not(.tm-group) {
            background: linear-gradient(to right, var(--blue-start) 0%, var(--blue-mid) 50%, rgba(255,255,255,0) 90%) !important;
        }

        /* 制作组样式 */
        table.torrentname > tbody > tr.tm-group:not(.tm-incomplete) {
            background: linear-gradient(to right, var(--purple-start) 0%, var(--purple-mid) 50%, rgba(255,255,255,0) 90%) !important;
        }

        /* incomplete&制作组双重标记样式 */
        table.torrentname > tbody > tr.tm-incomplete.tm-group {
            background: linear-gradient(to right, var(--purple-start) 0%, var(--purple-mid) 50%, rgba(255,255,255,0) 90%) !important;
        }

        /* 文字保护 */
        table.torrentname [class*="tm-"] td {
            text-shadow: 0 1px 1px rgba(255,255,255,0.1),
                         0 -1px 1px rgba(0,0,0,0.1) !important;
        }
    `);

    // 目标制作组列表(新增 PTerWEB)
    const targetGroups = [
        'AdBlue', 'AREY', 'BdC', 'BMDru', 'CatEDU', 'c0kE',
        'doraemon', 'JKCT', 'KMX', 'Lislander', 'RO',
        'Telesto', 'XPcl', 'ZTR', 'PTerWEB'
    ];

    // 辅助函数:转义正则特殊字符
    function escapeRegExp(string) {
        return string.replace(/[.*+?^${}()|[$$\$$]/g, '\\$&');
    }

    // ✅ 制作组正则:只匹配以 - 开头,并出现在标题结尾的组名(如 -ZTR)
    const groupRegex = new RegExp(
        `-(?:${targetGroups.map(g => escapeRegExp(g)).join('|')})(?=[\\s\\W]|$)`, 
        'i'
    );

    // 排除关键词正则(包含 Complete / Fin / FIN+ 的行不能被标记为 non-complete)
    const excludeKeywordRegex = /\b(?:Complete|Fin)(?!\w)|FIN\+/gi;

    // 新增:incomplete 正则(仅检测 SxxExx 或 第X集,不考虑 EP)
    const incompleteRegex = /(?:^|\s)(S\d+E\d+|第\d+集)(?=\s|$)/i;

    function safeHighlight() {
        const rows = document.querySelectorAll('table.torrentname > tbody > tr');

        rows.forEach(tr => {
            tr.classList.remove('tm-incomplete', 'tm-group');

            // 获取主标题
            const titleLink = tr.querySelector('.torrentname a');
            if (!titleLink) return;

            let mainTitle = titleLink.innerText.trim();

            // 获取副标题
            let subTitleEl = tr.querySelector('.torrentname div[style*="margin-top"] span');
            let subTitle = subTitleEl ? subTitleEl.innerText.trim() : '';

            let fullTitle = (mainTitle + ' ' + subTitle).trim();

            // 检查是否包含排除关键词
            const hasExclusion = excludeKeywordRegex.test(fullTitle);

            // 判断是否为非完结(主副标题中任意一个满足即可)
            const isIncomplete = !hasExclusion && incompleteRegex.test(fullTitle);

            // 判断是否为目标制作组(✅ 仅匹配以 - 开头并出现在结尾的组名)
            const isTargetGroup = groupRegex.test(fullTitle);

            if (isIncomplete) tr.classList.add('tm-incomplete');
            if (isTargetGroup) tr.classList.add('tm-group');
        });
    }

    // MutationObserver 设置
    const observer = new MutationObserver(mutations => {
        if (mutations.some(mut => mut.addedNodes.length > 0)) {
            safeHighlight();
        }
    });

    document.addEventListener('DOMContentLoaded', () => {
        safeHighlight();
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });

    // 页面卸载时清理
    window.addEventListener('unload', () => {
        document.querySelectorAll('tr').forEach(el => {
            el.className = el.className.replace(/\btm-\w+\b/g, '');
        });
    });

})();