知乎热榜首页显示回答数、关注数、浏览数、创建者、创建时间

在知乎的热榜页中,显示每个问题的回答数、关注数、浏览数、创建者、创建时间。

// ==UserScript==
// @name         知乎热榜首页显示回答数、关注数、浏览数、创建者、创建时间
// @namespace    http://tampermonkey.net/
// @version      2024-03-05
// @description  在知乎的热榜页中,显示每个问题的回答数、关注数、浏览数、创建者、创建时间。
// @author       Fat Cabbage
// @license      MIT
// @match        https://www.zhihu.com/hot
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://code.jquery.com/jquery-3.5.1.min.js
// ==/UserScript==
/* globals jQuery, $, waitForKeyElements */

let question_status_list = {};

(function () {
    'use strict';

    let wrapper_node_list = document.getElementsByClassName('HotItem-metrics');
    let links_list = document.getElementsByClassName('HotItem-content');

    (async () => {
        for (let i = 0; i < links_list.length; i++) {
            let links = links_list[i].getElementsByTagName('a')
            let href = links[0].href;

            if (/question/.test(href)) {
                let log_href = `${href}/log`

                let match = href.match(/.*\/question\/(\d+)/)
                let id = match ? match[1] : -1;

                if (question_status_list[id] == null) {
                    question_status_list[id] = {};
                }
                question_status_list[id].wrapper_node = wrapper_node_list[i];
                question_status_list[id].updated = true;

                let config = GM_getValue(id, {});

                if (config.last_updated != null) {
                    let time_diff = new Date() - new Date(config.last_updated);
                    time_diff /= 1000 * 60;

                    if (config.followers == null || config.views == null || config.answers == null || time_diff > 5) {
                        console.log("time_diff", time_diff);
                        console.log("知乎热榜首页显示回答数 case1");
                        await fetchDataRow1(href, id);
                    }
                } else {
                    console.log("知乎热榜首页显示回答数 case2");
                    await fetchDataRow1(href, id);
                }

                if (config.author == null || config.time == null) {
                    await fetchDataRow2(log_href, id);
                }

                update_interface_value();
            }
        }
    })();
})();

function fetchDataRow1(href, id) {
    return new Promise(function (resolve) {
        $.get(href, function (res) {
            let dom = new DOMParser().parseFromString(res, 'text/html');
            let values = dom.getElementsByClassName('NumberBoard-itemValue');

            let followers_num = parseInt(values[0].outerText.replaceAll(',', ''));
            let views_num = parseInt(values[1].outerText.replaceAll(',', ''));

            values = dom.getElementsByClassName('List-headerText');
            let answer_num = values[0].outerText;
            answer_num = answer_num.replaceAll(' 个回答', '').replaceAll(',', '')
            answer_num = parseInt(answer_num);

            let config = GM_getValue(id, {});

            config.followers = followers_num;
            config.views = views_num;
            config.answers = answer_num;
            config.last_updated = new Date().toISOString();

            GM_setValue(id, config);

            if (question_status_list[id] == null) {
                question_status_list[id] = {};
            }

            question_status_list[id].updated = true;

            update_interface_value();

            resolve(res);
        });
    });
}

function fetchDataRow2(href, id) {
    return new Promise(function (resolve) {
        $.get(href, function (res) {
            let dom = new DOMParser().parseFromString(res, 'text/html');
            let log_list = dom.getElementsByClassName('zm-item');
            let initial_log = log_list[log_list.length - 1];

            let child1 = initial_log.children[0];
            let author = child1.outerText;
            author = author.replaceAll('添加了问题', '').replaceAll('\n', '');

            let child2 = initial_log.querySelector('time');
            let time = child2.outerText;

            let config = GM_getValue(id, {});

            config.author = author;
            config.time = time;

            GM_setValue(id, config);

            if (question_status_list[id] == null) {
                question_status_list[id] = {};
            }

            question_status_list[id].updated = true;

            update_interface_value();

            resolve(res);
        });
    });
}

function update_interface_value() {
    for (let id in question_status_list) {

        let node = question_status_list[id].wrapper_node;
        let updated = question_status_list[id].updated;

        let config = GM_getValue(id);
        let followers_num = config.followers;
        let views_num = config.views;
        let answer_num = config.answers;
        let author = config.author;
        let created_time = config.time;

        let last_updated = '';
        if (config.last_updated != null) {
            let time_diff = new Date() - new Date(config.last_updated);
            time_diff /= 1000 * 60;

            if (time_diff > 1) {
                time_diff = Math.round(time_diff);
                last_updated = `(${time_diff}分钟前更新)`;
            } else {
                last_updated = "(刚刚更新)";
            }
        }


        if (!updated) {
            continue;
        }

        node = node.childNodes;

        let view_str;
        if (views_num < 1e4) {
            view_str = `${views_num} `;
        } else if (views_num < 1e8) {
            view_str = `${Math.floor(views_num / 1e4)} 万`;
        } else {
            view_str = `${(views_num / 1e8).toFixed(1)} 亿`;
        }

        let match = node[1].nodeValue.match(/\d+.*?热度/);
        let hot = match ? match[0] : -1;

        let row1_text = `${hot} - ${answer_num} 回答 - ${followers_num} 关注 - ${view_str}浏览${last_updated}`
        let row1_node = document.createTextNode(row1_text);

        for (let i = 1; i < node.length - 1; i++) {
            node[i].remove();
        }
        node[0].parentNode.style.bottom = '5px'
        node[0].parentNode.style.zIndex = '1'
        node[0].parentNode.insertBefore(row1_node, node[1])

        if (author != null) {
            let br = document.createElement('br');
            let row2_text = `创建 ${author} | ${created_time}`
            let row2_node = document.createTextNode(row2_text);

            node[0].parentNode.insertBefore(br, node[2]);
            node[0].parentNode.insertBefore(row2_node, node[3])
        }

        config.updated = false;
    }
}