Greasy Fork

Greasy Fork is available in English.

Masiro: Blurs NSFW Covers

Blurs the covers of NSFW novels on Masiro.

当前为 2023-12-27 提交的版本,查看 最新版本

// ==UserScript==
// @name               Masiro: Blurs NSFW Covers
// @name:zh-TW         真白萌:模糊 R17 封面
// @description        Blurs the covers of NSFW novels on Masiro.
// @description:zh-TW  模糊真白萌 R17 小說的封面。
// @icon               https://icons.duckduckgo.com/ip3/masiro.me.ico
// @author             Jason Kwok
// @namespace          https://jasonhk.dev/
// @version            1.2.3
// @license            MIT
// @match              https://masiro.me/admin
// @match              https://masiro.me/admin/
// @match              https://masiro.me/admin/novels
// @match              https://masiro.me/admin/novelIndex
// @run-at             document-idle
// @grant              GM.getValue
// @grant              GM.setValue
// @grant              GM.addStyle
// @require            https://update.greasyfork.icu/scripts/482311/1296481/queue.js
// @supportURL         http://greasyfork.icu/scripts/471783/feedback
// ==/UserScript==

GM.addStyle(`
    .updateCards > a.nsfw .updateImg, .layui-card.nsfw .n-img
    {
        filter: blur(7.5px);
        transition: 0.3s;
    }

    .updateCards > a.nsfw:hover .updateImg, .updateCards > a.nsfw:focus-within .updateImg,
    .layui-card.nsfw:hover .n-img, .layui-card.nsfw:focus-within .n-img
    {
        filter: blur(0px);
    }
`);

const pathname = location.pathname;
if ((pathname === "/admin") || (pathname === "/admin/"))
{
    const queue = new Queue({ autostart: true, concurrency: 4 });

    const observer = new MutationObserver((records) =>
    {
        for (const record of records)
        {
            if (record.target.classList.contains("updateCards"))
            {
                for (const node of record.addedNodes)
                {
                    queue.push(async () =>
                    {
                        if (await isNsfw(node.href))
                        {
                            node.classList.add("nsfw");
                        }
                    });
                }
            }
        }
    });

    observer.observe(document.querySelector(".fl"), { subtree: true, childList: true });

    async function isNsfw(url)
    {
        const novelId = new URL(url).searchParams.get("novel_id");
        {
            const isNsfw = await GM.getValue(novelId);
            if (typeof isNsfw === "boolean") { return isNsfw; }
        }

        try
        {
            const response = await fetch(url);
            if (response.status === 200)
            {
                const html = await response.text();
                const parser = new DOMParser();
                const page = parser.parseFromString(html, "text/html");

                const isNsfw = Array.prototype.map.call(page.querySelectorAll(".tags .label"), (element) => element.innerText)
                                              .includes("R17");

                GM.setValue(novelId, isNsfw);
                return isNsfw;
            }
            else if (response.status === 429)
            {
                const resetTime = Number.parseInt(response.headers.get("x-ratelimit-reset"));
                return new Promise((reslove) =>
                {
                    setTimeout(() => reslove(isNsfw(url)), (resetTime - Math.ceil(Date.now() / 1000) + 10) * 1000);
                });
            }
        }
        catch (e)
        {
            console.error(e);
        }

        return false;
    }
}
else
{
    const observer = new MutationObserver((records) =>
    {
        for (const record of records)
        {
            for (const node of record.addedNodes)
            {
                if ((node instanceof HTMLElement) && node.classList.contains("layui-card"))
                {
                    const isNsfw = Array.prototype.map.call(node.querySelectorAll(".tags > .tag"), (element) => element.innerText).includes("R17");
                    if (isNsfw) { node.classList.add("nsfw"); }

                    const url = new URL(node.querySelector(".glass + a").href);
                    GM.setValue(url.searchParams.get("novel_id"), isNsfw);
                }
            }
        }
    });

    observer.observe(document.querySelector(".n-leg"), { childList: true });
}