您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhances JAST app pages with data from VNDB.
// ==UserScript== // @name VNDB JAST USA Enhancer // @namespace https://vndb.org/ // @version 1.3 // @description Enhances JAST app pages with data from VNDB. // @author darklinkpower // @match https://jastusa.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=jastusa.com // @grant GM_xmlhttpRequest // @connect api.vndb.org // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; const VN_LENGTH = { 0: { txt: 'Unknown', time: '', low: 0, high: 0 }, 1: { txt: 'Very short', time: 'Less than 2 hours', low: 1, high: 2 * 60 }, 2: { txt: 'Short', time: '2 - 10 hours', low: 2 * 60, high: 10 * 60 }, 3: { txt: 'Medium', time: '10 - 30 hours', low: 10 * 60, high: 30 * 60 }, 4: { txt: 'Long', time: '30 - 50 hours', low: 30 * 60, high: 50 * 60 }, 5: { txt: 'Very long', time: 'More than 50 hours', low: 50 * 60, high: 32767 } }; function formatMinutes(minutes) { if (minutes < 60) { return "" + minutes + "m"; } return "" + Math.floor(minutes / 60) + "h" + (minutes % 60) + "m"; } function getMinutesMatchingLength(minutes) { for (let key in VN_LENGTH) { const vnLenght = VN_LENGTH[key]; if (minutes >= vnLenght.low && minutes < vnLenght.high) { return vnLenght; } } return VN_LENGTH[0]; } var CurrentAppID; function GetAppIDFromUrl() { var currentURL = window.location.href; var idPattern = /\/games\/([^/]+)/; var match = currentURL.match(idPattern); if (match && match.length > 1) { return match[1]; } else { console.log("Id not found from url"); return null; } } function GetCurrentAppID() { if (!CurrentAppID) { CurrentAppID = GetAppIDFromUrl(); } return CurrentAppID; } function makeRow(rowClass, subtitle, linkText, linkUrl) { const row = document.createElement("div"); row.className = "info-row"; const label = document.createElement("span"); label.className = "info-row__label"; label.textContent = subtitle; const value = document.createElement("div"); value.className = "info-row__value"; let linkEl; if (linkUrl) { linkEl = document.createElement("a"); linkEl.className = "info-row__link"; linkEl.textContent = linkText; linkEl.href = linkUrl; } else { linkEl = document.createElement("span"); linkEl.className = "info-row__text"; linkEl.textContent = linkText; } value.appendChild(linkEl); row.appendChild(label); row.appendChild(value); return row; } function insertPanel(result) { let item = result.results[0]; const vndbIdRow = makeRow( "vndb_id", "Id", item.id, "https://vndb.org/" + item.id ); const rows = [ vndbIdRow, ]; if (item.rating) { rows.push(makeRow( "vndb_rating", "Rating", "" + item.rating + " (" + item.votecount + ")" )); } let lengthText = "" if (item.length_minutes && item.length_votes) { const timeDescription = getMinutesMatchingLength(item.length_minutes).txt const formattedMinutes = formatMinutes(item.length_minutes) lengthText = `${timeDescription} (${formattedMinutes} from ${item.length_votes} votes)`; } else if (item.length) { const mappedLength = VN_LENGTH[item.length]; lengthText = mappedLength.txt; if (item.length != 0) { lengthText += ` (${mappedLength.time})`; } } if (lengthText != "") { rows.push(makeRow( "vndb_length", "Play time", lengthText )); } let vndbInfoContainer = document.createElement("div"); vndbInfoContainer.className = "game-info vndb-infos"; let panelTitle = document.createElement('h3'); panelTitle.classList.add('game-info__title'); panelTitle.textContent = 'VNDB'; vndbInfoContainer.appendChild(panelTitle); let panelContent = document.createElement('div'); panelContent.classList.add('game-info__content'); vndbInfoContainer.appendChild(panelContent); rows.forEach(function(row) { panelContent.appendChild(row); }); let gameInfoPanel = document.querySelector('.game-info.game-info--basic'); if (gameInfoPanel) { gameInfoPanel.parentNode.insertBefore(vndbInfoContainer, gameInfoPanel); } else { console.log("Game info panel not found"); } } function fetchVNDBData() { let appId = GetCurrentAppID(); if (appId == null) { return; } GM_xmlhttpRequest({ method: "POST", url: "https://api.vndb.org/kana/vn", data: JSON.stringify({ "filters": ["release", "=", ["extlink", "=", ["jastusa", appId]]], "fields": "length,length_votes,length_minutes,rating,votecount" }), headers: { "Content-Type": "application/json" }, onload: function(response) { let result = JSON.parse(response.responseText); if (!result.results || result.results.length == 0) { console.log("VNDB search did not yield results"); return; } insertPanel(result); } }); } function observeUrlChanges() { let lastUrl = window.location.href; const onUrlChange = () => { const currentUrl = window.location.href; if (currentUrl !== lastUrl) { lastUrl = currentUrl; console.log("URL changed to " + currentUrl); CurrentAppID = null; fetchVNDBData(); } }; const observer = new MutationObserver(onUrlChange); observer.observe(document.body, { childList: true, subtree: true }); } function onInitialLoad() { window.removeEventListener('load', onInitialLoad); fetchVNDBData(); observeUrlChanges(); } window.addEventListener('load', onInitialLoad); })();