您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays a text area with game titles and keys so you can copy them out easily.
当前为
// ==UserScript== // @name Fanatical Keys Backup // @namespace Lex@GreasyFork // @version 0.2.5 // @description Displays a text area with game titles and keys so you can copy them out easily. // @author Lex // @match https://www.fanatical.com/en/orders* // @grant none // ==/UserScript== (function() { 'use strict'; // Formats games array to a string to be displayed // Games is an array [ [title, key], ... ] function formatGames(games) { // Ignore games which do not have keys revealed games = games.filter(e => e[1]); // Format the output as tab-separated games = games.map(e => e[0]+"\t"+e[1]); return games.join("\n"); } function getGames(bundle) { let is = bundle.querySelectorAll(".new-order-item"); return Array.prototype.map.call(is, i => { const gameTitleElement = i.getElementsByClassName("game-name"); const gameTitle = gameTitleElement.length > 0 ? gameTitleElement[0].textContent.trim() : ""; const keyElement = i.querySelector("[aria-label='reveal-key']"); const gameKey = keyElement ? keyElement.value : ""; return [gameTitle, gameKey]; }); } function revealAllKeys(bundle) { const revealButtons = bundle.querySelectorAll(".key-container button.btn-block"); revealButtons.forEach(b => { b.click() }); this.style.display = "none"; } function createRevealButton(bundle) { let btn = document.createElement("button"); btn.type = "button"; // no default behavior btn.innerText = "Reveal this bundle's keys"; btn.onclick = revealAllKeys.bind(btn, bundle); return btn; } // Adds a textarea to the bottom of the games listing with all the titles and keys function handleBundle(bundles) { const bundle = bundles.at(-1); const bundleName = bundles[0].querySelector(".bundle-name")?.textContent.trim() ?? "No Title"; const games = bundles.flatMap(bundle => getGames(bundle)); const keyCount = games.filter(e => e[1]).length; const gameStr = formatGames(games); let notify = bundle.querySelector(".ktt-notify"); if (!notify) { notify = document.createElement("div"); notify.className = "ktt-notify"; bundle.append(notify); if (games.length != keyCount) { const btn = createRevealButton(bundle); notify.before(btn); } } const color = games.length === keyCount ? "" : "red"; let newInner = `Dumping keys for ${bundleName}: Found ${games.length} items and <span style="background-color:${color}">${keyCount} keys</span>.`; if (games.length != keyCount) { newInner += " Are some keys not revealed?"; } if (notify.innerHTML != newInner) { notify.innerHTML = newInner; } let area = bundle.querySelector(".ktt"); if (!area) { area = document.createElement("textarea"); area.className = "ktt"; area.style.width = "100%"; area.setAttribute('readonly', true); bundle.append(area); } if (area.value != gameStr) { area.value = gameStr; // Adjust the height so all the contents are visible area.style.height = ""; area.style.height = area.scrollHeight + 20 + "px"; } } var loopCount = 0; function handleOrderPage() { // There can be more than one bundle in an order let bundleItemsContainers = [...new Set([...document.querySelectorAll('.new-order-item')].map(item => item.closest('section')))]; // combine bundle groups into their overall bundle header // this is needed because mystery bundles span multiple bundle containers for some reason let currentBundleGroup = []; const bundleGroups = [currentBundleGroup]; for (const bundleItemsContainer of bundleItemsContainers) { if (bundleItemsContainer.firstChild.className === "bundle-name-container" && currentBundleGroup.length > 0) { // Indicates a new bundle group is starting currentBundleGroup = []; bundleGroups.push(currentBundleGroup); } currentBundleGroup.push(bundleItemsContainer); } if (bundleGroups.length > 0 && bundleGroups[0].length > 0) { //console.log(`Found ${bundleGroups.length} bundle(s)`); bundleGroups.forEach(handleBundle); if (loopCount++ < 100) { setTimeout(handleOrderPage, 500); } } else { if (loopCount++ < 100) { setTimeout(handleOrderPage, 100); } } } handleOrderPage(); })();