- // ==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);
- })();