IsThereAnyDeal.com Collection Importer

Adds buttons to various sites to export your game lists to ITAD

  1. // Generated by CoffeeScript 1.7.1
  2.  
  3. /* IsThereAnyDeal.com Collection Importer
  4. // ==UserScript==
  5. // @name IsThereAnyDeal.com Collection Importer
  6. // @version 0.1b18
  7. // @namespace http://isthereanydeal.com/
  8. // @description Adds buttons to various sites to export your game lists to ITAD
  9. // @icon http://s3-eu-west-1.amazonaws.com/itad/images/banners/50x50.gif
  10. // @license MIT
  11. // @supportURL https://github.com/ssokolow/itad_importer/issues
  12. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js
  13. //
  14. // @match *://fireflowergames.com/my-account*
  15. // @match *://fireflowergames.com/my-lists/*
  16. // @match *://flyingbundle.com/users/account*
  17. // @match *://www.flyingbundle.com/users/account*
  18. // @match *://www.gog.com/account*
  19. // @match *://www.gog.com/order/status/*
  20. // @match *://groupees.com/purchases*
  21. // @match *://groupees.com/users/*
  22. // @match *://www.humblebundle.com/home*
  23. // @match *://www.humblebundle.com/downloads?key=*
  24. // @match *://www.humblebundle.com/s?key=*
  25. // ==/UserScript==
  26.  
  27. Any patches to this script should be made against the original
  28. CoffeeScript source file available (and documented) at:
  29.  
  30. https://github.com/ssokolow/itad_importer
  31.  
  32. Copyright ©2014-2018 Stephan Sokolow
  33. License: MIT (http://opensource.org/licenses/MIT)
  34.  
  35. TODO:
  36. - Add a `@downloadURL` for the script
  37. */
  38. var BUTTON_LABEL, ITAD_12X12, ITAD_14X14_GRAY, attr, gog_prepare_title, humble_make_button, humble_parse, scrapeGames, scrapers;
  39.  
  40. BUTTON_LABEL = "Export to ITAD";
  41.  
  42. ITAD_12X12 = "data:image/png;base64,\niVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAZlBMVEUEbrIEbrIJcbQLcrQefboo\ng70rhb4thr8vh78zicA6jcNCksVLl8hWnctZn8xdoc1ipM9ipc9kptB5stZ6staCt9mHutqJu9ud\nxuGozeSrz+W72OrA2+zJ4O7U5vLX6PPn8fj3+vyC0mvkAAAAAXRSTlMAQObYZgAAAFdJREFUCB0F\nwYkCgUAABcA3CpElRyRH6/9/0kwCQALtZSwNglN9Pt5LR+jqGuelEaYbeBXh04P7KMwDeF6E8l1h\nW1vh8PsO/bWeiGPdl/kzdYjdBkACQP5LygQ7CM8T6wAAAABJRU5ErkJggg==";
  43.  
  44. ITAD_14X14_GRAY = "data:image/png;base64,\niVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAAdVBMVEUEbrKTlaCTlZ+TlZ+UlqCY\nmaSYmqWcnqednqieoKmfoaugoqulprCvsLivsbiwsrmztLuztby2uL7BwsjDxcrExcvIyc7V1trW\n1trX2Nvn5+rp6evx8vP19fb39/j4+Pn5+fr7+/v7+/z8/Pz8/P39/f3///8J+FboAAAAJHRSTlMA\ny+rw8PHx8fHx8vLy9PT09PT19vf39/n5+fz8/f3+/v7+/v695LIzAAAAcUlEQVQIHQXBhwGCQAAE\nsHui2FHsBeyy/4gmSQGgJKWCeTNFVQJNN9yH2xJB+z3WZuf3kjDuD+B8I6wfIzAbpsLuCrg3QtsD\n9TAXJq8tOHYEl9+W0eHbEPaf06u/PvoWsXmuTNrdegwp1QJAVZICQMkf1qQG7Yh+Z60AAAAASUVO\nRK5CYII=";
  45.  
  46. this.$ = this.jQuery = jQuery.noConflict(true);
  47.  
  48. attr = function(node, name) {
  49. return node.getAttribute(name);
  50. };
  51.  
  52. gog_prepare_title = function(elem) {
  53. var dom;
  54. dom = $('.product-title', elem).clone();
  55. $('._product-flag', dom).remove();
  56. return dom.text();
  57. };
  58.  
  59. humble_make_button = function() {
  60. var a, button, label;
  61. label = $('<span class="label"></span>').html(BUTTON_LABEL);
  62. a = $('<a class="a" href="#"></span>').html(BUTTON_LABEL).css('padding-left', '9px');
  63. return button = $('<div class="flexbtn active noicon"></div>').append('<div class="right"></div>').append(label).append(a);
  64. };
  65.  
  66. humble_parse = function() {
  67. var x;
  68. return {
  69. version: "02",
  70. data: (function() {
  71. var _i, _len, _ref, _results;
  72. _ref = $('div.row').has(' .downloads.windows .download, .downloads.linux .download, .downloads.mac .download, .downloads.android .download').find('div.title');
  73. _results = [];
  74. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  75. x = _ref[_i];
  76. _results.push({
  77. title: x.textContent.trim(),
  78. copies: [
  79. {
  80. type: 'humblestore'
  81. }
  82. ]
  83. });
  84. }
  85. return _results;
  86. })()
  87. };
  88. };
  89.  
  90. scrapers = {
  91. 'fireflowergames.com': {
  92. '^https://fireflowergames\\.com/my-account/?': {
  93. 'source_id': 'fireflower',
  94. 'game_list': function() {
  95. var results, title, titles, uniques, x;
  96. results = $('ul.digital-downloads li a');
  97. titles = [
  98. (function() {
  99. var _i, _len, _results;
  100. _results = [];
  101. for (_i = 0, _len = results.length; _i < _len; _i++) {
  102. x = results[_i];
  103. _results.push($(x).text().split(" – ")[0].trim());
  104. }
  105. return _results;
  106. })()
  107. ][0];
  108. uniques = titles.filter(function(title, pos) {
  109. return titles.indexOf(title) === pos;
  110. });
  111. return {
  112. version: "02",
  113. data: (function() {
  114. var _i, _len, _results;
  115. _results = [];
  116. for (_i = 0, _len = uniques.length; _i < _len; _i++) {
  117. title = uniques[_i];
  118. _results.push({
  119. title: title,
  120. copies: [
  121. {
  122. type: 'fireflower',
  123. status: 'redeemed',
  124. owned: 1
  125. }
  126. ]
  127. });
  128. }
  129. return _results;
  130. })()
  131. };
  132. },
  133. 'insert_button': function() {
  134. return $('<a class="button"></a>').html(BUTTON_LABEL).css({
  135. verticalAlign: '20%',
  136. marginLeft: '1em'
  137. }).appendTo($('ul.digital-downloads').prev());
  138. }
  139. },
  140. '^http://fireflowergames\\.com/my-lists/(edit-my|view-a)-list/\\?.+': {
  141. 'source_id': 'fireflower',
  142. 'game_list': function() {
  143. var results, x;
  144. results = $('table.wl-table tbody td.check-column input:checked').parents('tr').find('td.product-name a');
  145. if (!results.length) {
  146. results = $('table.wl-table td.product-name a');
  147. }
  148. return {
  149. version: "02",
  150. data: (function() {
  151. var _i, _len, _results;
  152. _results = [];
  153. for (_i = 0, _len = results.length; _i < _len; _i++) {
  154. x = results[_i];
  155. _results.push({
  156. title: $(x).text().trim()
  157. });
  158. }
  159. return _results;
  160. })()
  161. };
  162. },
  163. 'insert_button': function() {
  164. return $('<a class="button"></a>').html(BUTTON_LABEL).wrap('<td></td>').appendTo($('table.wl-actions-table tbody:first').find('tr:last'));
  165. },
  166. 'is_wishlist': true
  167. }
  168. },
  169. 'flyingbundle.com': {
  170. 'https?://(www\\.)?flyingbundle\\.com/users/account#?': {
  171. 'source_id': 'flying_bundle',
  172. 'game_list': function() {
  173. var x;
  174. return {
  175. version: "02",
  176. data: (function() {
  177. var _i, _len, _ref, _results;
  178. _ref = $(".div_btn_download[href^='/users/sources']").parents('li').find(':first');
  179. _results = [];
  180. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  181. x = _ref[_i];
  182. _results.push({
  183. title: $(x).text(),
  184. copies: [
  185. {
  186. type: 'Flying Bundle',
  187. status: 'redeemed',
  188. owned: 1,
  189. source: {
  190. type: "s",
  191. id: "other"
  192. }
  193. }
  194. ]
  195. });
  196. }
  197. return _results;
  198. })()
  199. };
  200. },
  201. 'insert_button': function() {
  202. var li;
  203. li = $("<li></li>").appendTo('.legenda_points ul');
  204. return $('<a href="#">' + BUTTON_LABEL + ' <img src="' + ITAD_14X14_GRAY + '" /></a>').css('text-transform', 'uppercase').wrap("<li></li>").appendTo(li);
  205. }
  206. }
  207. },
  208. 'www.gog.com': {
  209. '^https://www\\.gog\\.com/order/status/.+': {
  210. 'source_id': 'gog',
  211. 'game_list': function() {
  212. var x;
  213. console.debug("game_list called for GOG order status page");
  214. return {
  215. "version": "02",
  216. "data": (function() {
  217. var _i, _len, _ref, _results;
  218. _ref = $('.order + .container .product-row');
  219. _results = [];
  220. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  221. x = _ref[_i];
  222. _results.push({
  223. title: gog_prepare_title(x),
  224. copies: [
  225. {
  226. type: 'gog',
  227. status: 'redeemed',
  228. owned: 1
  229. }
  230. ]
  231. });
  232. }
  233. return _results;
  234. })()
  235. };
  236. },
  237. 'insert_button': function() {
  238. console.debug("insert_button called for GOG order status page");
  239. $(".order-article__btn-pointer-wrapper .order-article__btn-pointer").css({
  240. marginTop: -4,
  241. zIndex: 20
  242. });
  243. $('.order-article__dropdown-items').css('z-index', 10);
  244. return $("<a class='_dropdown__item ng-scope'></a>").html("On ITAD").prependTo($('.order-message__actions ._dropdown__items').filter(':first'));
  245. }
  246. },
  247. '^https?://www\\.gog\\.com/account(/games(/(shelf|list))?)?/?(\\?|$)': {
  248. 'source_id': 'gog',
  249. 'game_list': function() {
  250. var x;
  251. console.debug("game_list called for GOG collection page");
  252. return {
  253. "version": "02",
  254. "data": (function() {
  255. var _i, _len, _ref, _results;
  256. _ref = $('.product-row');
  257. _results = [];
  258. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  259. x = _ref[_i];
  260. _results.push({
  261. title: gog_prepare_title(x),
  262. copies: [
  263. {
  264. type: 'gog',
  265. status: 'redeemed',
  266. owned: 1
  267. }
  268. ]
  269. });
  270. }
  271. return _results;
  272. })()
  273. };
  274. },
  275. 'insert_button': function() {
  276. console.debug("insert_button called for GOG collection page");
  277. return $("<span></span>").css({
  278. float: 'right',
  279. cursor: 'pointer',
  280. position: 'relative',
  281. marginBottom: '-2em',
  282. zIndex: 1
  283. }).html(BUTTON_LABEL + " (This Page)").prependTo($('.collection-header').filter(':first'));
  284. }
  285. }
  286. },
  287. 'groupees.com': {
  288. 'https?://(www\\.)?groupees\\.com/(purchases|users/\\d+)': {
  289. 'source_id': 'other',
  290. 'game_list': function() {
  291. var x;
  292. return {
  293. "version": "02",
  294. "data": (function() {
  295. var _i, _len, _ref, _results;
  296. _ref = $('.product ul.dropdown-menu').parents('.details').find('h3');
  297. _results = [];
  298. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  299. x = _ref[_i];
  300. _results.push({
  301. title: x.textContent.trim(),
  302. copies: [
  303. {
  304. type: 'Groupees.com',
  305. status: 'redeemed',
  306. owned: 1,
  307. source: {
  308. type: "s",
  309. id: "other"
  310. }
  311. }
  312. ]
  313. });
  314. }
  315. return _results;
  316. })()
  317. };
  318. },
  319. 'insert_button': function() {
  320. return $("<button></button>").css({
  321. float: 'right'
  322. }).addClass('button btn btn-sm btn-primary').html(BUTTON_LABEL + " (Selected Bundle)").insertBefore("input[name='search']");
  323. }
  324. }
  325. },
  326. 'www.humblebundle.com': {
  327. 'https://www\\.humblebundle\\.com/home/library/?': {
  328. 'source_id': 'humblestore',
  329. 'game_list': function() {
  330. var x;
  331. return {
  332. "version": "02",
  333. "data": (function() {
  334. var _i, _len, _ref, _results;
  335. _ref = $('.subproduct-selector h2');
  336. _results = [];
  337. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  338. x = _ref[_i];
  339. _results.push({
  340. title: x.textContent.trim(),
  341. copies: [
  342. {
  343. type: 'humblestore',
  344. status: 'redeemed',
  345. owned: 1
  346. }
  347. ]
  348. });
  349. }
  350. return _results;
  351. })()
  352. };
  353. },
  354. 'insert_button': function() {
  355. var button, config, found_early, observer;
  356. config = {
  357. childList: true,
  358. subtree: true
  359. };
  360. button = $('<button class="download-button"></button>').html(BUTTON_LABEL).css({
  361. display: 'inline',
  362. border: '1px solid #CCC',
  363. background: '#F1F3F6',
  364. padding: '5px 10px 5px 10px',
  365. marginLeft: '10px'
  366. });
  367. found_early = $(".top-controls");
  368. if (found_early.length > 0) {
  369. console.log("Inserting button immediately.");
  370. button.appendTo(found_early);
  371. } else {
  372. console.log("Using MutationObserver for deferred button insertion.");
  373. observer = new MutationObserver(function(mutations) {
  374. return mutations.forEach(function(mutation) {
  375. var found, tnode_cls;
  376. tnode_cls = mutation.target.getAttribute("class");
  377. found = $(".top-controls", mutation.target);
  378. if (found.length > 0) {
  379. observer.disconnect();
  380. return button.appendTo(found);
  381. }
  382. });
  383. });
  384. observer.observe(document.querySelector('.js-library-holder'), config);
  385. }
  386. return button;
  387. }
  388. },
  389. 'https://www\\.humblebundle\\.com/home/?': {
  390. 'source_id': 'humblestore',
  391. 'game_list': humble_parse,
  392. 'insert_button': function() {
  393. return humble_make_button().css({
  394. float: 'right',
  395. fontSize: '14px',
  396. fontWeight: 'normal'
  397. }).prependTo('.base-main-wrapper h1');
  398. }
  399. },
  400. 'https://www\\.humblebundle\\.com/(download)?s\\?key=.+': {
  401. 'source_id': 'humblestore',
  402. 'game_list': humble_parse,
  403. 'insert_button': function() {
  404. var parent;
  405. parent = $('.js-gamelist-holder').parents('.whitebox');
  406. parent.find('.staple.s4').remove();
  407. return humble_make_button().css({
  408. position: 'absolute',
  409. top: 11,
  410. right: 17
  411. }).appendTo(parent);
  412. }
  413. }
  414. }
  415. };
  416.  
  417. scrapers['www.flyingbundle.com'] = scrapers['flyingbundle.com'];
  418.  
  419. scrapers['www.groupees.com'] = scrapers['groupees.com'];
  420.  
  421. scrapeGames = function(scraper_obj) {
  422. var form, params, url;
  423. params = {
  424. file: btoa(unescape(encodeURIComponent(JSON.stringify(scraper_obj.game_list())))),
  425. upload: 'x'
  426. };
  427. url = scraper_obj.is_wishlist != null ? 'https://isthereanydeal.com/waitlist/import/' : 'https://isthereanydeal.com/collection/import/';
  428. form = $("<form id='itad_submitter' method='POST' />").attr('action', url);
  429. params['returnTo'] = location.href;
  430. form.css({
  431. display: 'none'
  432. });
  433. $.each(params, function(key, value) {
  434. return $("<input type='hidden' />").attr("name", key).attr("value", value).appendTo(form);
  435. });
  436. $(document.body).append(form);
  437. return form.submit();
  438. };
  439.  
  440. $(function() {
  441. var e, profile, profile_matched, regex, scraper, _fn, _i, _len, _ref, _results;
  442. console.log("Loading ITAD importer...");
  443. if (scrapers[location.host]) {
  444. console.log("Matched domain: " + location.host);
  445. _ref = scrapers[location.host];
  446. _results = [];
  447. for (regex in _ref) {
  448. profile = _ref[regex];
  449. try {
  450. profile_matched = location.href.match(regex);
  451. } catch (_error) {
  452. e = _error;
  453. console.error("Bad regex: " + regex);
  454. }
  455. if (profile_matched) {
  456. console.log("Matched profile: " + regex);
  457. $('.itad_btn, #itad_dlg, .itad_close').remove();
  458. if (!Array.isArray(profile)) {
  459. profile = [profile];
  460. }
  461. _fn = function(scraper) {
  462. console.log("Inserting ITAD button for source ID: " + scraper.source_id);
  463. return typeof scraper.insert_button === "function" ? scraper.insert_button().addClass('itad_btn').click(function() {
  464. console.log("ITAD button clicked");
  465. return scrapeGames(scraper);
  466. }) : void 0;
  467. };
  468. for (_i = 0, _len = profile.length; _i < _len; _i++) {
  469. scraper = profile[_i];
  470. _fn(scraper);
  471. }
  472. break;
  473. } else {
  474. _results.push(void 0);
  475. }
  476. }
  477. return _results;
  478. }
  479. });