CC98 Tools - blablabla

Small tools for CC98.

// ==UserScript==
// @name         CC98 Tools - blablabla
// @version      1.0.1
// @description  Small tools for CC98.
// @icon         https://www.cc98.org/static/98icon.ico

// @author       ml98
// @namespace    https://www.cc98.org/user/name/ml98
// @license      MIT

// @match        https://www.cc98.org/*
// @match        https://www-cc98-org-s.webvpn.zju.edu.cn:8001/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        unsafeWindow
// @run-at       document-idle
// ==/UserScript==

/* eslint-env jquery */

main();

function main() {
    /* 隐藏用户名、头像 */
    hideUserName();
    /* 翻页快捷键 Ctrl+</> */
    addPageUpDownHotkey();
    /* 新帖显示回复数 */
    addTopicReplyCount();
    /* 新标签页打开帖子 */
    openTopicInNewTab();
    /* 修复WebVPN站外链接 */
    escapeFromWebVPN();
    /* 解决文件下载问题 */
    fixMixContent();
    /* 隐藏所有图片 */
    hideAllImages();
    /* 点击楼层数折叠楼层 */
    foldFloor();
    /* 自动提醒签到 */
    autoSignin();
}

function hideUserName() {
    const genRanHex = (size) =>
        [...Array(size)]
            .map(() => Math.floor(Math.random() * 16).toString(16))
            .join("")
            .toUpperCase();
    const userName = "匿名" + genRanHex(6);
    const userImgSrc = "/static/images/心灵头像.gif";
    GM_addStyle(`
        .topBarUserName {
            visibility: hidden;
        }
        .topBarUserName:after {
            visibility: visible;
            position: absolute;
            content: "${userName}";
        }
        .topBarUserImg img {
            content: url(${userImgSrc});
            /* opacity: 0; */
        }
    `);
}

function addPageUpDownHotkey() {
    $(document).on("keydown", function (e) {
        if (document.URL.includes("https://www.cc98.org/topic/")) {
            const p = document.querySelector(".page-link.active");
            if (e.ctrlKey) {
                switch (e.key) {
                    case "ArrowLeft":
                        p.parentNode.previousSibling?.children[0].click();
                        break;
                    case "ArrowRight":
                        p.parentNode.nextSibling?.children[0].click();
                        break;
                }
            }
        }
    });
}

function React(dom) {
    const key = Object.keys(dom).find((key) =>
        key.startsWith("__reactInternalInstance$")
    );
    const instance = dom[key];
    return (
        instance?._debugOwner?.stateNode ||
        instance?.return?.stateNode ||
        instance?._currentElement?._owner?._instance ||
        null
    );
}

function addTopicReplyCount() {
    setInterval(() => {
        if (
            document.URL.includes("https://www.cc98.org/newTopics") ||
            document.URL.includes("https://www.cc98.org/search") ||
            document.URL.includes("https://www.cc98.org/focus")
        ) {
            $(".focus-topic-info").each(function () {
                let replyCount = React(this.parentNode.parentNode).props
                    .replyCount;
                let hit = $(this).find(".fa-eye").parent()[0];
                let reply = $(this).find(".fa-reply").parent()[0];
                if (reply && hit.nextSibling == reply) {
                    if (reply.childNodes[1].textContent !== ` ${replyCount}`) {
                        reply.childNodes[1].textContent = ` ${replyCount}`;
                    }
                } else {
                    reply && reply.remove();
                    $(hit).after(
                        `<div><i class="fa fa-reply"></i> ${replyCount}</div>`
                    );
                }
            });
        }
    }, 1000);
}

function openTopicInNewTab() {
    $(document).on(
        "click",
        ".board-postItem-title a, .user-post-content a",
        function (e) {
            if (e.target.href.includes("https://www.cc98.org/topic/")) {
                e.preventDefault();
                unsafeWindow.open(e.target.href);
            }
        }
    );
}

/* global revertUrl */
function escapeFromWebVPN() {
    $(document).on("click", "a", function (e) {
        if (
            typeof revertUrl !== "undefined" &&
            this.href &&
            !new URL(this.href).host.includes("cc98.org")
        ) {
            e.preventDefault();
            open(revertUrl(this.href));
            return false;
        }
    });
}

function fixMixContent() {
    $(document).on("click", "a.download-file", function (e) {
        if (new URL(this.href).host === "file.cc98.org") {
            e.preventDefault();
            unsafeWindow.open(this.href.replace("http:", ""));
            return false;
        }
    });
}

function waitForElement(
    selector,
    callback,
    once = false,
    startNode = document
) {
    const uid = '_' + Math.random().toString().slice(2);
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            for (const node of mutation.addedNodes) {
                if (node.nodeType === 1) {
                    if (node.matches(selector)) {
                        callback(node);
                        if (once) {
                            observer.disconnect();
                            return;
                        }
                    } else {
                        const child = node.querySelector(
                            selector + `:not([${uid}])`
                        );
                        if (child) {
                            child.setAttribute(uid, "");
                            callback(child);
                            if (once) {
                                observer.disconnect();
                                return;
                            }
                        }
                    }
                }
            }
        }
    });
    observer.observe(startNode, {
        childList: true,
        subtree: true,
    });
}

function hideAllImages() {
    function hide() {
        $(`.reply-content img,.lazyload-placeholder`)
            .parent()
            .each((_, e) => React(e)?.toggleIsShowed?.(false));
    }
    waitForElement("#essayProp", function () {
        const button1 = $(`#essayProp > div.followTopic[style="width: 6rem;"]`);
        const button2 = $(
            `<div class="followTopic" style="width: 6rem;">隐藏所有图片</div>`
        );
        button1.after(button2);
        button2.on("click", hide);
    });
}

function foldFloor() {
    GM_addStyle(`
        .substance.fold {
            max-height: 400px;
            overflow-y: auto;
            position: relative;
        }
        .substance.fold > .markdown-container {
            overflow-y: auto;
        }
        .reply-floor {
            cursor: pointer;
        }
    `);
    $(document.body).on("click", ".reply-floor", function () {
        $(this).parents(".reply").find(".substance").toggleClass("fold");
    });
}

function autoSignin() {
    const today = new Date().getDate();
    if (GM_getValue("signin_date") !== today) {
        GM_setValue("signin_date", today);
        unsafeWindow.open("/signin");
        unsafeWindow.open("http://www.nexushd.org/signin.php");
        // unsafeWindow.open("https://glados.rocks/console/checkin");
    }
    /*
    if (document.URL.includes("https://www.cc98.org/signin")) {
        let id = setInterval(() => {
            $('.sign-in #post-topic-button').click().length
            && clearInterval(id);
        }, 5000);
    }
    */
}