Shows if an Itch.io link has been claimed or not
当前为
// ==UserScript==
// @name Itch.io Web Integration
// @namespace Lex@GreasyFork
// @match https://www.steamgifts.com/discussion/kGstL/free-itchio-games-and-everything-on-100-sale
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @version 0.1
// @author Lex
// @description Shows if an Itch.io link has been claimed or not
// @connect itch.io
// ==/UserScript==
// TODO
// Add caching of claimed results
// Add ability to claim the game with one click
(function(){
'use strict';
const INVALIDATION_TIME = 30*60*1000; // 30 minute cache time
const ITCH_GAME_CACHE_KEY = 'ItchGameCache';
var ItchGameCache;
// Promise wrapper for GM_xmlhttpRequest
const Request = details => new Promise((resolve, reject) => {
details.onerror = details.ontimeout = reject;
details.onload = resolve;
GM_xmlhttpRequest(details);
});
function loadItchCache() {
ItchGameCache = JSON.parse(GM_getValue(ITCH_GAME_CACHE_KEY) || '{}');
}
function _saveItchCache() {
if (ItchGameCache === undefined) return;
GM_setValue(ITCH_GAME_CACHE_KEY, JSON.stringify(ItchGameCache));
}
function setItchGameCache(key, game) {
loadItchCache(); // refresh our cache in case another tab has edited it
ItchGameCache[key] = game;
_saveItchCache();
}
function getItchGameCache(link) {
if (!ItchGameCache) loadItchCache();
if (Object.prototype.hasOwnProperty.call(ItchGameCache, link)) {
return ItchGameCache[link];
}
return null;
}
// Sends an XHR request and parses the results into a game object
async function fetchItchGame(url) {
const response = await Request({method: "GET",
url: url});
const parser = new DOMParser();
const dom = parser.parseFromString(response.responseText, 'text/html');
const h2 = dom.querySelector(".purchase_banner_inner .key_row .ownership_reason");
const game = {};
game.cachetime = (new Date()).getTime();
game.url = url;
game.isOwned = h2 !== null
return game;
}
// Loads an itch game from cache or fetches the page if needed
async function getItchGame(url) {
let game = getItchGameCache(url);
if (game !== null) {
const isExpired = (new Date()).getTime() - game.cachetime > INVALIDATION_TIME;
if (isExpired) {
console.log("Cache is expired for " + url);
game = null;
}
}
if (game === null) {
console.log("Fetching fresh results: " + url);
game = await fetchItchGame(url);
setItchGameCache(url, game);
} else {
console.log("Found the game in cache: " + url)
}
return game;
}
// Appends the isOwned tag to an anchor link
function appendTags(a, isOwned) {
const div = document.createElement("div");
a.after(div);
const ownMark = isOwned ? `<span title="Game is already claimed on itch.io">✔️</span>` : `<span title="Game is not claimed">❌</span>`;
div.outerHTML = `<div style="margin-left: 5px; background:rgb(200,200,200); border-radius: 5px; display: inline-block;">${ownMark}</div>`;
}
// Handles an itch.io link on a page
async function handleLink(a) {
const game = await getItchGame(a.href);
appendTags(a, game.isOwned);
}
// Finds all the itch.io links on the current page
function getItchLinks() {
const links = [...document.querySelectorAll("a[href*='itch.io/']")];
return links.filter(a => /^https:\/\/[^.]+\.itch\.io\/[^/]+$/.test(a.href));
}
function handlePage() {
const as = getItchLinks();
as.forEach(handleLink);
}
handlePage();
})();