Fanfiction.net: Link to Last Chapter

Add link to last chapter to alert/favorites page of Fanfiction.net.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Fanfiction.net: Link to Last Chapter
// @namespace    https://greasyfork.org/en/users/163551-vannius
// @version      1.4
// @license      MIT
// @description  Add link to last chapter to alert/favorites page of Fanfiction.net.
// @author       Vannius
// @match        https://www.fanfiction.net/alert/story.php*
// @match        https://www.fanfiction.net/favorites/story.php*
// @connect      fanfiction.net
// @icon         https://www.google.com/s2/favicons?sz=64&domain=fanfiction.net
// @grant        GM_openInTab
// ==/UserScript==

(function () {
    // Config
    // Open last chapter in new tab.
    const OPEN_IN_NEW_TAB = true;

    // Functions
    // Make and return a link button to last chapter.
    function makeLastLink (url) {
        const lastLink = document.createElement('a');

        // Add click event
        lastLink.addEventListener('click', function () {
            // Get url of last chapter
            fetch(url, { method: 'GET', mode: 'same-origin', cache: 'default' })
                .then(response => response.text())
                .then(body => {
                    const doc = document.implementation.createHTMLDocument('myBody');
                    doc.documentElement.innerHTML = body;
                    const chapSelectTag = doc.getElementById('chap_select');

                    const baseUrl = url.split('/').slice(0, 5).join('/');
                    const title = url.split('/')[6];
                    // If chapSelectTag === null, story has only one chapter.
                    const lastChpater = chapSelectTag ? chapSelectTag[chapSelectTag.length - 1].value : 1;
                    const lastHref = [baseUrl, lastChpater, title].join('/');

                    // Move page
                    if (OPEN_IN_NEW_TAB) {
                        GM_openInTab(lastHref);
                    } else {
                        window.location.href = lastHref;
                    }
                }).catch(error => console.log(error));
        });
        return lastLink;
    }

    // Main
    // Scrape alert or favorite page
    const storyTableTag = document.getElementById('gui_table1i').children[1];
    const trTags = storyTableTag.getElementsByTagName('tr');
    const storyTags = Array.from(trTags)
        .filter(tr => tr.children.length === 6)
        .map(tr => tr.firstElementChild.firstElementChild);

    for (let storyTag of storyTags) {
        // Make link button to last chapter.
        const lastLink = makeLastLink(storyTag.href);
        lastLink.title = "Click Event: open last chapter";
        lastLink.appendChild(document.createTextNode('L'));

        // Add link button to last chapter right after title of story and adjust placement.
        const fragment = document.createDocumentFragment();
        fragment.appendChild(document.createTextNode(' '));
        fragment.appendChild(lastLink);
        storyTag.parentElement.appendChild(fragment);
    }
})();