Decklog WS Deck Output

try to take over the world!

  1. // ==UserScript==
  2. // @name Decklog WS Deck Output
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.0.0
  5. // @description try to take over the world!
  6. // @author Chatgpt 4.0
  7. // @match https://decklog.bushiroad.com/view/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_setClipboard
  10. // ==/UserScript==
  11.  
  12. async function downloadImage(url) {
  13. return new Promise((resolve, reject) => {
  14. GM_xmlhttpRequest({
  15. method: "GET",
  16. url: url,
  17. responseType: "blob",
  18. onload: function (response) {
  19. resolve(response.response);
  20. },
  21. onerror: function (err) {
  22. reject(err);
  23. }
  24. });
  25. });
  26. }
  27.  
  28. async function loadImage(blob) {
  29. return new Promise((resolve, reject) => {
  30. const img = new Image();
  31. img.src = URL.createObjectURL(blob);
  32. img.onload = () => resolve(img);
  33. img.onerror = (err) => reject(err);
  34. });
  35. }
  36.  
  37. async function processImage(image, num) {
  38. const canvas = document.createElement('canvas');
  39. const ctx = canvas.getContext('2d');
  40.  
  41. if (image.width > image.height) {
  42. canvas.width = 1400;
  43. canvas.height = 1000;
  44. ctx.rotate(Math.PI / 2);
  45. ctx.drawImage(image, 0, -1400, 1000, 1400);
  46. } else {
  47. canvas.width = 1000;
  48. canvas.height = 1400;
  49. ctx.drawImage(image, 0, 0, 1000, 1400);
  50. }
  51.  
  52. const processedImages = [];
  53. for (let i = 0; i < num; i++) {
  54. processedImages.push(canvas.toDataURL());
  55. }
  56.  
  57. return processedImages;
  58. }
  59.  
  60. async function createDeckImage(images) {
  61. const canvas = document.createElement('canvas');
  62. const ctx = canvas.getContext('2d');
  63.  
  64. canvas.width = 10000;
  65. canvas.height = 7000;
  66.  
  67. let xPos = 0;
  68. let yPos = 0;
  69.  
  70. const imgPromises = images.map(async (image) => {
  71. return new Promise(async (resolve) => {
  72. const img = new Image();
  73. img.src = image;
  74. img.onload = () => {
  75. ctx.drawImage(img, xPos, yPos, 1000, 1400);
  76. xPos += 1000;
  77.  
  78. if (xPos >= 10000) {
  79. xPos = 0;
  80. yPos += 1400;
  81. }
  82. resolve();
  83. };
  84. });
  85. });
  86.  
  87. await Promise.all(imgPromises);
  88.  
  89. return new Promise((resolve) => {
  90. canvas.toBlob((blob) => {
  91. resolve(blob);
  92. }, 'image/jpeg');
  93. });
  94. }
  95.  
  96. async function ButtonClickAction(zEvent) {
  97. const deckList = [];
  98. let deckImages = [];
  99.  
  100. try {
  101. var list = document.querySelectorAll('.card-item.col-xl-2.col-lg-3.col-sm-4.col-6');
  102. } catch (e) {
  103. console.error(e.message);
  104. }
  105.  
  106. for (let item of list) {
  107. const imageUrl = item.getElementsByTagName("img")[0].getAttribute("data-src");
  108. const num = parseInt(item.getElementsByClassName("num")[0].innerHTML);
  109. deckList.push({ imageUrl, num });
  110. }
  111.  
  112. for (const item of deckList) {
  113. const imageBlob = await downloadImage(item.imageUrl);
  114. const image = await loadImage(imageBlob);
  115. const processedImages = await processImage(image, item.num);
  116. deckImages = deckImages.concat(processedImages);
  117. }
  118.  
  119. const deckBlob = await createDeckImage(deckImages);
  120. const deckFileName = window.location.pathname.split('/').pop() + '.jpg';
  121.  
  122. const a = document.createElement('a');
  123. a.href = URL.createObjectURL(deckBlob);
  124. a.download = deckFileName;
  125. a.click();
  126. URL.revokeObjectURL(a.href);
  127. }
  128.  
  129. async function copyDeckToClipboard(zEvent) {
  130. const deckList = [];
  131.  
  132. try {
  133. var list = document.querySelectorAll('.card-item.col-xl-2.col-lg-3.col-sm-4.col-6');
  134. } catch (e) {
  135. console.error(e.message);
  136. }
  137.  
  138. for (let item of list) {
  139. const title = item.getElementsByTagName("img")[0].getAttribute("title");
  140. let cardId = title.split(' ')[0];
  141. const num = parseInt(item.getElementsByClassName("num")[0].innerHTML);
  142.  
  143. // 替換特定結尾
  144. if (cardId.endsWith('SSP')) {
  145. cardId = cardId.replace('SSP', 's');
  146. } else if (cardId.endsWith('OFR')) {
  147. cardId = cardId.replace('OFR', 'f');
  148. } else if (cardId.endsWith('WIR')) {
  149. cardId = cardId.replace('WIR', 'i');
  150. } else if (cardId.endsWith('RRR')) {
  151. cardId = cardId.replace('RRR', 'r');
  152. } else if (cardId.endsWith('SR')) {
  153. cardId = cardId.replace('SR', 's');
  154. } else if (cardId.endsWith('SP')) {
  155. cardId = cardId.replace('SP', 'p');
  156. }
  157.  
  158. for (let i = 0; i < num; i++) {
  159. deckList.push(cardId);
  160. }
  161. }
  162.  
  163. const deckText = deckList.join('\n');
  164. GM_setClipboard(deckText);
  165. alert('Deck copied to clipboard!');
  166. }
  167.  
  168.  
  169. function addButtonWhenAvailable() {
  170. const viewBtnContainer = document.querySelector('.view-btn-container .btn-container');
  171.  
  172. if (viewBtnContainer) {
  173. const deckImageButton = document.createElement('button');
  174. deckImageButton.setAttribute('type', 'button');
  175. deckImageButton.setAttribute('class', 'btn btn-warning btn-sm');
  176. deckImageButton.textContent = 'Create Deck Image';
  177. viewBtnContainer.appendChild(deckImageButton);
  178. deckImageButton.addEventListener("click", ButtonClickAction, false);
  179.  
  180. const copyDeckButton = document.createElement('button');
  181. copyDeckButton.setAttribute('type', 'button');
  182. copyDeckButton.setAttribute('class', 'btn btn-warning btn-sm');
  183. copyDeckButton.textContent = 'Copy Deck to Clipboard';
  184. viewBtnContainer.appendChild(copyDeckButton);
  185. copyDeckButton.addEventListener("click", copyDeckToClipboard, false);
  186. } else {
  187. setTimeout(addButtonWhenAvailable, 500);
  188. }
  189. }
  190.  
  191. addButtonWhenAvailable();