[GC] - SDB Contents Collection

2/25/2024, 11:26:31 PM

  1. // ==UserScript==
  2. // @name [GC] - SDB Contents Collection
  3. // @namespace https://greasyfork.org/en/users/1225524-kaitlin
  4. // @match https://www.grundos.cafe/safetydeposit/*
  5. // @grant GM.setValue
  6. // @grant GM.getValue
  7. // @grant GM.addStyle
  8.  
  9. // @license MIT
  10. // @version 1.3
  11. // @author Cupkait
  12. // @icon https://i.imgur.com/4Hm2e6z.png
  13. // @description 2/25/2024, 11:26:31 PM
  14. // ==/UserScript==
  15.  
  16.  
  17. let collect = false;
  18. let active = false;
  19.  
  20. const sdbStyle = createSdbStyle();
  21. document.head.appendChild(sdbStyle);
  22.  
  23. const collectContainer = createCollectContainer();
  24. document.querySelector('main .sdb-info').append(collectContainer);
  25.  
  26. initialize();
  27.  
  28. async function initialize() {
  29. collect = await GM.getValue('collect', false);
  30. active = await GM.getValue('active', false);
  31. collect ? showNextButtons() : active ? enableNextPageNavigation() : showEnableButton();
  32. }
  33.  
  34. function createSdbStyle() {
  35. const style = document.createElement('style');
  36. style.innerHTML = `
  37. .collect-sdb {
  38. text-align: center;
  39. margin: 10px;
  40. }
  41. .collect-sdb a {
  42. background-color: var(--grid_head);
  43. border: 1px solid grey;
  44. padding: 5px 15px;
  45. margin: 10px;
  46. }
  47. `;
  48. return style;
  49. }
  50.  
  51. function createCollectContainer() {
  52. const container = document.createElement('div');
  53. container.classList.add('collect-sdb');
  54. return container;
  55. }
  56.  
  57. function showEnableButton() {
  58. collectContainer.append(createButton('Begin SDB Data Collection', () => {
  59. GM.setValue('collect', true).then(showNextButtons);
  60. }));
  61. }
  62.  
  63. function showNextButtons() {
  64. removeAllButtons();
  65. collectContainer.append(
  66. createButton('Collect full SDB', () => setActiveAndNavigate('https://www.grundos.cafe/safetydeposit/?view=100')),
  67. createButton('Collect quest only', () => setActiveAndNavigate('https://www.grundos.cafe/safetydeposit/?page=1&&max_rarity=89&view=100'))
  68. );
  69. }
  70.  
  71. function createButton(text, onClick) {
  72. const button = document.createElement('a');
  73. button.textContent = text;
  74. button.addEventListener('click', onClick);
  75. return button;
  76. }
  77.  
  78. function removeAllButtons() {
  79. while (collectContainer.firstChild) collectContainer.firstChild.remove();
  80. }
  81.  
  82. async function setActiveAndNavigate(url) {
  83. await Promise.all([GM.setValue('collect', false), GM.setValue('active', true)]);
  84. window.location.href = url;
  85. }
  86.  
  87. function enableNextPageNavigation() {
  88. removeEnableButton();
  89. collectContainer.append(createButton('Cancel/Restart Collection', cancelCollection));
  90. initTableProcessing();
  91. }
  92.  
  93. function removeEnableButton() {
  94. const enableButton = collectContainer.querySelector('button');
  95. if (enableButton) enableButton.remove();
  96. }
  97.  
  98. function appendMessages(messageText) {
  99. const message = document.createElement('p');
  100. message.innerHTML = messageText;
  101. collectContainer.append(message);
  102. }
  103.  
  104. async function initTableProcessing() {
  105. await processTableData();
  106. displayPageInfo();
  107. setupKeyboardNavigation();
  108. }
  109.  
  110. async function loadSdbContents() {
  111. return GM.getValue('sdbContents', []);
  112. }
  113.  
  114. async function saveSdbContents(contents) {
  115. await GM.setValue('sdbContents', contents);
  116. }
  117.  
  118. async function processTableData() {
  119. const sdbContents = await loadSdbContents();
  120. const data = document.querySelectorAll('.data');
  121. const rows = [];
  122.  
  123. for (let i = 0; i < data.length; i += 7) {
  124. const row = createRow(data, i);
  125. const existingItemIndex = sdbContents.findIndex(item => item.n === row.n);
  126. if (existingItemIndex > -1) sdbContents[existingItemIndex] = row;
  127. else sdbContents.push(row);
  128. rows.push(row);
  129. }
  130.  
  131. await saveSdbContents(sdbContents);
  132. }
  133.  
  134. function createRow(data, index) {
  135. return {
  136. n: data[index + 1].querySelector('strong').textContent,
  137. r: parseInt(data[index + 1].querySelector('span').textContent.match(/\d+/)[0]),
  138. p: data[index + 2].querySelector('img').src.split('/').pop(),
  139. q: parseInt(data[index + 3].textContent),
  140. t: data[index + 4].querySelector('strong').textContent,
  141. };
  142. }
  143.  
  144. function setupKeyboardNavigation() {
  145. document.addEventListener('keydown', (event) => {
  146. if (event.key === 'ArrowRight' && !['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
  147. const nextPageLink = [...document.querySelectorAll('.center a')].find(link => link.textContent.trim().startsWith('Next'));
  148. if (nextPageLink) nextPageLink.click();
  149. }
  150. });
  151. }
  152.  
  153. async function displayPageInfo() {
  154. const pageCount = document.querySelectorAll('#page option').length;
  155. const currentPage = parseInt(new URLSearchParams(window.location.search).get('page')) || 1;
  156. const sdbContents = await loadSdbContents();
  157. const totalItems = sdbContents.length;
  158. const endTotal = parseFloat(document.querySelector('main div:nth-child(6)').childNodes[4].textContent.replace(/[^0-9.]/g, '').replace(/,/g, ''));
  159.  
  160. console.log(endTotal)
  161.  
  162. appendMessages(`Total items collected: <strong>${totalItems.toLocaleString()}</strong> <br>You are viewing page <strong>${currentPage.toLocaleString()}</strong> / <strong>${pageCount.toLocaleString()}</strong>.`);
  163. appendMessages(`Click "Next" or press the right arrow key to go to the next page.`);
  164.  
  165. if (totalItems === endTotal) appendExportButtons();
  166. }
  167.  
  168. function appendExportButtons() {
  169. collectContainer.append(createButton('Export to CSV', exportToCSV), createButton('Copy to Clipboard', copyToClipboard));
  170. appendMessages(`Export to CSV to make a spreadsheet of the results. Copy to Clipboard to paste into a Virtupets.net Checklist.`)
  171. }
  172.  
  173. function exportToCSV() {
  174. loadSdbContents().then(sdbContents => {
  175. const csvContent = "data:text/csv;charset=utf-8," + sdbContents.map(e => Object.values(e).join(",")).join("\n");
  176. const link = document.createElement("a");
  177. link.setAttribute("href", encodeURI(csvContent));
  178. link.setAttribute("download", "sdbContents.csv");
  179. document.body.appendChild(link);
  180. link.click();
  181. link.remove();
  182. displayCompletionMessage();
  183. });
  184. }
  185.  
  186. async function copyToClipboard() {
  187. try {
  188. const sdbContents = await loadSdbContents();
  189. await navigator.clipboard.writeText(JSON.stringify(sdbContents));
  190. displayCompletionMessage();
  191. } catch (err) {
  192. console.error('Error copying to clipboard:', err);
  193. }
  194. }
  195.  
  196.  
  197. function displayCompletionMessage() {
  198. const collectContainer = document.querySelector('.collect-sdb'); // or whatever selector you need
  199.  
  200. if (!collectContainer) {
  201. console.error('Collect container not found!');
  202. return;
  203. }
  204.  
  205. let message = collectContainer.querySelector('.completion-message');
  206.  
  207. if (!message) {
  208. message = document.createElement('p');
  209. message.classList.add('completion-message');
  210. collectContainer.append(message);
  211. }
  212. message.innerHTML = 'Copy complete! Press "Restart Collection" to return to your usual SDB view.';
  213. }
  214.  
  215.  
  216. async function cancelCollection() {
  217. await Promise.all([GM.setValue('active', false), GM.setValue('sdbContents', [])]);
  218. window.location.href = 'https://www.grundos.cafe/safetydeposit/?view=100';
  219. }