Greasy Fork 支持简体中文。

Groupees Backup

备份 Groupees 数据。

  1. // ==UserScript==
  2. // @name Groupees Backup
  3. // @namespace https://greasyfork.org/users/34380
  4. // @version 20220706
  5. // @description 备份 Groupees 数据。
  6. // @match https://groupees.com/purchases
  7. // @grant none
  8. // ==/UserScript==
  9.  
  10. (function () {
  11. 'use strict';
  12.  
  13. // Your code here...
  14.  
  15. var id, page, generator1, generator2, all, text, output;
  16. var plats = ["Steam", "Itch.io", "Desura"];
  17. var kws = ["PC", "OS X", "Linux", "Android", "Mp3", "Flac"];
  18. var user_id = document.querySelector('.fayepub').getAttribute('data-user');
  19.  
  20. function getNextPageBundle(mode) {
  21. fetch('https://groupees.com/users/'+ user_id + '/more_entries?page=' + page + '&kind=bundles').then(res => res.json()).then(res => {
  22. if (res.length > 0) {
  23. if (mode == 1) {
  24. generator1 = getBundleHTML(res);
  25. generator1.next();
  26. } else {
  27. generator2 = revealOrder(res);
  28. generator2.next();
  29. }
  30. } else {
  31. if (mode == 1) { toExcel(); } else { output.value += '刮开完成。\n'; }
  32. }
  33. });
  34. }
  35.  
  36. function* getBundleHTML(bundles) {
  37. for (var bundle of bundles) {
  38. var bun = JSON.parse(bundle);
  39. if (id) {
  40. if (id == bun.id) { id = false; }
  41. } else {
  42. yield fetch('https://groupees.com/orders/' + bun.id + '?user_id=' + user_id).then(res => res.text()).then(res => {
  43. // var html = res.match(/(?<=html = )[\s\S]+(?=;[\s\S]+var groupeesRe)/);
  44. var html = res.match(/(?<=html = \$\(')[\s\S]+(?='\);[\s\S]+var groupeesRe)/);
  45. var div = document.createElement('DIV');
  46. html = html[0].replace(/\\n/g, "").replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\//g, "/");
  47. div.innerHTML = html;
  48. var [json, note] = getMainData(div);
  49. all.push([bun, json, note]);
  50. output.value += '已加载包 id ' + bun.id + ' ' + bun.bundle_name + '\n';
  51.  
  52. setTimeout(() => {
  53. if (generator1.next().done == true) {
  54. page++;
  55. getNextPageBundle(1);
  56. }
  57. }, 3000);
  58. });
  59. }
  60. }
  61. if (id && bundles.length) { page++; getNextPageBundle(1); }
  62. }
  63.  
  64. function getMainData(div) {
  65. var jsons = [];
  66. var items = div.querySelectorAll('.product');
  67. var note = div.querySelector('.announcements');
  68. note = note ? note.innerText.replace(/\n/g, ' ') : '';
  69. for (var item of items) {
  70. var obj = {};
  71. obj['name'] = item.querySelector('.product-name').innerText;
  72.  
  73. var action = item.querySelector('.product-meta');
  74. if (action) {
  75. if (action.querySelector('.icon-givenaway-arrow')) { obj['Steam'] = { "key": "", "status": "Givenaway" }; }
  76. else { obj['Steam'] = { "key": "", "status": "Reveal this product" }; }
  77. } else {
  78. var keys_rows = item.querySelectorAll('.col-sm-6.key');
  79. for (var row of keys_rows) {
  80. var type = row.querySelector('strong').innerText.replace(/^i/, "I");
  81. var key = row.querySelector('.form-control.code');
  82. // if (!key) {document.querySelector('.key-meta').innerText;}
  83. var value = key.value;
  84. var status = key.disabled;
  85. if (row.querySelector('.key-meta .green')) { status = row.querySelector('.key-meta .green').innerText; }
  86. if (obj[type]) { note += type + ' ' + obj['name'] + ': ' + value + ' ' + status + '. '; }
  87. if (!plats.includes(type)) { note += type + ' ' + obj['name'] + ': ' + value + ' ' + status + '. '; }
  88. obj[type] = { "key": value, "status": status };
  89. }
  90.  
  91. var link_row = item.querySelectorAll('.dropdown-header');
  92. for (var row of link_row) {
  93. var type = row.innerText;
  94. var link = row.nextElementSibling.children[0].href;
  95. if (obj[type]) { note += type + ' ' + obj['name'] + ': ' + link + ' . '; }
  96. if (!kws.includes(type)) { note += type + ' ' + obj['name'] + ': ' + link + ' . '; }
  97. obj[type] = link;
  98. }
  99. }
  100. jsons.push(obj);
  101. }
  102. return [jsons, note];
  103. }
  104.  
  105. function toExcel() {
  106. text = '包名 价格 日期 名字 Steam 状态 Itch 状态 Desura 状态 PC OS X Linux Android Mp3 Flac\n';
  107. for (var one of all) {
  108. var text_bun = one[0].bundle_name + ' ' + one[0].total_amount + ' ' + one[0].completed_at + ' ';
  109. for (var item of one[1]) {
  110. var text_item = item.name + ' ';
  111. for (var plat of plats) {
  112. if (item[plat]) {
  113. text_item += item[plat].key + ' ' + item[plat].status + ' ';
  114. } else {
  115. text_item += ' ' + ' ';
  116. }
  117. }
  118.  
  119. for (var kw of kws) {
  120. text_item += (item[kw] || '') + ' ';
  121. }
  122. text += text_bun + text_item + '\n';
  123. }
  124. if (one[2] != '') { text += one[2] + '\n'; }
  125. }
  126. output.value = text;
  127. }
  128.  
  129. function* revealOrder(bundles) {
  130. for (var bundle of bundles) {
  131. var bun = JSON.parse(bundle);
  132. yield $.ajax({
  133. url: 'https://groupees.com/orders/' + bun.id + '/reveal_all_products', method: "POST", data: { v: 0 }, dataType: "script"
  134. }).done(function (res) {
  135. var html = res.match(/(?<=html = \$\(')[\s\S]+(?='\);[\s\S]+var groupeesRe)/);
  136. var div = document.createElement('DIV');
  137. html = html[0].replace(/\\n/g, "").replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\//g, "/");
  138. div.innerHTML = html;
  139. revealKey(div);
  140. output.value += 'Revealed 包 id ' + bun.id + ' ' + bun.bundle_name + '\n';
  141.  
  142. setTimeout(() => {
  143. if (generator2.next().done == true) {
  144. page++;
  145. getNextPageBundle(2);
  146. }
  147. }, 5000);
  148. });
  149. }
  150. }
  151.  
  152. function revealKey(div) {
  153. var items = div.querySelectorAll('.product');
  154. for (var item of items) {
  155. var name = item.querySelector('.product-name').innerText;
  156. var keys_rows = item.querySelectorAll('.col-sm-6.key');
  157. for (var row of keys_rows) {
  158. ajaxKey(name ,row);
  159. }
  160. }
  161. }
  162.  
  163. function ajaxKey(name ,row){
  164. if (row.querySelector('.unrevealed-group') && row.querySelector('.key-meta .green').innerText == 'Not revealed') {
  165. var type = row.querySelector('strong').innerText.replace(/^i/, "I");
  166. var key_id = row.getAttribute('data-id');
  167. $.ajax({ url: 'https://groupees.com/activation_codes/' + key_id + '/reveal', method: "POST"}).done(function (res) {
  168. output.value += name + ' ' + type + ' key: ' + res.code + '\n';
  169. });
  170. }
  171. }
  172.  
  173. document.querySelector('.pre-nav').insertAdjacentHTML('afterend', `
  174. <div>
  175. <input id="bun-id" type="text" placeholder="留空或输入 id 继续上次加载" style="width:200px;">
  176. <button id="run-script"type="button">运行备份脚本</button>
  177. <button id="excel-data" type="button">Excel 数据</button>
  178. <button id="reveal-all" type="button">刮开所有</button>
  179. <button id="download-links" type="button">下载输入链接</button>
  180. <textarea id="output-textarea" style="display:block; wide:100%;"></textarea>
  181. <div id="textarea-links"></div>
  182. <style>#textarea-links a{display:block;}</style>
  183. </div>
  184. `);
  185.  
  186. document.querySelector('#run-script').addEventListener('click', () => {
  187. output = document.querySelector('#output-textarea');
  188. output.value = '加载中\n';
  189. page = 1, all = [];
  190. id = document.querySelector('#bun-id').value;
  191. id = id == "" ? false : parseInt(id, 10);
  192. getNextPageBundle(1);
  193. });
  194.  
  195. document.querySelector('#excel-data').addEventListener('click', () => {
  196. toExcel();
  197. });
  198.  
  199. document.querySelector('#reveal-all').addEventListener('click', () => {
  200. output = document.querySelector('#output-textarea');
  201. output.value = '刮开中\n';
  202. page = 1;
  203. getNextPageBundle(2);
  204. });
  205.  
  206. document.querySelector('#download-links').addEventListener('click',()=>{
  207. var value = document.querySelector('#output-textarea').value;
  208. if (!value.match(/^https:\/\/storage\.groupees\.com/)){
  209. document.querySelector('#output-textarea').value = '请输入下载链接,一行一条。';
  210. } else {
  211. var links = value.split('\n');
  212. var html = '';
  213. for (var link of links) {
  214. if (link.match(/storage\.groupees\.com/)){
  215. html += `<a href="${link}">${link}</a>`;
  216. }
  217. }
  218. document.querySelector('#textarea-links').innerHTML = html;
  219. // $('#textarea-links a').each(function (t, e) { return setTimeout(function () { return e.click() }, 1500 * t); });
  220. }
  221. });
  222. })();