// ==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 https://greasyfork.org/users/1354622 // @downloadURL none // ==/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(); })();