Bangumi shared book collections

共読 at Bangumi

当前为 2022-08-08 提交的版本,查看 最新版本

// ==UserScript==
// @name         Bangumi shared book collections
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  共読 at Bangumi
// @description  Ref: https://github.com/bangumi/scripts/tree/b0113743743dba35accb28e9b7b9da8cbbea6952/yonjar#%E7%94%A8%E6%88%B7%E8%AF%A6%E6%83%85%E7%88%AC%E5%8F%96
// @license      MIT
// @author       txfs19260817
// @require      https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.18.2/babel.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js
// @match        http*://*.bangumi.tv/
// @match        http*://*.bgm.tv/
// @match        http*://*.chii.in/
// @icon         https://bangumi.tv/img/favicon.ico
// ==/UserScript==

const parseTimestamp = (s) => {
    if (!s.includes("ago")) {
        return new Date(s);
    }
    const now = new Date();
    const d = s.match(/(\d+)d/i)?.[1] || 0;
    const h = s.match(/(\d+)h/i)?.[1] || 0;
    const m = s.match(/(\d+)m/i)?.[1] || 0;
    now.setDate(now.getDate() - parseInt(d));
    now.setHours(now.getHours() - parseInt(h));
    now.setMinutes(now.getMinutes() - parseInt(m));
    return now;
}

const getUID = () => {
    return document
          .querySelector("#headerNeue2 > div > div.idBadgerNeue > a")
          .href.split("user/")[1];
}

const fetchHTMLDocument = (url, fetchMethod = "GET") => {
  const fetchInit = {
    method: fetchMethod,
    cache: "default",
    credentials: "include"
  };

  return fetch(new Request(url, fetchInit)).then(
    (r) => r.text(),
    (err) => Promise.reject(err)
  ).then((t) => {
    const parser = new DOMParser();
    return parser.parseFromString(t, "text/html");
  });
};

const fetchComments = async (uid) => {
    const url = `${location.origin}/book/list/${uid}/collect`;
    const page1 = await fetchHTMLDocument(url);
    const maxPageNum = page1.getElementsByClassName('page_inner')[0].childElementCount - 1;
    const pageURLs = Array.from({length: maxPageNum}, (_, i) => i + 1).map((i) => `${url}?page=${i}`)
    pageURLs.shift(); // [2, ..., maxPageNum]
    const pages = await Promise.all(pageURLs.map((u) => fetchHTMLDocument(u)));
    pages.unshift(page1);

    const subjectUrls = pages
        .flatMap((page) => Array.from(page.getElementById("browserItemList").children).map((c) => c.firstElementChild.href + "/comments"));
    const subjectCovers = pages
        .flatMap((page) => Array.from(page.getElementById("browserItemList").children).map((c) => c.getElementsByTagName('img')[0].src));
    const commentDOMs = await Promise.all(subjectUrls.map((u) => fetchHTMLDocument(u)));
    const commentElements = commentDOMs.map((p) => Array.from(p.getElementsByClassName("text")));
    const subjectTitles = pages
        .flatMap((page) => Array.from(page.getElementById("browserItemList").children).map((c) => c.getElementsByTagName('h3')[0].textContent.trim()));
    const data = commentElements.flatMap((cs, i) => {
        return cs.map((c) => {
            return {
                subjectUrl: subjectUrls[i],
                subjectTitle: subjectTitles[i],
                subjectCover: subjectCovers[i],
                userUrl: c.firstElementChild.href,
                username: c.firstElementChild.text,
                date: parseTimestamp(c.getElementsByTagName('small')[0].textContent.slice(2)),
                comment: c.getElementsByTagName('p')[0].textContent,
            }
        }
    )});
    data.sort((a,b)=>b.date-a.date);
    return data
}

const createTabAnchor = () => {
    const li = document.createElement("li");
    const a = document.createElement("a");
    a.text = '共读';
    a.style.cursor = 'pointer';
    li.appendChild(a)
    document.getElementById('timelineTabs').appendChild(li);
    return a;
}

const commentDataToTLList = (data) => {
    const ul = document.createElement("ul");
    const lis = data.map((d) => {
        const li = document.createElement("li");
        li.classList.add("clearit");
        li.classList.add("tml_item");
        // avatar
        const avatar = document.createElement("span");
        const userAvatarAnchor = document.createElement("a");
        const userAvatarSpan = document.createElement("span");
        userAvatarSpan.classList.add("avatarNeue");
        userAvatarSpan.classList.add("avatarReSize40");
        userAvatarSpan.classList.add("ll");
        userAvatarSpan.style.backgroundImage = 'url("//lain.bgm.tv/pic/user/l/icon.jpg")'
        userAvatarAnchor.href = d.userUrl;
        userAvatarAnchor.appendChild(userAvatarSpan);
        avatar.classList.add("avatar");
        avatar.appendChild(userAvatarAnchor);
        li.appendChild(avatar);
        // info
        const info = document.createElement("span");
        info.classList.add("clearit");
        info.classList.add("info");
        // info - cover
        const coverAnchor = document.createElement("a");
        const coverImg = document.createElement("img");
        coverImg.classList.add("rr");
        coverImg.src = d.subjectCover;
        coverImg.height = "48";
        coverImg.width = "48";
        coverAnchor.appendChild(coverImg);
        info.appendChild(coverAnchor);
        // info - username
        const userAnchor = document.createElement("a");
        userAnchor.href = d.userUrl;
        userAnchor.textContent = d.username;
        userAnchor.classList.add("l");
        info.appendChild(userAnchor);
        const connector = document.createElement("span");
        connector.textContent = " 读过 ";
        info.appendChild(connector);
        // info - subject
        const subjectAnchor = document.createElement("a");
        subjectAnchor.href = d.subjectUrl;
        subjectAnchor.textContent = d.subjectTitle;
        subjectAnchor.classList.add("l");
        info.appendChild(subjectAnchor);
        // info - comment
        const collectInfo = document.createElement("div");
        collectInfo.classList.add("collectInfo");
        const quoteDiv = document.createElement("div");
        quoteDiv.classList.add("quote");
        const quoteQ = document.createElement("q");
        quoteQ.textContent = d.comment;
        quoteDiv.appendChild(quoteQ);
        collectInfo.appendChild(quoteDiv);
        info.appendChild(collectInfo);
        // info - date
        const dateP = document.createElement("p");
        dateP.classList.add("date");
        dateP.textContent = d.date.toLocaleString();
        info.appendChild(dateP);
        // info done
        li.appendChild(info);
        return li
    });
    lis.forEach((l) => {ul.appendChild(l)});
    return ul;
}

var inline_src = `
    // Your code here...
    const uid = getUID();
    fetchComments(uid)
        .then((r) => {
            const tabAnchor = createTabAnchor();
            const tl = document.getElementById("timeline");
            // TODO: pagination?
            tabAnchor.onclick = function() {
                tabAnchor.classList.add("focus");
                tl.replaceChildren(commentDataToTLList(r.slice(0, 100)));
            };
        });
`;
var c = Babel.transform(inline_src, { presets: [ "es2015", "es2016" ] });
eval(c.code);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址