IsThereAnyDeal.com Collection Importer

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

目前為 2015-11-14 提交的版本,檢視 最新版本

  1. // Generated by CoffeeScript 1.8.0
  2.  
  3. /* IsThereAnyDeal.com Collection Importer
  4.  
  5. Any patches to this script should be made against the original
  6. CoffeeScript source file available (and documented) at:
  7.  
  8. https://github.com/ssokolow/itad_importer
  9.  
  10. Copyright ©2014-2015 Stephan Sokolow
  11. License: MIT (http://opensource.org/licenses/MIT)
  12.  
  13. TODO:
  14. - Add a `@downloadURL` for the script
  15.  
  16. Note: While we do not use GM_info, we must request it to force the userscript
  17. to be isolated from the page so its jQuery doesn't collide with the site's
  18. jQuery.
  19.  
  20. // ==UserScript==
  21. // @name IsThereAnyDeal.com Collection Importer
  22. // @version 0.1b12
  23. // @namespace http://isthereanydeal.com/
  24. // @description Adds buttons to various sites to export your game lists to ITAD
  25. // @icon http://s3-eu-west-1.amazonaws.com/itad/images/banners/50x50.gif
  26. // @license MIT
  27. // @supportURL https://github.com/ssokolow/itad_importer/issues
  28. // @grant GM_info
  29. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js
  30. //
  31. // @match *://www.dotemu.com/*
  32. // @match *://fireflowergames.com/my-lists/*
  33. // @match *://flyingbundle.com/users/account
  34. // @match *://www.flyingbundle.com/users/account
  35. // @match *://www.gog.com/account*
  36. // @match *://www.gog.com/order/status/*
  37. // @match *://groupees.com/purchases
  38. // @match *://groupees.com/users/*
  39. // @match *://www.humblebundle.com/home*
  40. // @match *://www.humblebundle.com/downloads?key=*
  41. // @match *://www.humblebundle.com/s?key=*
  42. // @match *://indiegamestand.com/wallet.php
  43. // @match *://indiegamestand.com/wishlist.php
  44. // @match *://www.shinyloot.com/m/games*
  45. // @match *://www.shinyloot.com/m/wishlist*
  46. // ==/UserScript==
  47. */
  48. var BUTTON_LABEL, ITAD_12X12, ITAD_14X14_GRAY, attr, dotemu_add_button, gog_prepare_title, humble_make_button, humble_parse, scrapers, shinyloot_insert_button, titlecase_cb, underscore_re, word_re;
  49.  
  50. BUTTON_LABEL = "Export to ITAD";
  51.  
  52. ITAD_12X12 = "data:image/png;base64,\niVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAZlBMVEUEbrIEbrIJcbQLcrQefboo\ng70rhb4thr8vh78zicA6jcNCksVLl8hWnctZn8xdoc1ipM9ipc9kptB5stZ6staCt9mHutqJu9ud\nxuGozeSrz+W72OrA2+zJ4O7U5vLX6PPn8fj3+vyC0mvkAAAAAXRSTlMAQObYZgAAAFdJREFUCB0F\nwYkCgUAABcA3CpElRyRH6/9/0kwCQALtZSwNglN9Pt5LR+jqGuelEaYbeBXh04P7KMwDeF6E8l1h\nW1vh8PsO/bWeiGPdl/kzdYjdBkACQP5LygQ7CM8T6wAAAABJRU5ErkJggg==";
  53.  
  54. 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=";
  55.  
  56. underscore_re = /_/g;
  57.  
  58. word_re = /\b\w+/g;
  59.  
  60. titlecase_cb = function(s) {
  61. return s.charAt(0).toUpperCase() + s.substr(1).toLowerCase();
  62. };
  63.  
  64. attr = function(node, name) {
  65. return node.getAttribute(name);
  66. };
  67.  
  68. dotemu_add_button = function(parent_selector) {
  69. return $('<button></button>').html(BUTTON_LABEL).css({
  70. float: 'right',
  71. marginRight: '5px'
  72. }).appendTo(parent_selector);
  73. };
  74.  
  75. gog_prepare_title = function(elem) {
  76. var dom;
  77. dom = $('.product-title', elem).clone();
  78. $('._product-flag', dom).remove();
  79. return dom.text();
  80. };
  81.  
  82. humble_make_button = function() {
  83. var a, button, label;
  84. label = $('<span class="label"></span>').html(BUTTON_LABEL);
  85. a = $('<a class="a" href="#"></span>').html(BUTTON_LABEL).css('padding-left', '9px');
  86. return button = $('<div class="flexbtn active noicon"></div>').append('<div class="right"></div>').append(label).append(a);
  87. };
  88.  
  89. humble_parse = function() {
  90. var x, _i, _len, _ref, _results;
  91. _ref = $('div.row').has(' .downloads.windows .download, .downloads.linux .download, .downloads.mac .download, .downloads.android .download').find('div.title');
  92. _results = [];
  93. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  94. x = _ref[_i];
  95. _results.push({
  96. title: x.textContent.trim(),
  97. sources: ['humblestore']
  98. });
  99. }
  100. return _results;
  101. };
  102.  
  103. shinyloot_insert_button = function() {
  104. return $('<button></button>').html(BUTTON_LABEL).css({
  105. background: 'url("/images/filters/sort-background-inactive.png") ' + 'repeat-x scroll 0% 0% transparent',
  106. border: '1px solid #666',
  107. borderRadius: '2px',
  108. boxShadow: '0px 1px 6px #777',
  109. color: '#222',
  110. fontSize: '12px',
  111. fontWeight: 'bold',
  112. fontFamily: 'Arial,Helvetica,Sans-serif',
  113. float: 'right',
  114. padding: '2px 8px',
  115. marginRight: '-6px',
  116. verticalAlign: 'middle'
  117. }).appendTo('#content .header');
  118. };
  119.  
  120. scrapers = {
  121. 'www.dotemu.com': {
  122. 'https://www\\.dotemu\\.com/(en|fr|es)/user/?': [
  123. {
  124. 'source_id': 'dotemu',
  125. 'game_list': function() {
  126. var x, _i, _len, _ref, _results;
  127. _ref = $('div.my-games div.field-title a');
  128. _results = [];
  129. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  130. x = _ref[_i];
  131. _results.push({
  132. title: attr(x, 'title'),
  133. url: x.href,
  134. sources: ['dotemu']
  135. });
  136. }
  137. return _results;
  138. },
  139. 'insert_button': function() {
  140. return dotemu_add_button('div.my-games h2.pane-title');
  141. }
  142. }, {
  143. 'source_id': 'dotemu',
  144. 'game_list': function() {
  145. var x, _i, _len, _ref, _results;
  146. _ref = $('div.user-wishlist .views-field-title-1 a');
  147. _results = [];
  148. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  149. x = _ref[_i];
  150. _results.push({
  151. title: attr(x, 'title'),
  152. url: x.href,
  153. sources: ['dotemu']
  154. });
  155. }
  156. return _results;
  157. },
  158. 'insert_button': function() {
  159. return dotemu_add_button('.user-wishlist h2.pane-title');
  160. },
  161. 'is_wishlist': true
  162. }
  163. ]
  164. },
  165. 'fireflowergames.com': {
  166. '^http://fireflowergames\\.com/my-lists/(edit-my|view-a)-list/\\?.+': {
  167. 'source_id': 'fireflower',
  168. 'game_list': function() {
  169. var results, x, _i, _len, _results;
  170. results = $('table.wl-table tbody td.check-column input:checked').parents('tr').find('td.product-name a');
  171. if (!results.length) {
  172. results = $('table.wl-table td.product-name a');
  173. }
  174. _results = [];
  175. for (_i = 0, _len = results.length; _i < _len; _i++) {
  176. x = results[_i];
  177. _results.push({
  178. title: $(x).text().trim(),
  179. url: x.href,
  180. sources: ['fireflower']
  181. });
  182. }
  183. return _results;
  184. },
  185. 'insert_button': function() {
  186. return $('<a class="button"></a>').html(BUTTON_LABEL).wrap('<td></td>').appendTo($('table.wl-actions-table tbody:first').find('tr:last'));
  187. },
  188. 'is_wishlist': true
  189. }
  190. },
  191. 'flyingbundle.com': {
  192. 'https?://(www\\.)?flyingbundle\\.com/users/account': {
  193. 'source_id': 'flying_bundle',
  194. 'game_list': function() {
  195. var x, _i, _len, _ref, _results;
  196. _ref = $(".div_btn_download[href^='/users/sources']").parents('li').find(':first');
  197. _results = [];
  198. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  199. x = _ref[_i];
  200. _results.push({
  201. title: $(x).text(),
  202. sources: 'flying_bundle'
  203. });
  204. }
  205. return _results;
  206. },
  207. 'insert_button': function() {
  208. var li;
  209. li = $("<li></li>").appendTo('.legenda_points ul');
  210. return $('<a href="#">' + BUTTON_LABEL + ' <img src="' + ITAD_14X14_GRAY + '" /></a>').css('text-transform', 'uppercase').wrap("<li></li>").appendTo(li);
  211. }
  212. }
  213. },
  214. 'www.gog.com': {
  215. '^https://www\\.gog\\.com/order/status/.+': {
  216. 'source_id': 'gog',
  217. 'game_list': function() {
  218. var x, _i, _len, _ref, _results;
  219. console.debug("game_list called for GOG order status page");
  220. _ref = $('.order__hero-unit ul.summary-list li');
  221. _results = [];
  222. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  223. x = _ref[_i];
  224. _results.push({
  225. title: $(x).text().trim(),
  226. sources: ['gog']
  227. });
  228. }
  229. return _results;
  230. },
  231. 'insert_button': function() {
  232. console.debug("insert_button called for GOG order status page");
  233. return $("<a class='_dropdown__item ng-scope'></a>").html("On ITAD").prependTo($('.order-message__actions ._dropdown__items').filter(':first'));
  234. }
  235. },
  236. '^https?://www\\.gog\\.com/account(/games(/(shelf|list))?)?/?(\\?|$)': {
  237. 'source_id': 'gog',
  238. 'game_list': function() {
  239. var x, _i, _len, _ref, _results;
  240. console.debug("game_list called for GOG collection page");
  241. _ref = $('.product-row');
  242. _results = [];
  243. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  244. x = _ref[_i];
  245. _results.push({
  246. id: attr(x, 'gog-product'),
  247. title: gog_prepare_title(x),
  248. sources: ['gog']
  249. });
  250. }
  251. return _results;
  252. },
  253. 'insert_button': function() {
  254. console.debug("insert_button called for GOG collection page");
  255. return $("<span></span>").css({
  256. float: 'right',
  257. cursor: 'pointer',
  258. position: 'relative',
  259. marginBottom: '-2em',
  260. zIndex: 1
  261. }).html(BUTTON_LABEL + " (This Page)").prependTo($('.collection-header').filter(':first'));
  262. }
  263. }
  264. },
  265. 'groupees.com': {
  266. 'https?://(www\\.)?groupees\\.com/(purchases|users/\\d+)': {
  267. 'source_id': 'other',
  268. 'game_list': function() {
  269. var x, _i, _len, _ref, _results;
  270. _ref = $('.product ul.dropdown-menu').parents('.details').find('h3');
  271. _results = [];
  272. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  273. x = _ref[_i];
  274. _results.push({
  275. title: x.textContent.trim(),
  276. sources: ['other']
  277. });
  278. }
  279. return _results;
  280. },
  281. 'insert_button': function() {
  282. return $("<button></button>").css({
  283. float: 'right'
  284. }).addClass('button btn btn-sm btn-primary').html(BUTTON_LABEL + " (Selected Bundle)").insertBefore("input[name='search']");
  285. }
  286. }
  287. },
  288. 'www.humblebundle.com': {
  289. 'https://www\\.humblebundle\\.com/home/library/?': {
  290. 'source_id': 'humblestore',
  291. 'game_list': function() {
  292. var x, _i, _len, _ref, _results;
  293. _ref = $('.subproduct-selector h2');
  294. _results = [];
  295. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  296. x = _ref[_i];
  297. _results.push({
  298. title: x.textContent.trim(),
  299. sources: ['humblestore']
  300. });
  301. }
  302. return _results;
  303. },
  304. 'insert_button': function() {
  305. var button, config, found_early, observer;
  306. config = {
  307. childList: true,
  308. subtree: true
  309. };
  310. button = $('<button class="download-button"></button>').html(BUTTON_LABEL).css({
  311. display: 'inline',
  312. border: '1px solid #CCC',
  313. background: '#F1F3F6',
  314. padding: '5px 10px 5px 10px',
  315. marginLeft: '10px'
  316. });
  317. found_early = $(".top-controls");
  318. if (found_early.length > 0) {
  319. console.log("Inserting button immediately.");
  320. button.appendTo(found_early);
  321. } else {
  322. console.log("Using MutationObserver for deferred button insertion.");
  323. observer = new MutationObserver(function(mutations) {
  324. return mutations.forEach(function(mutation) {
  325. var found, tnode_cls;
  326. tnode_cls = mutation.target.getAttribute("class");
  327. found = $(".top-controls", mutation.target);
  328. if (found.length > 0) {
  329. observer.disconnect();
  330. return button.appendTo(found);
  331. }
  332. });
  333. });
  334. observer.observe(document.querySelector('.js-library-holder'), config);
  335. }
  336. return button;
  337. }
  338. },
  339. 'https://www\\.humblebundle\\.com/home/?': {
  340. 'source_id': 'humblestore',
  341. 'game_list': humble_parse,
  342. 'insert_button': function() {
  343. return humble_make_button().css({
  344. float: 'right',
  345. fontSize: '14px',
  346. fontWeight: 'normal'
  347. }).prependTo('.base-main-wrapper h1');
  348. }
  349. },
  350. 'https://www\\.humblebundle\\.com/(download)?s\\?key=.+': {
  351. 'source_id': 'humblestore',
  352. 'game_list': humble_parse,
  353. 'insert_button': function() {
  354. var parent;
  355. parent = $('.js-gamelist-holder').parents('.whitebox');
  356. parent.find('.staple.s4').remove();
  357. return humble_make_button().css({
  358. position: 'absolute',
  359. top: 11,
  360. right: 17
  361. }).appendTo(parent);
  362. }
  363. }
  364. },
  365. 'indiegamestand.com': {
  366. 'https://indiegamestand\\.com/wallet\\.php': {
  367. 'source_id': 'indiegamestand',
  368. 'game_list': function() {
  369. var x, _i, _len, _ref, _ref1, _ref2, _ref3, _results;
  370. _ref = $('#wallet_contents .line-item');
  371. _results = [];
  372. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  373. x = _ref[_i];
  374. _results.push({
  375. url: (_ref1 = $('.game-thumb', x)) != null ? (_ref2 = _ref1.closest('a')) != null ? (_ref3 = _ref2[0]) != null ? _ref3.href : void 0 : void 0 : void 0,
  376. title: $('.game-title', x).text().trim(),
  377. sources: ['indiegamestand']
  378. });
  379. }
  380. return _results;
  381. },
  382. 'insert_button': function() {
  383. return $('<div class="request key"></div>').html(BUTTON_LABEL).wrapInner("<div></div>").css({
  384. display: 'inline-block',
  385. marginLeft: '1em',
  386. verticalAlign: 'middle'
  387. }).appendTo('#game_wallet h2');
  388. }
  389. },
  390. 'https://indiegamestand\\.com/wishlist\\.php': {
  391. 'source_id': 'indiegamestand',
  392. 'game_list': function() {
  393. var x, _i, _len, _ref, _ref1, _ref2, _ref3, _results;
  394. _ref = $('#store_browse_game_list .game_list_item');
  395. _results = [];
  396. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  397. x = _ref[_i];
  398. _results.push({
  399. url: (_ref1 = $('.game-thumb', x)) != null ? (_ref2 = _ref1.closest('a')) != null ? (_ref3 = _ref2[0]) != null ? _ref3.href : void 0 : void 0 : void 0,
  400. title: $('.game_details h3', x).text().trim(),
  401. sources: ['indiegamestand']
  402. });
  403. }
  404. return _results;
  405. },
  406. 'is_wishlist': true,
  407. 'insert_button': function() {
  408. var innerDiv;
  409. innerDiv = $("<div></div>").css({
  410. paddingLeft: '10px',
  411. background: 'url("images/icon-arrow.png") no-repeat scroll ' + '155px 45% transparent'
  412. });
  413. return $('<div class="request key"></div>').html(BUTTON_LABEL).wrapInner(innerDiv).css({
  414. display: 'inline-block',
  415. verticalAlign: 'middle',
  416. float: 'right',
  417. width: '170px',
  418. height: '21px',
  419. background: 'url("images/btn-bg-blue-longer.png") ' + 'no-repeat scroll 0px 0px transparent',
  420. lineHeight: '21px',
  421. color: '#FFF',
  422. whiteSpace: 'nowrap',
  423. marginLeft: '1em',
  424. marginBottom: '4px',
  425. fontSize: '12px',
  426. cursor: 'pointer'
  427. }).css({
  428. margin: '11px 5px auto auto'
  429. }).appendTo('#store_browse_game_list .header');
  430. }
  431. }
  432. },
  433. 'www.shinyloot.com': {
  434. 'https?://www\\.shinyloot\\.com/m/games/?': {
  435. 'source_id': 'shinyloot',
  436. 'game_list': function() {
  437. var x, _i, _len, _ref, _results;
  438. _ref = $('#accordion .ui-widget-content');
  439. _results = [];
  440. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  441. x = _ref[_i];
  442. _results.push({
  443. url: $('.right-float a img', x).closest('a')[0].href,
  444. title: $(x).prev('h3').text().trim(),
  445. sources: ['shinyloot']
  446. });
  447. }
  448. return _results;
  449. },
  450. 'insert_button': shinyloot_insert_button
  451. },
  452. 'https?://www\\.shinyloot\\.com/m/wishlist/?': {
  453. 'source_id': 'shinyloot',
  454. 'game_list': function() {
  455. var x, _i, _len, _ref, _results;
  456. _ref = $('.gameItem');
  457. _results = [];
  458. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  459. x = _ref[_i];
  460. _results.push({
  461. url: $('.gameInfo + a', x)[0].href,
  462. title: $('.gameName', x).text().trim()
  463. });
  464. }
  465. return _results;
  466. },
  467. 'insert_button': shinyloot_insert_button,
  468. 'is_wishlist': true
  469. }
  470. }
  471. };
  472.  
  473. scrapers['www.flyingbundle.com'] = scrapers['flyingbundle.com'];
  474.  
  475. scrapers['www.groupees.com'] = scrapers['groupees.com'].scrapeGames = function(scraper_obj) {
  476. var form, params, url;
  477. params = {
  478. json: JSON.stringify(scraper_obj.game_list()),
  479. source: scraper_obj.source_id
  480. };
  481. url = scraper_obj.is_wishlist != null ? 'https://isthereanydeal.com/outside/user/wait/3rdparty' : 'https://isthereanydeal.com/outside/user/collection/3rdparty';
  482. form = $("<form id='itad_submitter' method='POST' />").attr('action', url);
  483. params['returnTo'] = location.href;
  484. form.css({
  485. display: 'none'
  486. });
  487. $.each(params, function(key, value) {
  488. return $("<input type='hidden' />").attr("name", key).attr("value", value).appendTo(form);
  489. });
  490. $(document.body).append(form);
  491. return form.submit();
  492. };
  493.  
  494. $(function() {
  495. var e, profile, profile_matched, regex, scraper, _fn, _i, _len, _ref, _results;
  496. console.log("Loading ITAD importer...");
  497. if (scrapers[location.host]) {
  498. console.log("Matched domain: " + location.host);
  499. _ref = scrapers[location.host];
  500. _results = [];
  501. for (regex in _ref) {
  502. profile = _ref[regex];
  503. try {
  504. profile_matched = location.href.match(regex);
  505. } catch (_error) {
  506. e = _error;
  507. console.error("Bad regex: " + regex);
  508. }
  509. if (profile_matched) {
  510. console.log("Matched profile: " + regex);
  511. $('.itad_btn, #itad_dlg, .itad_close').remove();
  512. if (!Array.isArray(profile)) {
  513. profile = [profile];
  514. }
  515. _fn = function(scraper) {
  516. console.log("Inserting ITAD button for source ID: " + scraper.source_id);
  517. return typeof scraper.insert_button === "function" ? scraper.insert_button().addClass('itad_btn').click(function() {
  518. console.log("ITAD button clicked");
  519. return scrapeGames(scraper);
  520. }) : void 0;
  521. };
  522. for (_i = 0, _len = profile.length; _i < _len; _i++) {
  523. scraper = profile[_i];
  524. _fn(scraper);
  525. }
  526. break;
  527. } else {
  528. _results.push(void 0);
  529. }
  530. }
  531. return _results;
  532. }
  533. });