您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在蜜柑计划首页显示 Bangumi 评分及链接。
当前为
// ==UserScript== // @name mikananiBgmScore // @name:zh-CN 在蜜柑计划首页显示 Bangumi 评分及链接。 // @namespace https://github.com/kjtsune/UserScripts // @version 0.1 // @description 在蜜柑计划首页显示 Bangumi 评分及链接。 // @author kjtsune // @match https://mikanani.me/ // @icon https://www.google.com/s2/favicons?sz=64&domain=mikanani.me // @grant none // ==/UserScript== 'use strict'; let config = { logLevel: 2 }; let logger = { error: function (...args) { if (config.logLevel >= 1) console.log("%cerror", "color: yellow; font-style: italic; background-color: blue;", args); }, info: function (...args) { if (config.logLevel >= 2) console.log("%cinfo", "color: yellow; font-style: italic; background-color: blue;", args); }, debug: function (...args) { if (config.logLevel >= 3) console.log("%cdebug", "color: yellow; font-style: italic; background-color: blue;", args); }, } async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function getJSON(url) { try { const response = await fetch(url); logger.info(`fetch ${url}`) if (response.status >= 200 && response.status < 400) return await response.json(); console.error(`Error fetching ${url}:`, response.status, response.statusText, await response.text()); } catch (e) { console.error(`Error fetching ${url}:`, e); } } async function getBgmJson(bgmId) { let url = `https://api.bgm.tv/v0/subjects/${bgmId}` return await getJSON(url) } function multiTimesSeletor(storage = null, seletorAll = false, ...cssSeletor) { const seletor = cssSeletor[0] const restSeletor = cssSeletor.slice(1) if (!seletor) return storage; function queryForArray(query, array) { let result = []; for (let index = 0; index < array.length; index++) { const element = array[index]; let res = element.querySelectorAll(query); if (!res) logger.error("not result", query, array); result.push(...res); } return result } if (seletorAll) { storage = storage || [document] let res = queryForArray(seletor, storage); if (res) storage = res; storage && logger.debug('storage', storage.length, seletor, restSeletor); if (!restSeletor) { return storage; } else { return multiTimesSeletor(storage, true, ...restSeletor); } } else { storage = storage || document; const lastRes = storage; storage = storage.querySelector(seletor); storage && logger.debug('storage', storage, seletor); if (!storage) logger.error("not result", seletor, lastRes); if (!restSeletor) { return storage; } else { return multiTimesSeletor(storage, false, ...restSeletor); } } } async function myFetch(url, selector = null, selectAll = false) { let response = await fetch(url); let text = await response.text(); const parser = new DOMParser(); const htmlDocument = parser.parseFromString(text, "text/html"); const element = htmlDocument.documentElement; if (!selector) return element; if (selectAll) { return element.querySelectorAll(selector); } else { return element.querySelector(selector); } } async function getBgmId(mikanUrl) { let selector = "p.bangumi-info > a[href*='tv/subject']"; let bgm = await myFetch(mikanUrl, selector); if (bgm) bgm = bgm.href.split("/").slice(-1)[0]; return bgm } class MyStorage { constructor(prefix, splitStr = '|', expireDay = 0) { this.prefix = prefix; this.splitStr = splitStr; this.expireMs = expireDay * 864E5 } _keyGenerator(key) { return `${this.prefix}${this.splitStr}${key}` } get(key, defalut = null) { key = this._keyGenerator(key); let res = localStorage.getItem(key); if (this.expireMs && res) { res = JSON.parse(localStorage.getItem(key)).value; } res = res || defalut; return res } set(key, value) { key = this._keyGenerator(key); if (this.expireMs) { value = JSON.stringify({ timestamp: Date.now(), value: value }) } localStorage.setItem(key, value) } del(key) { key = this._keyGenerator(key); if (key in localStorage) { localStorage.removeItem(key) }; } checkIsExpire(key) { key = this._keyGenerator(key); if (!(key in localStorage)) return true; if (!this.expireMs && key in localStorage) { return false }; let timestamp = JSON.parse(localStorage.getItem(key)).timestamp; if (!timestamp) throw `checkIsExpire not work , not timestamp, key: ${key}`; if (timestamp + this.expireMs < Date.now()) { return true; } else { return false; } } } let mikanBgmStorage = new MyStorage("mikan"); let bgmInfoStorage = new MyStorage("bgm", undefined, 7); async function storeMikanBgm(mikanElementList, storeBgmInfo = false) { async function checkBgmInfoExist(mkId) { let bgmId = mikanBgmStorage.get(mkId); if (!bgmId) return; if (bgmInfoStorage.checkIsExpire(bgmId)) { bgmInfoStorage.set(bgmId, await parseBgmInfo(bgmId)); } } for (const element of mikanElementList) { let mikanUrl = element.href; let mikanId = mikanUrl.split('/').slice(-1)[0]; if (storeBgmInfo) await checkBgmInfoExist(mikanId); if (!mikanBgmStorage.checkIsExpire(mikanId)) { continue }; let bgmId = await getBgmId(mikanUrl); logger.info("fetch run", mikanId) await sleep(1000); if (mikanBgmStorage.checkIsExpire(mikanId)) { mikanBgmStorage.set(mikanId, bgmId); logger.info(`set ${mikanId} to ${bgmId}`); } } } async function parseBgmInfo(bgmId, stringify = false) { let bgmJson = await getBgmJson(bgmId); let score = (bgmJson) ? bgmJson.rating.score : 0.1; let summary = (bgmJson) ? bgmJson.summary : "maybe 18x"; let res = { score: score, summary: summary } res = (stringify) ? JSON.stringify(res) : res; return res } async function addScoreSummaryToHtml(mikanElementList) { for (const element of mikanElementList) { let scoreElement = element.nextElementSibling; if (scoreElement) continue; let mikanUrl = element.href; let mikanId = mikanUrl.split('/').slice(-1)[0]; let bgmId = mikanBgmStorage.get(mikanId); let bgmInfo = bgmInfoStorage.get(bgmId); if (!bgmId || !bgmInfo) continue; let bgmUrl = `https://bgm.tv/subject/${bgmId}` let score = bgmInfo.score; let summary = bgmInfo.summary let bgmHtml = `<a href="${bgmUrl}" target="_blank" title="${summary}" id="bgmScore">${score}</a>` element.insertAdjacentHTML("afterend", bgmHtml); let pathName = element.pathname; let mobileElement = document.querySelectorAll(`a[href="${pathName}"`)[1].nextElementSibling let title = mobileElement.textContent; let mobileHtml = `<a href="${bgmUrl}" target="_blank" title="${summary}" id="bgmScore">${title} ${score}</a>` mobileElement.insertAdjacentHTML("afterend", mobileHtml); mobileElement.remove(); } } async function main() { let animeList = multiTimesSeletor(null, true, "div.sk-bangumi", "a[href^='/Home/Bangumi']"); // animeList = animeList.slice(0, 81); await storeMikanBgm(animeList, true); await addScoreSummaryToHtml(animeList); logger.info(animeList) } (function loop() { setTimeout(async function () { let start = Date.now() await main(); let usedSec = (Date.now() - start) / 1000; if (usedSec > 0.01) logger.info(`used time ${usedSec}`); loop(); }, 2000); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址