Greasy Fork

Greasy Fork is available in English.

Bangumi 隐藏NSFW条目

隐藏NSFW条目

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name Bangumi 隐藏NSFW条目
// @version 3.0
// @description 隐藏NSFW条目
// @author 墨云
// @match https://bangumi.tv/*
// @match https://chii.in/*
// @match https://bgm.tv/*
// @grant none
// @namespace http://greasyfork.icu/users/1354622
// ==/UserScript==
 
(function() {
    'use strict';
 
    const SETTING_KEY = 'bangumi_hide_nsfw_mode';
 
    // 缓存有效时长
    const CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000;

    // 检查条目是否为NSFW
    async function isSubjectChecked(subjectId) {
        const cacheKey = `nsfw_cache_${subjectId}`;
        const cachedData = localStorage.getItem(cacheKey);
        
        if (cachedData) {
            try {
                const data = JSON.parse(cachedData);
                // 检查缓存是否过期
                if (Date.now() < data.timestamp + CACHE_EXPIRY) {
                    return data.value;
                }
            } catch (e) {
                // 解析失败,忽略旧缓存
                localStorage.removeItem(cacheKey);
            }
        }

        try {
            const response = await fetch(`/subject/${subjectId}/edit_detail`);
            const text = await response.text();
            const isChecked = text.includes('checked="checked"');
            
            // 存入缓存
            const dataToCache = {
                value: isChecked,
                timestamp: Date.now()
            };
            localStorage.setItem(cacheKey, JSON.stringify(dataToCache));
            return isChecked;
        } catch (error) {
            console.error('Failed to fetch subject detail:', error);
            // 出错时假定非NSFW,并存入缓存
            const dataToCache = {
                value: false,
                timestamp: Date.now()
            };
            localStorage.setItem(cacheKey, JSON.stringify(dataToCache));
            return false;
        }
    }
 
    // 根据设置模式来隐藏或显示条目
    async function applyMode(mode) {
        const listItems = document.querySelectorAll('li > a[href^="/subject/"]');
        const promises = [];

        // 并行处理所有条目
        for (const item of listItems) {
            const subjectId = item.getAttribute('href').split('/')[2];
            promises.push(isSubjectChecked(subjectId).then(isChecked => {
                if (isChecked) {
                    item.parentElement.style.display = (mode === 'hide') ? 'none' : '';
                }
            }));
        }

        await Promise.all(promises);
    }
 
    // 添加设置面板
    function addNSFWSetting() {
        chiiLib.ukagaka.addGeneralConfig({
            title: 'NSFW',
            name: 'nsfwMode',
            type: 'radio',
            defaultValue: 'off', 
            getCurrentValue: function() { return $.cookie(SETTING_KEY) || 'off'; },
            onChange: function(value) {
                $.cookie(SETTING_KEY, value, {expires: 30, path: '/'});
                applyMode(value);
            },
            options: [
                { value: 'off', label: '关闭' },
                { value: 'hide', label: '隐藏' }
            ]
        });
    }
 
    // 初始化
    async function init() {

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', addNSFWSetting);
        } else {
            addNSFWSetting();
        }
 
        const currentMode = $.cookie(SETTING_KEY) || 'off';
        await applyMode(currentMode);

        const observer = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === 1 && node.matches('li > a[href^="/subject/"]')) {
                            applyMode($.cookie(SETTING_KEY) || 'off');
                        }
                    });
                }
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }
 
    init();
})();