Humble Bundle Keys Backup

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

当前为 2020-05-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Humble Bundle Keys Backup
  3. // @namespace Lex@GreasyFork
  4. // @version 0.1
  5. // @description Displays a text area with game titles and keys so you can copy them out easily.
  6. // @author Lex
  7. // @match https://www.humblebundle.com/downloads*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. function formatGames(games) {
  15. // Ignore games which do not have keys revealed
  16. //games = games.filter(e => e.key);
  17. // Format the output as tab-separated
  18. games = games.map(e => (e.title+"\t"+e.key).trim());
  19. return games.join("\n");
  20. }
  21.  
  22. function createNotify(bundle, message) {
  23. const areaName = "ktt-notify";
  24. let notify = bundle.querySelector("."+areaName);
  25. if (!notify) {
  26. notify = document.createElement("div");
  27. notify.className = areaName;
  28. bundle.append(notify);
  29. }
  30. notify.innerHTML = message;
  31. return notify;
  32. }
  33.  
  34. function createArea() {
  35. const area = document.createElement("textarea");
  36. area.className = "key-text-area";
  37. area.style.width = "100%";
  38. area.setAttribute('readonly', true);
  39. return area;
  40. }
  41.  
  42. // Updates an area if it needs updating, adjusting the height to fit the contents
  43. function updateArea(area, updateStr) {
  44. if (area.value != updateStr) {
  45. area.value = updateStr;
  46. // Adjust the height so all the contents are visible
  47. area.style.height = "";
  48. area.style.height = area.scrollHeight + 20 + "px";
  49. }
  50. }
  51.  
  52. // Returns array of the games in the target bundle
  53. function getGames(bundle) {
  54. let games = [];
  55. bundle.querySelectorAll(".key-redeemer").forEach(div => {
  56. let game = {};
  57. game.title = div.querySelector(".heading-text h4").innerText;
  58. const keyfield = div.querySelector(".keyfield");
  59. game.key = keyfield.title;
  60. if (game.key == "Reveal your Steam key") {
  61. game.key = "";
  62. game.revealed = false;
  63. } else {
  64. game.revealed = true;
  65. }
  66. game.isGift = keyfield.classList.contains("redeemed-gift");
  67. game.isKey = keyfield.classList.contains("redeemed");
  68. games.push(game);
  69. });
  70. return games;
  71. }
  72.  
  73. function handlePage() {
  74. document.querySelectorAll(".key-container.wrapper").forEach(bundle => {
  75. const gameCount = document.querySelectorAll(".keyfield").length;
  76. const revealedCount = document.querySelectorAll(".redeemed,.redeemed-gift").length;
  77.  
  78. const color = gameCount == revealedCount ? "" : "tomato";
  79. let notifyHtml = `Found ${gameCount} keyfields. <span style="background:${color}">${revealedCount} are revealed.</span>`;
  80. if (gameCount != revealedCount) {
  81. notifyHtml += " Are some keys not revealed?";
  82. }
  83. createNotify(bundle, notifyHtml);
  84.  
  85. const area = createArea();
  86. bundle.append(area);
  87. const games = getGames(bundle);
  88. updateArea(area, formatGames(games));
  89. });
  90. }
  91.  
  92. function waitForLoad(query, callback) {
  93. if (document.querySelector(query)) {
  94. callback();
  95. } else {
  96. setTimeout(waitForLoad.bind(null, query, callback), 100);
  97. }
  98. }
  99.  
  100. waitForLoad(".key-redeemer", handlePage);
  101. })();