SG Game Tags

Shows some tags of the game in Steamgifts.

目前为 2016-04-13 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name SG Game Tags
  3. // @namespace http://steamcommunity.com/id/Ruphine/
  4. // @version 2.9
  5. // @description Shows some tags of the game in Steamgifts.
  6. // @author Ruphine
  7.  
  8. // @match http://www.steamgifts.com/*
  9. // @connect store.steampowered.com
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
  11. // @grant GM_deleteValue
  12. // @grant GM_getValue
  13. // @grant GM_listValues
  14. // @grant GM_setValue
  15. // @grant GM_xmlhttpRequest
  16. // ==/UserScript==
  17.  
  18. /* CSS */
  19. var myCSS;
  20. myCSS = '<style> \
  21. .tags { \
  22. color: #FFFFFF; \
  23. text-decoration: none; \
  24. border-radius: 4px; \
  25. padding-top: 2px; \
  26. padding-bottom: 2px; \
  27. padding-left: 5px; \
  28. padding-right: 5px; \
  29. font-size: 8pt; \
  30. margin-right: 3px; \
  31. margin-bottom: 3px; \
  32. margin-top: 3px; \
  33. text-shadow: none; \
  34. display: none; \
  35. } \
  36. .tags-green { background-color: #3AA435; } \
  37. .tags-red { background-color: #E9202A; } \
  38. .tags-blue { background-color: #305AC9; } \
  39. .tags-purple { background-color: #6600CC; } \
  40. .tags-brown { background-color: #A0522D; } \
  41. .my__checkbox { \
  42. cursor:pointer; \
  43. padding:7px 0 \
  44. } \
  45. .my__checkbox i { \
  46. margin-right:7px \
  47. } \
  48. .my__checkbox:not(:last-of-type) { \
  49. border-bottom:1px dotted #d2d6e0 \
  50. } \
  51. .my__checkbox:not(:hover) .form__checkbox__hover,.my__checkbox.is-selected .form__checkbox__hover,.my__checkbox:not(.is-selected) .form__checkbox__selected,.my__checkbox:hover .form__checkbox__default,.my__checkbox.is-selected .form__checkbox__default { \
  52. display:none \
  53. } \
  54. </style>';
  55.  
  56. $("head").append(myCSS);
  57.  
  58.  
  59. /* Constant Variables */
  60. const linkCard = "http://www.steamcardexchange.net/index.php?inventorygame-appid-";
  61. const linkAchievement = "http://steamcommunity.com/stats/"; // 424280/achievements/";
  62. const linkBundle = "http://www.steamgifts.com/bundle-games/search?q=";
  63. const linkHidden = "http://www.steamgifts.com/account/settings/giveaways/filters/search?q=";
  64. const linkWishlist = "http://www.steamgifts.com/account/steam/wishlist/search?q=";
  65.  
  66. const linkGameAPI = "http://store.steampowered.com/api/appdetails?filters=categories&appids=";
  67. const linkPackAPI = "http://store.steampowered.com/api/packagedetails?filters=categories&packageids=";
  68.  
  69. const ClassCard = "tags tags-green";
  70. const TitleCard = "This game has trading cards";
  71. const TextCard = "Trading Cards";
  72.  
  73. const ClassBundle = "tags tags-red";
  74. const TitleBundle = "This game is marked as bundled by Steamgifts";
  75. const TextBundle = "Bundled";
  76.  
  77. const ClassAchievement = "tags tags-blue";
  78. const TitleAchievement = "This game has steam achievements";
  79. const TextAchievement = "Achievements";
  80.  
  81. const ClassHidden = "tags tags-brown";
  82. const TitleHidden = "This game is in your filter list";
  83. const TextHidden = "Hidden";
  84.  
  85. const ClassWishlist = "tags tags-purple";
  86. const TitleWishlist = "This game is in your Steam wishlist";
  87. const TextWishlist = "Wishlist";
  88.  
  89. var cbCards = GM_getValue("cbCards", true);
  90. var cbAchievement = GM_getValue("cbAchievement", true);
  91. var cbBundled = GM_getValue("cbBundled", true);
  92. var cbHidden = GM_getValue("cbHidden", true);
  93. var cbWishlist = GM_getValue("cbWishlist", true);
  94.  
  95. main();
  96.  
  97. function main()
  98. {
  99. var currLoc = window.location.href.split("/");
  100.  
  101. // shows trading card tag in featured game (header)
  102. if($(".featured__inner-wrap").length == 1) //exclude page without featured inner wrap
  103. {
  104. var url;
  105. if(currLoc[3] == "giveaway") //giveaway page
  106. url = $(".featured__inner-wrap a")[0].href;
  107. else if(currLoc[3] != "user" && currLoc[3] != "group") //homepage
  108. url = $(".featured__inner-wrap a img")[0].src;
  109.  
  110. if (url != null) //for game without appID e.g Humble Indie Bundle
  111. {
  112. var ID = getAppIDfromLink(url);
  113. var Name = $(".featured__heading__medium").text();
  114. var target = $(".featured__heading");
  115.  
  116. var tagCard = createTag(ClassCard, TitleCard, TextCard, linkCard+ID, target);
  117. var tagAchievement = createTag(ClassAchievement, TitleAchievement, TextAchievement, linkAchievement+ID+"/achievements/", tagCard);
  118. var tagBundle = createTag(ClassBundle, TitleBundle, TextBundle, linkBundle+Name, tagAchievement);
  119. var tagHidden = createTag(ClassHidden, TitleHidden, TextHidden, linkHidden+Name, tagBundle);
  120. var tagWishlist = createTag(ClassWishlist, TitleWishlist, TextWishlist, linkWishlist+Name, tagHidden);
  121.  
  122. if(isAppOrPackage(url))
  123. {
  124. getSteamCategories(ID, tagCard, tagAchievement);
  125. }
  126. else
  127. {
  128. tagCard.setAttribute("href", url);
  129. tagAchievement.setAttribute("href", url);
  130. getSteamCategoriesFromPackage(ID, tagCard, tagAchievement);
  131. }
  132.  
  133. getBundleStatus(ID, Name, tagBundle);
  134.  
  135. if(currLoc[3] == "giveaway") //only trigger inside giveaway page, no need for homepage
  136. {
  137. getHiddenStatus(ID, Name, tagHidden);
  138. getWishlistStatus(ID, Name, tagWishlist);
  139. }
  140. }
  141. }
  142. else if(currLoc[3] == "giveaways" && currLoc[4] == "new") // http://www.steamgifts.com/giveaways/new
  143. {
  144. $(".js__autocomplete-data").on("DOMNodeInserted", NewGiveawayDivUpdated);
  145. }
  146. /*
  147. http://www.steamgifts.com/giveaways/*
  148. http://www.steamgifts.com/sales/*
  149. http://www.steamgifts.com/account/settings/giveaways/filters
  150. http://www.steamgifts.com/account/steam/*
  151. */
  152. else if((currLoc[3] == "giveaways" && !(/search*/.test(currLoc[4]))) || currLoc[6] == "filters" || currLoc[3] == "sales" || currLoc[4] == "steam")
  153. {
  154. $(".table__row-inner-wrap").each(function(index, element)
  155. {
  156.  
  157. var Name = $(element).find(".table__column__heading").text();
  158. var target = $(element).find(".table__column--width-fill > :first-child");
  159.  
  160. //because sales don't use <p> thus tags will appears in line with title
  161. if(currLoc[3] == "sales") target.css("display", "block");
  162.  
  163. var url;
  164. if(currLoc[6] == "filters")
  165. url = $(element).find("a.table__column__secondary-link").text();
  166. else
  167. url = $($(element).find(".global__image-inner-wrap")[0]).css('background-image');
  168.  
  169. if(url != null) //if can get app ID from image
  170. {
  171. url = url.replace('url(', '').replace(')', '');
  172. var ID = getAppIDfromLink(url);
  173.  
  174. var tagCard = createTag(ClassCard, TitleCard, TextCard, linkCard+ID, target);
  175. var tagAchievement = createTag(ClassAchievement, TitleAchievement, TextAchievement, linkAchievement+ID+"/achievements/", tagCard);
  176. var tagBundle = createTag(ClassBundle, TitleBundle, TextBundle, linkBundle+Name, tagAchievement);
  177.  
  178. if(isAppOrPackage(url))
  179. {
  180. getSteamCategories(ID, tagCard, tagAchievement);
  181. }
  182. else
  183. {
  184. tagCard.setAttribute("href", url);
  185. tagAchievement.setAttribute("href", url);
  186. getSteamCategoriesFromPackage(ID, tagCard, tagAchievement);
  187. }
  188.  
  189. getBundleStatus(ID, Name, tagBundle);
  190. }
  191. else //if image does not have appID
  192. {
  193. //TODO: open giveaway page, and then get appID from image
  194. }
  195. });
  196. }
  197.  
  198. /*
  199. http://www.steamgifts.com/
  200. http://www.steamgifts.com/giveaways/search*
  201. http://www.steamgifts.com/user/*
  202. http://www.steamgifts.com/group/*
  203. */
  204. $(".giveaway__row-inner-wrap").each(function(index, element)
  205. {
  206. var url = $(element).find("a.giveaway__icon").attr("href");
  207. if(url != null)
  208. {
  209. var ID = getAppIDfromLink(url);
  210.  
  211. var Name = $(element).find(".giveaway__heading__name").text();
  212. var target = $(element).find(".giveaway__heading");
  213.  
  214. var tagCard = createTag(ClassCard, TitleCard, TextCard, linkCard+ID, target);
  215. var tagAchievement = createTag(ClassAchievement, TitleAchievement, TextAchievement, linkAchievement+ID+"/achievements/", tagCard);
  216. var tagBundle = createTag(ClassBundle, TitleBundle, TextBundle, linkBundle+Name, tagAchievement);
  217.  
  218. if(isAppOrPackage(url))
  219. {
  220. getSteamCategories(ID, tagCard, tagAchievement);
  221. }
  222. else
  223. {
  224. tagCard.setAttribute("href", url);
  225. tagAchievement.setAttribute("href", url);
  226. getSteamCategoriesFromPackage(ID, tagCard, tagAchievement);
  227. }
  228.  
  229. getBundleStatus(ID, Name, tagBundle);
  230. }
  231. });
  232.  
  233. if(currLoc[3] == "account" && currLoc[5] == "giveaways")
  234. {
  235. initSetting();
  236. }
  237. }
  238.  
  239. function createTag(_class, title, text, href, divTarget)
  240. {
  241. var tag = document.createElement("a");
  242. tag.setAttribute("id", "tags");
  243. tag.setAttribute("target", "_blank");
  244. tag.setAttribute("class", _class);
  245. tag.setAttribute("title", title);
  246. tag.setAttribute("href", href);
  247. tag.innerHTML = text;
  248.  
  249. $(divTarget).after(tag);
  250. return tag;
  251. }
  252.  
  253. function displayElems(elems)
  254. {
  255. $(elems).css("display", "inline-block");
  256. }
  257.  
  258. function getSteamCategories(appID, tagCard, tagAchievement)
  259. {
  260. var jsonCards = GM_getValue("cards-" + appID, "");
  261. var jsonAchievement = GM_getValue("achievements-" + appID, "");
  262.  
  263. var reqCard = needRequest(jsonCards);
  264. var reqAchievement = needRequest(jsonAchievement);
  265.  
  266. if(!reqCard && cbCards) // if app card is saved
  267. {
  268. if(JSON.parse(jsonCards).val)
  269. displayElems(tagCard);
  270. }
  271. if(!reqAchievement && cbAchievement) // if app achievement is saved
  272. {
  273. if(JSON.parse(jsonAchievement).val)
  274. displayElems(tagAchievement);
  275. }
  276.  
  277. if((reqCard && cbCards) || (reqAchievement && cbAchievement))
  278. {
  279. console.log("request steam " + appID);
  280. GM_xmlhttpRequest({
  281. method: "GET",
  282. timeout: 10000,
  283. url: linkGameAPI+appID,
  284. onload: function(data)
  285. {
  286. var obj = JSON.parse(data.responseText)[appID].data;
  287. if(obj == null)
  288. {
  289. console.log("apps " + appID + " does not have store page or does not exist");
  290. saveData("cards-" + appID, false);
  291. saveData("achievements-" + appID, false);
  292. }
  293. else
  294. {
  295. obj = obj.categories;
  296. flagCard = false;
  297. flagAchievement = false;
  298. if(obj != null)
  299. {
  300. for(i=0; i<obj.length; i++)
  301. {
  302. if(obj[i].id == "29" && reqCard)
  303. {
  304. displayElems(tagCard);
  305. saveData("cards-" + appID, true);
  306. flagCard = true;
  307. }
  308. if(obj[i].id == "22" && reqAchievement)
  309. {
  310. displayElems(tagAchievement);
  311. saveData("achievements-" + appID, true);
  312. flagAchievement = true;
  313. }
  314. }
  315. }
  316. else
  317. console.log("apps " + appID + " does not have categories");
  318.  
  319. if(reqCard && !flagCard)
  320. saveData("cards-" + appID, false);
  321. if(reqAchievement && !flagAchievement)
  322. saveData("achievements-" + appID, false);
  323. }
  324. }
  325. });
  326. }
  327. }
  328.  
  329. function getBundleStatus(appID, appName, elems)
  330. {
  331. if(cbBundled)
  332. {
  333. var jsonBundle = GM_getValue("bundled-" + appID, "");
  334. appName = appName.replace("+", "%2B");
  335.  
  336. if(!needRequest(jsonBundle))
  337. {
  338. if(JSON.parse(jsonBundle).val)
  339. displayElems(elems);
  340. }
  341. else
  342. {
  343. console.log("request bundle " + appID);
  344. $.get( linkBundle+appName, function(data) {
  345. var gamesfound = $(data).find(".table__column__secondary-link");
  346. for(i=0; i<$(gamesfound).length; i++)
  347. {
  348. var url = $(gamesfound)[i].href;
  349. var ID = getAppIDfromLink(url);
  350.  
  351. if(appID == ID)
  352. {
  353. //TODO : Save appID + true ke local cache
  354. displayElems(elems);
  355. saveData("bundled-" + appID, true);
  356. return true; //exit function
  357. }
  358. }
  359. saveData("bundled-" + appID, false);
  360. });
  361. }
  362. }
  363. }
  364.  
  365. function getHiddenStatus(appID, appName, elems)
  366. {
  367. if(cbHidden)
  368. {
  369. console.log("request hidden " + appID);
  370. appName = appName.replace("+", "%2B");
  371. $.get(linkHidden+appName, function(data)
  372. {
  373. var gamesfound = $(data).find("a.table__column__secondary-link");
  374. for(i=0; i<$(gamesfound).length; i++)
  375. {
  376. var url = $(gamesfound)[i].href;
  377. var ID = getAppIDfromLink(url);
  378. if(appID == ID)
  379. {
  380. //TODO : Save appID + true ke local cache
  381. displayElems(elems);
  382. return true; //exit function
  383. }
  384. }
  385. });
  386. }
  387. }
  388.  
  389. function getWishlistStatus(appID, appName, elems)
  390. {
  391. if(cbWishlist)
  392. {
  393. console.log("request wishlist " + appID);
  394. appName = appName.replace("+", "%2B");
  395. $.get(linkWishlist+appName, function(data)
  396. {
  397. var gamesfound = $(data).find("a.table__column__secondary-link");
  398. for(i=0; i<$(gamesfound).length; i++)
  399. {
  400. var url = $(gamesfound)[i].href;
  401. var ID = getAppIDfromLink(url);
  402. if(appID == ID)
  403. {
  404. //TODO : Save appID + true ke local cache
  405. displayElems(elems);
  406. return true; //exit function
  407. }
  408. }
  409. });
  410. }
  411. }
  412.  
  413. function getSteamCategoriesFromPackage(appID, tagCard, tagAchievement) //Need more research
  414. {
  415. if(cbCards || cbAchievement)
  416. {
  417. //TODO: Check if the game is saved, if no then request to steam
  418. GM_xmlhttpRequest({
  419. method: "GET",
  420. timeout: 10000,
  421. url: linkPackAPI+appID,
  422. onload: function(data)
  423. {
  424. var IDs = JSON.parse(data.responseText)[appID].data;
  425. if(IDs == null) console.log("package " + appID + " does not exist");
  426. else
  427. {
  428. IDs = IDs.apps;
  429. $.each(IDs, function(index)
  430. {
  431. getSteamCategories(IDs[index].id, tagCard, tagAchievement);
  432. //TODO : Save appID + false + expire time ke local cache
  433. });
  434. }
  435. }
  436. });
  437. }
  438. }
  439.  
  440. function getAppIDfromLink(link)
  441. {
  442. // http://store.steampowered.com/app/403570/
  443. var url = link.split("/");
  444. return url[url.length-2];
  445. }
  446.  
  447. function isAppOrPackage(link)
  448. {
  449. // store.steampowered.com/app/403570/
  450. var pattern = /\/app\/|\/apps\//;
  451. return pattern.test(link);
  452. }
  453.  
  454. function saveData(name, val)
  455. {
  456. var today = new Date().toJSON().slice(0,10);
  457. var data = {val:val, savedDate:today};
  458. GM_setValue(name, JSON.stringify(data));
  459. }
  460.  
  461. function needRequest(json)
  462. {
  463. if(json == "")
  464. return true;
  465. else
  466. {
  467. var obj = JSON.parse(json);
  468. if(obj.val)
  469. return false;
  470. else
  471. {
  472. var today = new Date().toJSON().slice(0,10);
  473. if(obj.savedDate == today)
  474. return false;
  475. else
  476. return true;
  477. }
  478. }
  479. }
  480.  
  481. function NewGiveawayDivUpdated(event)
  482. {
  483. if(event.type == "DOMNodeInserted") //show bundle tag for shown game
  484. {
  485. var gamesfound = $(".table__row-inner-wrap");
  486. $(".tags").remove();
  487. $(".table__row-inner-wrap").each(function(index, element)
  488. {
  489. var url = $(element).find("a.table__column__secondary-link").text();
  490. var ID = getAppIDfromLink(url);
  491. var Name = $(element).find(".table__column__heading").text();
  492. var Target = $(element).find(".table__column--width-fill");
  493.  
  494. $(".js__autocomplete-data").off("DOMNodeInserted");
  495. var tagBundle = createTag(ClassBundle, TitleBundle, TextBundle, linkBundle+Name, Target);
  496. $(tagBundle).css("float", "right");
  497. getBundleStatus(ID, Name, tagBundle);
  498. });
  499. if(gamesfound.length > 0)
  500. {
  501. $(".js__autocomplete-data").on("DOMNodeRemoved", NewGiveawayDivUpdated);
  502.  
  503. $(".table__row-inner-wrap").on("click", function(event)
  504. {
  505. var url = $(this).find("a.table__column__secondary-link").text();
  506. var ID = getAppIDfromLink(url);
  507. var Name = $(this).find(".table__column__heading").text();
  508. var Target = $(".js__autocomplete-name")[0];
  509. tagBundle = createTag(ClassBundle, TitleBundle, TextBundle, linkBundle+Name, Target);
  510. getBundleStatus(ID, Name, tagBundle);
  511. });
  512. }
  513. }
  514. else if(event.type == "DOMNodeRemoved")//show / remove tag of selected game
  515. {
  516. $(".js__autocomplete-data").off("DOMNodeRemoved");
  517. $(".table__row-inner-wrap").off("click");
  518. $(".js__autocomplete-data").on("DOMNodeInserted", NewGiveawayDivUpdated);
  519. }
  520. }
  521.  
  522. function initSetting()
  523. {
  524. var n = $(".form__heading").length + 1;
  525. var CheckIcon = '<i class="form__checkbox__default fa fa-circle-o"></i><i class="form__checkbox__hover fa fa-circle"></i><i class="form__checkbox__selected fa fa-check-circle"></i>';
  526. var Color_picker = '<div><input id="textColor" type="color" value="" class="form-control" /></div>';
  527.  
  528. var form__row_1 = document.createElement("div");
  529. form__row_1.setAttribute("class", "form__row");
  530.  
  531. var form__heading_1 = document.createElement("div");
  532. form__heading_1.setAttribute("class", "form__heading");
  533.  
  534. var form__heading__number_1 = document.createElement("div");
  535. form__heading__number_1.setAttribute("class", "form__heading__number");
  536. form__heading__number_1.innerHTML = n + ".";
  537. n++;
  538.  
  539. var form__heading__text_1 = document.createElement("div");
  540. form__heading__text_1.setAttribute("class", "form__heading__text");
  541. form__heading__text_1.innerHTML = "[SG Game Tags] Which tags do you want to see?";
  542.  
  543. $(form__heading_1).append(form__heading__number_1).append(form__heading__text_1);
  544.  
  545. var form__row__indent_1 = document.createElement("div");
  546. form__row__indent_1.setAttribute("class", "form__row__indent");
  547.  
  548. var form__checkbox_1 = createCheckBox("my__checkbox", CheckIcon + "Trading Cards", cbCards);
  549. var form__checkbox_2 = createCheckBox("my__checkbox", CheckIcon + "Achievements", cbAchievement);
  550. var form__checkbox_3 = createCheckBox("my__checkbox", CheckIcon + "Bundled", cbBundled);
  551. var form__checkbox_4 = createCheckBox("my__checkbox", CheckIcon + "Hidden", cbHidden);
  552. var form__checkbox_5 = createCheckBox("my__checkbox", CheckIcon + "Wishlist", cbWishlist);
  553.  
  554. $(form__checkbox_1).click(function(){toggleCBTags(form__checkbox_1, "cbCards");});
  555. $(form__checkbox_2).click(function(){toggleCBTags(form__checkbox_2, "cbAchievement");});
  556. $(form__checkbox_3).click(function(){toggleCBTags(form__checkbox_3, "cbBundled");});
  557. $(form__checkbox_4).click(function(){toggleCBTags(form__checkbox_4, "cbHidden");});
  558. $(form__checkbox_5).click(function(){toggleCBTags(form__checkbox_5, "cbWishlist");});
  559.  
  560. $(form__row__indent_1).append(form__checkbox_1).append(form__checkbox_2).append(form__checkbox_3).append(form__checkbox_4).append(form__checkbox_5);
  561.  
  562. $(form__row_1).append(form__heading_1).append(form__row__indent_1);
  563.  
  564. $(".form__submit-button").before(form__row_1);
  565.  
  566. var desc = document.createElement("div");
  567. desc.setAttribute("class", "form__input-description");
  568. desc.innerHTML = "No need to press Save Changes button. It is automatically saved when the value changed.";
  569. $(desc).appendTo([form__row__indent_1]);
  570.  
  571. changeCBColor();
  572. }
  573.  
  574. function createCheckBox(_class, _html, cbValue)
  575. {
  576. var cb = document.createElement("div");
  577. cb.setAttribute("class", _class);
  578. cb.innerHTML = _html;
  579. if(cbValue)
  580. $(cb).addClass("is-selected");
  581. else
  582. $(cb).addClass("is-disabled");
  583.  
  584. return cb;
  585. }
  586.  
  587. function toggleCBTags(cbElems, cbName)
  588. {
  589. var cbValue;
  590. if(cbName == "cbCards")
  591. {
  592. cbCards = !cbCards;
  593. cbValue = cbCards;
  594. }
  595. else if(cbName == "cbAchievement")
  596. {
  597. cbAchievement = !cbAchievement;
  598. cbValue = cbAchievement;
  599. }
  600. else if(cbName == "cbBundled")
  601. {
  602. cbBundled = !cbBundled;
  603. cbValue = cbBundled;
  604. }
  605. else if(cbName == "cbHidden")
  606. {
  607. cbHidden = !cbHidden;
  608. cbValue = cbHidden;
  609. }
  610. else if(cbName == "cbWishlist")
  611. {
  612. cbWishlist = !cbWishlist;
  613. cbValue = cbWishlist;
  614. }
  615.  
  616. GM_setValue(cbName, cbValue);
  617. if(cbValue)
  618. $(cbElems).removeClass("is-disabled").addClass("is-selected");
  619. else
  620. $(cbElems).removeClass("is-selected").addClass("is-disabled");
  621.  
  622. changeCBColor();
  623. }
  624.  
  625. function changeCBColor()
  626. {
  627. var colorCBDisabled = $(".form__checkbox.is-disabled").css("color");
  628. var colorCBSelected = $(".form__checkbox.is-selected").css("color");
  629.  
  630. $(".my__checkbox.is-disabled").css("color", colorCBDisabled);
  631. $(".my__checkbox.is-selected").css("color", colorCBSelected);
  632. }