返回首頁 

Greasy Fork is available in English.

Humble Bundle Keys Backup

Displays a text area with game titles and keys so you can copy them out easily.


Installer ce script?
// ==UserScript==// @name         Humble Bundle Keys Backup// @namespace    Lex@GreasyFork// @version      0.2.0// @description  Displays a text area with game titles and keys so you can copy them out easily.// @author       Lex// @match        https://www.humblebundle.com/downloads*// @grant        none// ==/UserScript==(function() {'use strict';function formatGames(games, bundleTitle) {// Format the output as tab-separatedif (bundleTitle) {games = games.map(e => (bundleTitle + "\t" + e.title+"\t"+e.key).trim());} else{games = games.map(e => (e.title+"\t"+e.key).trim());}return games.join("\n");}function createNotify() {const notify = document.createElement("div");notify.className = "ktt-notify";return notify;}function updateNotify(bundle, message) {const notify = bundle.querySelector(".ktt-notify");notify.innerHTML = message;}function createConfig(updateCallback) {const createCheckbox = (labelText, className, defaultChecked) => {const label = document.createElement("label");label.style.marginRight = "10px";const checkbox = document.createElement("input");checkbox.type = "checkbox";checkbox.className = className;checkbox.checked = defaultChecked;checkbox.addEventListener("change", updateCallback);label.append(` ${labelText} `, checkbox,);return label;};const container = document.createElement("div");container.append(createCheckbox("Include Bundle Title", "includeTitle", false),createCheckbox("Include Unrevealed", "includeUnrevealed", true));container.className = "ktt-config-container"return container;}function createArea() {const area = document.createElement("textarea");area.className = "key-text-area";area.style.width = "100%";area.setAttribute('readonly', true);return area;}// Updates an area if it needs updating, adjusting the height to fit the contentsfunction updateArea(bundle, updateStr) {const area = bundle.querySelector(".key-text-area")if (area.value != updateStr) {area.value = updateStr;// Adjust the height so all the contents are visiblearea.style.height = "";area.style.height = area.scrollHeight + 20 + "px";}}function createCopyButton(area) {const button = document.createElement("button");button.textContent = "Copy to Clipboard";button.style.cssText = "display: block; margin: 5px 0; padding: 5px 10px; cursor: pointer;";button.addEventListener("click", async () => {await navigator.clipboard.writeText(area.value);button.textContent = "Copied!";setTimeout(() => (button.textContent = "Copy to Clipboard"), 1500);});return button;}// Returns array of the games in the target bundlefunction getGames(bundle) {let games = [];bundle.querySelectorAll(".key-redeemer").forEach(div => {let game = {};game.title = div.querySelector(".heading-text h4").innerText;const keyfield = div.querySelector(".keyfield");if (!keyfield) return;game.key = keyfield.title;if (game.key.startsWith("Reveal your ")) {game.key = "";game.revealed = false;} else {game.revealed = true;}game.isGift = keyfield.classList.contains("redeemed-gift");game.isKey = keyfield.classList.contains("redeemed");games.push(game);});return games;}function refreshOutput(bundle) {const gameCount = document.querySelectorAll(".keyfield").length;const revealedCount = document.querySelectorAll(".redeemed,.redeemed-gift").length;const color = gameCount == revealedCount ? "" : "tomato";let notifyHtml = `Found ${gameCount} keyfields. <span style="background:${color}">${revealedCount} are revealed.</span>`;if (gameCount != revealedCount) {notifyHtml += " Are some keys not revealed?";}if (!bundle.querySelector(".ktt-config-container")) {const updateCallback = () => refreshOutput(bundle);const textArea = createArea();bundle.append(createNotify(), createConfig(updateCallback), textArea, createCopyButton(textArea))}updateNotify(bundle, notifyHtml)let games = getGames(bundle);const includeTitle = bundle.querySelector(".includeTitle").checked;const bundleTitle = includeTitle ? $('h1#hibtext')[0].childNodes[2].textContent.trim() : null;const includeUnrevealed = bundle.querySelector(".includeUnrevealed").checked;if (!includeUnrevealed) games = games.filter(e => e.key);const outputText = formatGames(games, bundleTitle);updateArea(bundle, outputText);}function handlePage() {document.querySelectorAll(".key-container.wrapper").forEach(refreshOutput);}function waitForLoad(query, callback) {if (document.querySelector(query)) {callback();} else {setTimeout(waitForLoad.bind(null, query, callback), 100);}}waitForLoad(".key-redeemer", handlePage);})();