您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows if an Itch.io link has been claimed or not
当前为
- // ==UserScript==
- // @name Itch.io Web Integration
- // @namespace Lex@GreasyFork
- // @match *://*/*
- // @grant GM_xmlhttpRequest
- // @grant GM_getValue
- // @grant GM_setValue
- // @version 0.1.8.1
- // @author Lex
- // @description Shows if an Itch.io link has been claimed or not
- // @connect itch.io
- // ==/UserScript==
- (function(){
- 'use strict';
- const CACHE_VERSION_KEY = "CacheVersion";
- const INVALIDATION_TIME = 5*60*60*1000; // 5 hour 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 versionCacheInvalidator() {
- const sVersion = v => {
- if (typeof v !== 'string' || !v.match(/\d+\.\d+/)) return 0;
- return parseFloat(v.match(/\d+\.\d+/)[0]);
- }
- const prev = sVersion(GM_getValue(CACHE_VERSION_KEY, '0.0'));
- if (prev < 0.1) {
- console.log(`${GM_info.script.version} > ${prev}`);
- console.log(`New minor version of ${GM_info.script.name} detected. Invalidating cache.`)
- _clearItchCache();
- }
- GM_setValue(CACHE_VERSION_KEY, GM_info.script.version);
- }
- function _clearItchCache() {
- ItchGameCache = {};
- _saveItchCache();
- }
- 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 deleteItchGameCache(key) {
- if (key === undefined) return;
- loadItchCache();
- delete ItchGameCache[key];
- _saveItchCache();
- }
- function getItchGameCache(link) {
- if (!ItchGameCache) loadItchCache();
- if (Object.prototype.hasOwnProperty.call(ItchGameCache, link)) {
- return ItchGameCache[link];
- }
- return null;
- }
- async function claimGame(url) {
- const parser = new DOMParser();
- const purchase_url = url + "/purchase";
- console.log("Getting purchase page: " + purchase_url);
- const purchase_resp = await Request({method: "GET", url: purchase_url});
- const purchase_dom = parser.parseFromString(purchase_resp.responseText, 'text/html');
- const download_csrf_token = purchase_dom.querySelector("form.form").csrf_token.value;
- const download_url_resp = await Request({
- method: "POST",
- url: url + "/download_url",
- headers: {
- "Content-Type": "application/x-www-form-urlencoded"
- },
- data: 'csrf_token='+encodeURIComponent(download_csrf_token)
- });
- const downloadUrl = JSON.parse(download_url_resp.responseText).url;
- console.log("Received download url: " + downloadUrl);
- const download_resp = await Request({method: "GET", url: downloadUrl});
- const dom = parser.parseFromString(download_resp.responseText, 'text/html');
- const claimForm = dom.querySelector(".claim_to_download_box form");
- const claim_csrf_token = claimForm.csrf_token.value;
- const claim_key_url = claimForm.action;
- console.log("Claiming game using " + claim_key_url);
- const claim_key_resp = await Request({
- method: "POST",
- url: claim_key_url,
- headers: {
- "Content-Type": "application/x-www-form-urlencoded"
- },
- data: 'csrf_token='+encodeURIComponent(claim_csrf_token)
- });
- return /You claimed this/.test(claim_key_resp.responseText);
- }
- // Parses a DOM into a game object
- function parsePage(url, dom) {
- // Gets the inner text of an element if it can be found otherwise returns undefined
- const txt = query => { const e = dom.querySelector(query); return e && e.innerText.trim(); };
- const game = {};
- game.cachetime = (new Date()).getTime();
- game.url = url;
- game.isOwned = dom.querySelector(".purchase_banner_inner .key_row .ownership_reason") !== null;
- game.isClaimable = [...dom.querySelectorAll(".buy_btn")].filter(e => e.innerText == "Download or claim").length > 0;
- game.isFree = [...dom.querySelectorAll("span[itemprop=price]")].filter(e => e.innerText == "$0.00 USD").length > 0;
- game.hasFreeDownload = [...dom.querySelectorAll("a.download_btn,a.buy_btn")].filter(e => e.innerText == "Download" || e.innerText == "Download Now").length > 0;
- game.original_price = txt("span.original_price");
- game.price = txt("span[itemprop=price]");
- game.saleRate = txt(".sale_rate");
- return game;
- }
- // Sends an XHR request and parses the results into a game object
- async function fetchItchGame(url) {
- const response = await Request({method: "GET",
- url: url});
- if (response.status != 200) {
- console.log(`Error ${response.status} fetching page ${url}`);
- return null;
- }
- const parser = new DOMParser();
- const dom = parser.parseFromString(response.responseText, 'text/html');
- return parsePage(url, dom);
- }
- // 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;
- // Expiration checking currently disabled
- /*if (isExpired) {
- game = null;
- }*/
- }
- if (game === null) {
- game = await fetchItchGame(url);
- if (game !== null)
- setItchGameCache(url, game);
- }
- return game;
- }
- async function claimClicked(a, game) {
- console.log("Attempting to claim " + game.url);
- a.innerText += ' ⌛';
- a.onclick = null;
- const success = await claimGame(game.url);
- if (success === true) {
- a.style.display = "none";
- const ownMark = a.previousElementSibling;
- ownMark.innerHTML = `<span title="Successfully claimed">✔️</span>`;
- deleteItchGameCache(game.url);
- }
- }
- // Appends the isOwned tag to an anchor link
- function appendTags(a, game) {
- const div = document.createElement("div");
- a.after(div);
- let ownMark = '';
- if (game === null) {
- ownMark = `<span title="Status unknown. Try refreshing.">❓</span>`;
- } else if (game.isOwned) {
- ownMark = `<span title="Game is already claimed on itch.io">✔️</span>`;
- } else {
- if (!game.isClaimable) {
- if (game.hasFreeDownload) {
- ownMark = `<span title="Game is a free download but not claimable">⛔</span>`;
- } else if (game.price) {
- ownMark = `<span title="🛒 Game costs ${game.price}">🛒</span>`;
- } else {
- ownMark = `<span title="Status unknown">👽</span>`;
- }
- } else {
- const origPrice = game.original_price ? ` 🛒 Original price: ${game.original_price} 💸 Current Price: ${game.price}` : '';
- ownMark = `<span title="Game is claimable but you haven't claimed it.${origPrice}">❌</span> <span style="padding: 2px; cursor:pointer; background:rgb(200,200,200); border-radius: 5px" class="ClaimButton">🛄 Claim Game</span>`;
- }
- }
- div.innerHTML = ownMark;
- div.style.display = "inline-block";
- div.childNodes[0].style = "margin-left: 5px; background:rgb(200,200,200); padding: 2px; border-radius: 2px";
- const claimBtn = div.querySelector(".ClaimButton");
- if (claimBtn) {
- claimBtn.onclick = function(event) { claimClicked(event.target, game); };
- }
- }
- function addClickHandler(a) {
- a.addEventListener('mouseup', event => {
- deleteItchGameCache(event.target.href);
- });
- }
- // Handles an itch.io link on a page
- async function handleLink(a) {
- addClickHandler(a);
- const game = await getItchGame(a.href);
- appendTags(a, game);
- }
- function isGameUrl(url) {
- return /^https:\/\/[^.]+\.itch\.io\/[^/]+$/.test(url);
- }
- // Finds all the itch.io links on the current page
- function getItchLinks() {
- let links = [...document.querySelectorAll("a[href*='itch.io/']")];
- links = links.filter(a => isGameUrl(a.href));
- links = links.filter(a => !a.classList.contains("return_link"));
- links = links.filter(a => { const t = a.textContent.trim(); return t !== "" && t !== "GIF"; });
- return links;
- }
- function handlePage() {
- if (isGameUrl(window.location.href)) {
- const game = parsePage(window.location.href, document);
- setItchGameCache(window.location.href, game);
- }
- const as = getItchLinks();
- as.forEach(handleLink);
- }
- versionCacheInvalidator();
- handlePage();
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址