Greasy Fork

Greasy Fork is available in English.

Iwara ID 黑名单 (v3.9 最终版)

在 iwara.tv 上根据作者 Profile ID 屏蔽作品和评论,并提供默认折叠的导入/导出/管理黑名单的功能。

当前为 2025-09-27 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Iwara ID 黑名单 (v3.9 最终版)
// @namespace    http://tampermonkey.net/
// @version      3.9
// @description  在 iwara.tv 上根据作者 Profile ID 屏蔽作品和评论,并提供默认折叠的导入/导出/管理黑名单的功能。
// @author       Gemini
// @match        https://*.iwara.tv/*
// @license      MIT
// @grant        GM_getValue
// @grant        GM_setValue
// @run-at       document-start
// ==/UserScript==

(function() {
    'use-strict';

    const BLACKLIST_KEY = 'iwara_id_blacklist';

    const getBlacklist = () => {
        const defaultValue = '["blacklane"]';
        return new Set(JSON.parse(GM_getValue(BLACKLIST_KEY, defaultValue)));
    };

    const saveBlacklist = (blacklistSet) => {
        GM_setValue(BLACKLIST_KEY, JSON.stringify(Array.from(blacklistSet)));
    };

    const hideBlacklistedWorks = () => {
        const blacklist = getBlacklist();
        if (blacklist.size === 0) return;
        const works = document.querySelectorAll('.videoTeaser:not([data-id-checked]), .imageTeaser:not([data-id-checked])');
        for (const work of works) {
            work.dataset.idChecked = 'true';
            const authorLink = work.querySelector('a.username');
            if (authorLink) {
                const profileId = authorLink.href.split('/profile/')[1];
                if (profileId && blacklist.has(profileId)) {
                    const workContainer = work.closest('[class*="col-"]');
                    if (workContainer) workContainer.style.display = 'none';
                }
            }
        }
    };

    const hideBlacklistedComments = () => {
        const blacklist = getBlacklist();
        if (blacklist.size === 0) return;
        const comments = document.querySelectorAll('.comment:not([data-id-checked])');
        for (const comment of comments) {
            comment.dataset.idChecked = 'true';
            const authorLink = comment.querySelector('a.username');
            if (authorLink) {
                const profileId = authorLink.href.split('/profile/')[1];
                if (profileId && blacklist.has(profileId)) {
                    const commentContainer = comment.closest('.col-12');
                    if (commentContainer) commentContainer.style.display = 'none';
                }
            }
        }
    };

    const addBlockButton = () => {
        if (!window.location.pathname.startsWith('/profile/')) return;
        if (document.querySelector('#author-id-block-btn')) return;
        const container = document.querySelector('.page-profile__header__middle .d-flex.align-items-center');
        if (!container) return;
        const currentProfileId = window.location.pathname.split('/profile/')[1];
        if (!currentProfileId) return;
        const blockButton = document.createElement('div');
        blockButton.id = 'author-id-block-btn';
        Object.assign(blockButton.style, {
            marginLeft: '16px', padding: '4px 10px', border: '1px solid #ccc',
            borderRadius: '5px', cursor: 'pointer', fontSize: '14px',
            fontWeight: 'bold', userSelect: 'none', transition: 'all 0.2s ease'
        });

        const updateButtonState = (isBlocked) => {
            if (isBlocked) {
                // 已拉黑状态
                blockButton.textContent = '🚫已拉黑此ID (点击移除)';
                blockButton.style.borderColor = '#e91e63';
                blockButton.style.color = '#e91e63';
                blockButton.style.backgroundColor = '#fce4ec';
            } else {
                // --- 核心改动:更新按钮的文本和样式 ---
                // 未拉黑 (正常) 状态
                blockButton.textContent = '✅正常状态 (点击拉黑)';
                blockButton.style.borderColor = '#4CAF50';
                blockButton.style.color = '#4CAF50';
                blockButton.style.backgroundColor = '#e8f5e9';
            }
        };

        let blacklist = getBlacklist();
        updateButtonState(blacklist.has(currentProfileId));
        blockButton.addEventListener('click', (e) => {
            e.stopPropagation();
            let currentBlacklist = getBlacklist();
            if (currentBlacklist.has(currentProfileId)) {
                currentBlacklist.delete(currentProfileId);
            } else {
                currentBlacklist.add(currentProfileId);
            }
            saveBlacklist(currentBlacklist);
            updateButtonState(currentBlacklist.has(currentProfileId));

            const managerList = document.querySelector('#blacklist-manager-list');
            const toggleBtn = document.querySelector('#toggle-blacklist-view-btn');
            if (managerList && toggleBtn) {
                renderBlacklistDisplay(managerList);
                updateToggleBtnText(toggleBtn, managerList);
            }
        });
        container.appendChild(blockButton);
    };

    const updateToggleBtnText = (btn, listElement) => {
        const count = getBlacklist().size;
        const isHidden = listElement.style.display === 'none';
        btn.textContent = `${isHidden ? '显示' : '隐藏'}列表 (${count}个)`;
    };

    const renderBlacklistDisplay = (targetElement) => {
        const blacklist = getBlacklist();
        targetElement.innerHTML = '';
        if (blacklist.size === 0) {
            targetElement.textContent = '黑名单为空。';
            return;
        }
        blacklist.forEach(id => {
            const item = document.createElement('div');
            item.style.cssText = 'display: flex; justify-content: space-between; padding: 2px 5px; border-bottom: 1px solid #eee;';
            item.innerHTML = `
                <a href="/profile/${id}" target="_blank" style="color: #337ab7;">${id}</a>
                <button data-id="${id}" class="remove-id-btn" style="cursor: pointer; color: red; background: none; border: none; font-size: 12px;">[移除]</button>
            `;
            targetElement.appendChild(item);
        });
    };

    const createManagementUI = () => {
        if (document.querySelector('#blacklist-manager')) return;
        const footerThreadsBlock = document.querySelector('.footer__threads');
        if (!footerThreadsBlock) return;
        const targetContainer = footerThreadsBlock.closest('.block');
        if (!targetContainer) return;

        const managerDiv = document.createElement('div');
        managerDiv.id = 'blacklist-manager';
        managerDiv.className = 'block block--padding block--margin';
        managerDiv.innerHTML = `
            <div class="block__content">
                <div class="text mb-2 text--inline text--bold">🚫 Iwara ID 黑名单管理面板</div>
                <button id="toggle-blacklist-view-btn" type="button" style="padding: 5px 10px; cursor: pointer; margin-bottom: 10px; width: 100%; text-align: left;"></button>
                <div id="blacklist-manager-list" style="display: none; margin-bottom: 15px; max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 5px; border-radius: 4px;"></div>
                <div style="margin-bottom: 15px;">
                    <button id="export-blacklist-btn" type="button" style="padding: 5px 10px; cursor: pointer;">导出列表</button>
                    <textarea id="blacklist-io-area" placeholder="导出数据将显示在此处,或在此处粘贴数据以导入" style="width: 100%; min-height: 60px; margin-top: 5px; font-size: 12px; padding: 5px; box-sizing: border-box;"></textarea>
                </div>
                <button id="import-blacklist-btn" type="button" style="padding: 5px 10px; cursor: pointer; background-color: #4CAF50; color: white; border: none; border-radius: 4px;">导入列表 (将覆盖现有列表并刷新)</button>
            </div>
        `;

        targetContainer.parentNode.insertBefore(managerDiv, targetContainer.nextSibling);

        const listDiv = managerDiv.querySelector('#blacklist-manager-list');
        const ioArea = managerDiv.querySelector('#blacklist-io-area');
        const exportBtn = managerDiv.querySelector('#export-blacklist-btn');
        const importBtn = managerDiv.querySelector('#import-blacklist-btn');
        const toggleBtn = managerDiv.querySelector('#toggle-blacklist-view-btn');

        updateToggleBtnText(toggleBtn, listDiv);

        toggleBtn.addEventListener('click', () => {
            const isHidden = listDiv.style.display === 'none';
            listDiv.style.display = isHidden ? 'block' : 'none';
            if (isHidden) {
                renderBlacklistDisplay(listDiv);
            }
            updateToggleBtnText(toggleBtn, listDiv);
        });

        exportBtn.addEventListener('click', () => {
            const blacklist = getBlacklist();
            ioArea.value = JSON.stringify(Array.from(blacklist));
            ioArea.select();
            alert(`已生成 ${blacklist.size} 个ID,请手动复制文本框中的内容。`);
        });

        importBtn.addEventListener('click', () => {
            const data = ioArea.value.trim();
            if (!data) return alert('导入数据不能为空!');
            try {
                const parsed = JSON.parse(data);
                if (!Array.isArray(parsed)) throw new Error('数据格式不是一个有效的数组。');
                const newBlacklist = new Set(parsed.filter(item => typeof item === 'string'));
                saveBlacklist(newBlacklist);
                alert(`成功导入 ${newBlacklist.size} 个ID!页面即将刷新以应用新的黑名单。`);
                window.location.reload();
            } catch (e) {
                alert('导入失败!请检查数据是否为之前导出的正确JSON格式。\n错误信息: ' + e.message);
            }
        });

        listDiv.addEventListener('click', (e) => {
            if (e.target.classList.contains('remove-id-btn')) {
                const idToRemove = e.target.dataset.id;
                if (idToRemove && confirm(`确定要将ID: ${idToRemove} 从黑名单中移除吗?`)) {
                    let blacklist = getBlacklist();
                    blacklist.delete(idToRemove);
                    saveBlacklist(blacklist);
                    renderBlacklistDisplay(listDiv);
                    updateToggleBtnText(toggleBtn, listDiv);
                }
            }
        });
    };

    const observer = new MutationObserver(() => {
        hideBlacklistedWorks();
        hideBlacklistedComments();
        addBlockButton();
        createManagementUI();
    });

    observer.observe(document.documentElement, {
        childList: true,
        subtree: true
    });
})();