ESJ Zone:修復無法點擊的章節

修復因作者設定錯誤或網頁設計問題等原因而無法點擊的章節連結。

目前為 2024-02-19 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name               ESJ Zone: Repair Non-clickable Chapters
// @name:zh-TW         ESJ Zone:修復無法點擊的章節
// @name:zh-CN         ESJ Zone:修复无法点击的章节
// @description        Repair chapter links that were not-clickable due to for example, author misconfigured or by-designed.
// @description:zh-TW  修復因作者設定錯誤或網頁設計問題等原因而無法點擊的章節連結。
// @description:zh-CN  修复因作者设定错误或网页设计问题等原因而无法点击的章节链接。
// @icon               https://icons.duckduckgo.com/ip3/www.esjzone.cc.ico
// @author             Jason Kwok
// @namespace          https://jasonhk.dev/
// @version            1.0.3
// @license            MIT
// @match              https://www.esjzone.cc/
// @match              https://www.esjzone.cc/update
// @match              https://www.esjzone.cc/update/
// @match              https://www.esjzone.cc/list
// @match              https://www.esjzone.cc/list/
// @match              https://www.esjzone.cc/list-*
// @match              https://www.esjzone.cc/tags/*
// @match              https://www.esjzone.cc/tags-*
// @match              https://www.esjzone.cc/my/favorite
// @match              https://www.esjzone.cc/my/favorite/*
// @match              https://www.esjzone.me/
// @match              https://www.esjzone.me/update
// @match              https://www.esjzone.me/update/
// @match              https://www.esjzone.me/list
// @match              https://www.esjzone.me/list/
// @match              https://www.esjzone.me/list-*
// @match              https://www.esjzone.me/tags/*
// @match              https://www.esjzone.me/tags-*
// @match              https://www.esjzone.me/my/favorite
// @match              https://www.esjzone.me/my/favorite/*
// @run-at             document-end
// @grant              none
// @require            https://update.greasyfork.org/scripts/482311/1296481/queue.js
// @supportURL         https://greasyfork.org/scripts/487645/feedback
// ==/UserScript==

let translateText;
if (GM.info.scriptHandler === "Greasemonkey")
{
    translateText = window.eval("getCookie(targetEncodingCookie)") ? window.eval("translateText") : ((text) => text);
}
else
{
    translateText = getCookie(targetEncodingCookie) ? window.translateText : ((text) => (text));
}

async function findChapterUrl(novelUrl, chapterName)
{
    const response = await fetch(novelUrl);
    if (response.status === 200)
    {
        const html = await response.text();
        const parser = new DOMParser();
        const page = parser.parseFromString(html, "text/html");

        return Array.from(page.querySelectorAll("#chapterList a"))
                    .reverse()
                    .find((chapter) => (translateText(chapter.innerText.trim()) === chapterName))?.href ?? null;
    }
}

let repaired = 0;

const queue = new Queue({ autostart: true, concurrency: 4 });
queue.addEventListener("error", (event) => console.error(event.detail.error));
queue.addEventListener("end", () => console.info(`Repaired ${repaired} URL(s).`));

const pathname = location.pathname;
if (pathname === "/my/favorite" || pathname.startsWith("/my/favorite/"))
{
    const novels = document.querySelectorAll(".product-item");
    for (const novel of novels)
    {
        const chapterWrapper = novel.querySelector(".book-ep div:nth-child(2)");
        const chapter = chapterWrapper.childNodes[0]?.splitText(5);
        if (chapter instanceof Text)
        {
            queue.push(async () =>
            {
                const url = await findChapterUrl(novel.querySelector(".product-title a").href, chapter.data);
                if (url)
                {
                    const link = document.createElement("a");
                    link.href = url;

                    link.append(chapter);
                    chapterWrapper.append(link);

                    repaired++;
                }
            });
        }
    }
}
else
{
    const novels = document.querySelectorAll(".card");
    for (const novel of novels)
    {
        const chapterWrapper = novel.querySelector(".card-ep");
        const chapter = chapterWrapper.childNodes[0];
        if (chapter instanceof Text)
        {
            queue.push(async () =>
            {
                const url = await findChapterUrl(novel.querySelector(".card-title a").href, chapter.data);
                if (url)
                {
                    const link = document.createElement("a");
                    link.href = url;

                    link.append(chapter);
                    chapterWrapper.append(link);

                    repaired++;
                }
            });
        }
    }
}