Advertisement
Tristar

Library Checker fix+upgrade

Apr 6th, 2018
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        SteamGifts Library Checker
  3. // @namespace   https://github.com/Gaffi/SG-WL-Inventory
  4. // @version     0.17
  5. // @description Scans your whitelist for a particular game to see how many on your list own it. Many props to Sighery for helping me with the API business and for creating the code I butchered to make this.
  6. // @author      Gaffi
  7. // icon
  8. // @downloadURL https://github.com/Gaffi/SG-WL-Inventory/raw/master/SG-WL-Inventory.user.js
  9. // @updateURL   https://github.com/Gaffi/SG-WL-Inventory/raw/master/SG-WL-Inventory.meta.js
  10. // @supportURL  https://www.steamgifts.com/discussion/HipoH/
  11. // @match       https://www.steamgifts.com/account/manage/whitelist*
  12. // @match       https://www.steamgifts.com/group/*
  13. // @match       http://store.steampowered.com/app/*
  14. // @grant       GM_xmlhttpRequest
  15. // @grant       GM_setValue
  16. // @grant       GM_getValue
  17. // @grant       GM_deleteValue
  18. // @grant       GM_log
  19. // @connect     api.steampowered.com
  20. // @connect     store.steampowered.com
  21. // @connect     www.steamgifts.com
  22. // @connect     steamcommunity.com
  23. // ==/UserScript==
  24.  
  25. var cacheVersion = 0.17;
  26. var newJSONTemplate = JSON.parse('{"version":' + cacheVersion + ',"userData":[]}');
  27. var apiKey = null;
  28. var appInput = null;
  29. var totalScanned = 0;
  30. var inactive = 0;
  31. var totalHave = 0;
  32. var countToCheck = 0;
  33. var userPages = 0;
  34. var gameTitle = null;
  35. var libraryDiv;
  36. var libraryDivOutput;
  37. var urlWhitelist = 'https://www.steamgifts.com/account/manage/whitelist';
  38. var urlGroup = 'www.steamgifts.com/group/';
  39. var urlSteamApp = 'store.steampowered.com/app/';
  40. var whichPage = -1; // 0 = Steam, 1 = SG Group, 2 = SG WL
  41. var whichCheck = -1; // 0 = Own, 1 = Want (wishlist)
  42. var startedWrapUp = false;
  43. //var groupInput = null;
  44. var groupIDList = [];
  45. var userLimit = 2000;
  46.  
  47. var logHeader = "[SGLC " + cacheVersion + "] ";
  48.  
  49. var keyStorageUpdated = 'SG_WL_Inventory_last_updated';
  50. var keyStorageOwnData = 'SG_WL_Inventory_user_own_data';
  51. var keyStorageWishData = 'SG_WL_Inventory_user_wish_data';
  52.  
  53. var cacheDate = new Date();
  54. cacheDate.setDate(new Date().getDate()-1);
  55.  
  56. var LAST_UPDATED = GM_getValue(keyStorageUpdated);
  57. var USER_OWN_DATA, USER_WISH_DATA;
  58.  
  59. if (!Array.prototype.indexOf) {
  60.     Array.prototype.indexOf = function (obj, fromIndex) {
  61.     if (fromIndex === null) {
  62.         fromIndex = 0;
  63.     } else if (fromIndex < 0) {
  64.         fromIndex = Math.max(0, this.length + fromIndex);
  65.     }
  66.     for (var i = fromIndex, j = this.length; i < j; i++) {
  67.         if (this[i] === obj)
  68.             return i;
  69.     }
  70.     return -1;
  71.     };
  72. }
  73.  
  74. apiKey = GM_getValue('SGLCdlg-APIKey');
  75.  
  76. if (window.location.href.indexOf(urlSteamApp) > 0) {
  77.     GM_log(logHeader + 'SteamGifts Library Checker Injecting Steam Store');
  78.     whichPage = 0;
  79.     injectInterfaceSteam();
  80. } else {
  81.     if (window.location.href.indexOf(urlGroup) > 0) {
  82.         GM_log(logHeader + 'SteamGifts Library Checker Injecting SteamGifts Group Page');
  83.         whichPage = 1;
  84.     } else {
  85.         GM_log(logHeader + 'SteamGifts Library Checker Injecting SteamGifts Whitelist Page');
  86.         whichPage = 2;
  87.     }
  88.     injectDialog();
  89.     injectDlgStyle();
  90.     injectInterfaceSG();
  91. }
  92.  
  93. /**
  94.  * Adds user data from Steam API to pre-load JSON
  95.  * @param {Object} newJSON - A parsed JSON object to add (if not already present)
  96.  * @param {Number} steamID - Steam user ID to check ownership
  97.  */
  98. function addUserToJSONOwnership(newJSON, steamID) {
  99.     GM_log(logHeader + "Checking to see if we need to add user " + steamID + " to stored data pre-load (JSON for ownership).");
  100.     var alreadyHave = false;
  101.     for (var i = 0; i < USER_OWN_DATA.userData.length; i++) {
  102.         if (USER_OWN_DATA.userData[i].userID == steamID) {
  103.             alreadyHave = true;
  104.             GM_log(logHeader + "We already have data for this user, so skipping...");
  105.             break;
  106.         }
  107.     }
  108.     if (!alreadyHave) {
  109.         if (newJSON.response.games) {
  110.             GM_log(logHeader + "No data for " + steamID + ", but we have games to add. Adding to pre-load (JSON for ownership).");
  111.             var tempJSON = JSON.parse('{"userID":' + steamID + ',"userData":[]}');
  112.             for(var j = 0; j < newJSON.response.games.length; j++) {
  113.                 tempJSON.userData.push(newJSON.response.games[j].appid);
  114.             }
  115.             USER_OWN_DATA.userData.push(tempJSON);
  116.         } else {
  117.             GM_log(logHeader + "No data for " + steamID + ", with no games to add (possibly private profile). Adding to pre-load (JSON).");
  118.             USER_OWN_DATA.userData.push(JSON.parse('{"userID":' + steamID + ',"userData":[]}'));
  119.         }
  120.     }
  121. }
  122.  
  123. /**
  124.  * Adds user data from Steam API to pre-load JSON
  125.  * @param {Object} wishlistHTML - Wishlist page HTML to add (if not already present)
  126.  * @param {Number} steamID - Steam user ID to check ownership
  127.  */
  128. function addUserToJSONWishlist(wishlistHTML, steamID) {
  129.     GM_log(logHeader + "Checking to see if we need to add user " + steamID + " to stored data pre-load (JSON for wishlist).");
  130.     var alreadyHave = false;
  131.    
  132.     for (var i = 0; i < USER_WISH_DATA.userData.length; i++) {
  133.         if (USER_WISH_DATA.userData[i].userID == steamID) {
  134.             alreadyHave = true;
  135.             GM_log(logHeader + "We already have data for this user, so skipping...");
  136.             break;
  137.         }
  138.     }
  139.  
  140.     if (!alreadyHave) {
  141.         GM_log(logHeader + "We do not have data for this user, so adding...");
  142.         // First check is YOU/user running the script, second check is a normal user.
  143.         // Steam allows sorting of your own wishlist, so the div class is different.
  144.         var re = /"appid":(\d+),"priority"/g;
  145.         var result = '';
  146.         var resultJSON = JSON.parse('{"userID":' + steamID + ',"userData":[]}');
  147.  
  148.         do {
  149.             result = re.exec(wishlistHTML);
  150.             if (result) {
  151.                 resultJSON.userData.push(result[1]);
  152.             }
  153.         } while (result);
  154.        
  155.         USER_WISH_DATA.userData.push(resultJSON);
  156.     }
  157. }
  158.  
  159. /**
  160.  * Gets user header info (steamID) from whitelist and initiates process for confirming whether or not the game is owned or wanted by that user after checking if their data is already stored in cache.
  161.  * @param {Object} row - Div element from whitelist that holds user data
  162.  * @param {Number} appID - Steam game ID to check ownership of
  163.  */
  164. function checkHasGameInData(row, appID) {
  165.     GM_xmlhttpRequest({
  166.         method: "GET",
  167.         url: 'https://www.steamgifts.com/user/' + row.getElementsByClassName('table__column__heading')[0].innerHTML,
  168.         onload: function(response) {
  169.             // If countToCheck = 0, then we have no whitelist, or we want to terminate the script.
  170.             // Asnyc calls keep running, so this check appears multiple times in the code.
  171.             if (countToCheck > 0 ) {
  172.                 var tempElem = document.createElement("div");
  173.                 tempElem.style.display = "none";
  174.                 tempElem.innerHTML = response.responseText;
  175.                 var steamIDdivhtml = tempElem.getElementsByClassName("sidebar__shortcut-inner-wrap")[0].innerHTML;
  176.                 var searchString1 = 'href="https://steamcommunity.com/profiles/';
  177.                 var searchString2 = '" data-tooltip=';
  178.                 var steamID = steamIDdivhtml.slice(steamIDdivhtml.indexOf(searchString1)+searchString1.length,steamIDdivhtml.indexOf(searchString2));
  179.                 if (!gameTitle) {
  180.                     importJSONSteamGameDetail(appID);
  181.                 }
  182.                 if (steamID.length > 0) {
  183.                     GM_log(logHeader + 'Checking stored data for ' + steamID);
  184.                     var haveUser = false;
  185.                     var i;
  186.                     switch (whichCheck) {
  187.                         case 0:
  188.                             for (i = 0; i < USER_OWN_DATA.userData.length; i++) {
  189.                                 if (USER_OWN_DATA.userData[i].userID == steamID) {
  190.                                     haveUser = true;
  191.                                     break;
  192.                                 }
  193.                             }
  194.                             break;
  195.                         case 1:
  196.                             for (i = 0; i < USER_WISH_DATA.userData.length; i++) {
  197.                                 if (USER_WISH_DATA.userData[i].userID == steamID) {
  198.                                     haveUser = true;
  199.                                     break;
  200.                                 }
  201.                             }
  202.                             break;
  203.                     }
  204.                     if (!haveUser) {
  205.                         GM_log(logHeader + 'Do not have user stored - checking API data for ' + steamID);
  206.                         switch (whichCheck) {
  207.                             case 0:
  208.                                 checkSteamUserLibrary(steamID, appID);
  209.                                 break;
  210.                             case 1:
  211.                                 checkSteamUserWishlist(steamID, appID);
  212.                                 break;
  213.                         }
  214.                     } else {
  215.                         GM_log(logHeader + 'Already have user stored for ' + steamID + '. Not checking API.');
  216.                         readStoredUserData(steamID, appID);
  217.                     }
  218.                 }
  219.             }
  220.         }
  221.     });
  222. }
  223.  
  224. /**
  225.  * Reads Steam API for user details (listing of all games, plus extra info). Writes result to main user data for caching to prevent future API calls. Also sends result to count summary for final output.
  226.  * @param {Number} steamID - Steam user ID to check ownership
  227.  * @param {Number} appID - Steam game ID to check ownership of
  228.  */
  229. function checkSteamUserLibrary(steamID, appID) {
  230.     // If countToCheck = 0, then we have no whitelist, or we want to terminate the script.
  231.     // Asnyc calls keep running, so this check appears multiple times in the code.
  232.     // apiKey check here plays a similar role.
  233.     if (apiKey && countToCheck > 0 && steamID) {
  234.         var link = "https://api.steampowered.com/IPlayerService/GetOwnedGames/v1/?key=" + apiKey + '&input_json={"steamid":' + steamID + '}';
  235.         //GM_log(logHeader + link);
  236.         var jsonFile;
  237.         GM_xmlhttpRequest ({
  238.             method: "GET",
  239.             url: link,
  240.             timeout: 5000,
  241.             onload: function(response) {
  242.                 if (response){
  243.                     try{
  244.                         jsonFile = JSON.parse(response.responseText);
  245.                     }catch(e){
  246.                         var badAPIMsg = "Unexpected token < in JSON";
  247.                         if (e.name == 'SyntaxError' && e.message.slice(0,badAPIMsg.length) == badAPIMsg) {
  248.                             // Clear API values to prevent more calls to API.
  249.                             processCount(2);
  250.                             GM_log(logHeader + 'Error loading user JSON!');
  251.                             apiKey = null;
  252.                             countToCheck = 0;
  253.                             wrapUp();
  254.                         } else {
  255.                             GM_log(logHeader + "Uncaught error: " + e.name + " -- " + e.message);
  256.                         }
  257.                     }
  258.                     if (jsonFile) {
  259.                         addUserToJSONOwnership(JSON.parse(response.responseText), steamID);
  260.                         readStoredUserData(steamID, appID);
  261.                     }
  262.                 }
  263.             },
  264.         });
  265.     }
  266. }
  267.  
  268. /**
  269.  * Reads Steam wishist page (NO API CALL FOR THIS. THIS MAY BE VERY SLOW...)
  270.  * Writes result to main user data for caching to prevent future API calls.
  271.  * Also sends result to count summary for final output.
  272.  * @param {Number} steamID - Steam user ID to check wishlist status
  273.  * @param {Number} appID - Steam game ID to check
  274.  */
  275. function checkSteamUserWishlist(steamID, appID) {
  276.     if (steamID && appID) {
  277.         var link = 'https://steamcommunity.com/profiles/' + steamID + '/wishlist';
  278.         GM_xmlhttpRequest({
  279.             method: "GET",
  280.             url: link,
  281.             onload: function(response) {
  282.                 if (response){                 
  283.                     if (response.responseText) {
  284.                         addUserToJSONWishlist(response.responseText, steamID);
  285.                         readStoredUserData(steamID, appID);
  286.                     } else {
  287.                         GM_log(logHeader + 'Error loading wishlist page (probably private user)...');
  288.                         addUserToJSONWishlist("", steamID);
  289.                         readStoredUserData(steamID, appID);
  290.                     }
  291.                 } else {
  292.                     GM_log(logHeader + 'Error loading wishlist page...');
  293.                     processCount(2);
  294.                 }
  295.             }
  296.         });
  297.     }
  298. }
  299.  
  300. /**
  301.  * Begins processing of user ownership checking. Disables buttons/shows progress, etc.
  302.  */
  303. function clickButtonOwn() {
  304.     var input = document.getElementById('SGLCdlg-APIKey');
  305.     GM_setValue('SGLCdlg-APIKey', input.value);
  306.     document.getElementById('SGLCdlg-GameName').value = null;
  307.     document.getElementById('SGLCdlg-output').value = null;
  308.     if(document.getElementById('SGLCdlg-AppID').value.length ===    0) {
  309.         document.getElementById('SGLCdlg-output').value = 'Please enter a valid app ID...';
  310.     } else {
  311.         whichCheck = 0;
  312.         switch (whichPage) {
  313.             case 1:
  314.                 document.getElementById('SGLCdlg-output').value = 'Checking group users...';
  315.                 break;
  316.             case 2:
  317.                 document.getElementById('SGLCdlg-output').value = 'Checking whitelisted users...';
  318.                 break;
  319.         }
  320.         if (whichCheck == 1) {
  321.             document.getElementById('SGLCdlg-output').value = document.getElementById('SGLCdlg-output').value + '\n\nIf this data has not been cached yet, this may take a few minutes, depending on the size of the userlist. Please be patient.';
  322.         }
  323.         document.getElementById('SGLCdlg-checkbuttonown').disabled = true;
  324.         document.getElementById('SGLCdlg-checkbuttonwant').disabled = true;
  325.         document.getElementById('SGLCdlg-cachebutton').disabled = true;
  326.         startCheck();
  327.     }
  328. }
  329.  
  330. /**
  331.  * Begins processing of user wishlist checking. Disables buttons/shows progress, etc.
  332.  */
  333. function clickButtonWant() {
  334.     var input = document.getElementById('SGLCdlg-APIKey');
  335.     GM_setValue('SGLCdlg-APIKey', input.value);
  336.     document.getElementById('SGLCdlg-GameName').value = null;
  337.     document.getElementById('SGLCdlg-output').value = null;
  338.     if(document.getElementById('SGLCdlg-AppID').value.length ===    0) {
  339.         document.getElementById('SGLCdlg-output').value = 'Please enter a valid app ID...';
  340.     } else {
  341.         whichCheck = 1;
  342.         switch (whichPage) {
  343.             case 1:
  344.                 document.getElementById('SGLCdlg-output').value = 'Checking group users...';
  345.                 break;
  346.             case 2:
  347.                 document.getElementById('SGLCdlg-output').value = 'Checking whitelisted users...';
  348.                 break;
  349.         }
  350.         document.getElementById('SGLCdlg-checkbuttonown').disabled = true;
  351.         document.getElementById('SGLCdlg-checkbuttonwant').disabled = true;
  352.         document.getElementById('SGLCdlg-cachebutton').disabled = true;
  353.         startCheck();
  354.     }
  355. }
  356.  
  357. /**
  358.  * Checks if user-specific info already exists in stored JSON data.
  359.  * @param {Object} JSONArray - A parsed JSON object to search through - holds a listing of all users
  360.  * @param {Number} steamID - Steam user ID to check ownership
  361.  * @return {Object} returnJSON - A parsed JSON object (if not null) - that is a subset of the passed JSONArray - with user ownership list/details
  362.  */
  363. function findUserInJSON(JSONArray, steamID) {
  364.     var returnJSON = null;
  365.     GM_log(logHeader + 'Scanning stored user data for user ' + steamID);
  366.     for (var i = 0; i < JSONArray.length; i++) {
  367.         if (JSONArray[i].userID == steamID) {
  368.             GM_log(logHeader + 'Found user ' + steamID + ' in stored data.');
  369.             returnJSON = JSONArray[i].userData;
  370.             return returnJSON;
  371.         }
  372.     }
  373.     GM_log(logHeader + 'Could not find user ' + steamID + ' in stored data.');
  374.     return null;
  375. }
  376.  
  377. /**
  378.  * Checks if game-specific info already exists in stored JSON data.
  379.  * @param {Object} JSONArray - A parsed JSON object to search through - holds a listing of all games for a user
  380.  * @param {Number} appID - Steam game ID to check ownership of
  381.  * @return {boolean} hasGame - Result of searching for game in JSON data - true = owned, false = not owned
  382.  */
  383. function findGameInJSON(JSONArray, appID, steamID) {
  384.     var canReadGames = true;
  385.     var hasGame = false;
  386.     try{
  387.         GM_log(logHeader + 'Scanning ' + JSONArray.length + ' total saved user games for ' + appID);
  388.     }catch(e){
  389.         canReadGames = false;
  390.     }
  391.     if (canReadGames) {
  392.         for (var i = 0; i < JSONArray.length; i++) {
  393.             if (JSONArray[i] == appID) {
  394.                 hasGame = true;
  395.                 return hasGame;
  396.             }
  397.         }
  398.     }
  399.     return hasGame;
  400. }
  401.  
  402. /**
  403.  * Preloads total whitelist/group count information to avoid loading pages multiple times.
  404.  * Pre-loading also prevents asnyc calls to hit before counts are obtained.
  405.  */
  406. function getUserCounts() {
  407.     countToCheck = 0;
  408.     var link = '';
  409.     switch(whichPage) {
  410.         case 0:
  411.             // Load the whitelist page and read from xml data
  412.             GM_log(logHeader + 'Getting user counts for WL page from Steam Store...');
  413.             link = urlWhitelist + '/search?page=1000';
  414.             GM_log(logHeader + 'Checking WL page [' + link + '] for user count.');
  415.             GM_xmlhttpRequest({
  416.                 method: "GET",
  417.                 url: link,
  418.                 onload: function(response) {
  419.                     if (response){
  420.                         var tempElem = document.createElement("div");
  421.                         tempElem.style.display = "none";
  422.                         tempElem.innerHTML = response.responseText;
  423.                         countToCheck = parseInt(tempElem.getElementsByClassName('sidebar__navigation__item__count')[0].innerHTML.replace(/\,/g,''));
  424.                     } else {
  425.                         GM_log(logHeader + 'Error loading WL page...');
  426.                     }
  427.                 }
  428.             });
  429.             break;
  430.         case 1:
  431.             // Load the user page and get the user/page count.
  432.             GM_log(logHeader + 'Getting user counts from main group page from SG...');
  433.             countToCheck = parseInt(document.getElementsByClassName('sidebar__navigation__item__count')[1].innerHTML.replace(/\,/g,''));
  434.             break;
  435.         case 2:
  436.             // Read the whitelist page in place
  437.             GM_log(logHeader + 'Getting user counts for WL page from SG...');
  438.             countToCheck = parseInt(document.getElementsByClassName('sidebar__navigation__item__count')[0].innerHTML.replace(/\,/g,''));
  439.             break;
  440.     }
  441.     GM_log(logHeader + 'Setting user pages for ' + countToCheck + ' users (' + Math.ceil(countToCheck/25) + ').');
  442.     userPages = Math.ceil(countToCheck/25);
  443. }
  444.  
  445. /**
  446.  * Reads HTML of whitelist/group page and returns an array of div elements, each housing one user's data.
  447.  * @param {string} curHTML - The HTML to parse and search through for user data.
  448.  * @return {Object} userRows - Array of div elements with user data.
  449.  */
  450. function getUserRows(curHTML) {
  451.     var tempElem = document.createElement("div");
  452.     tempElem.style.display = "none";
  453.     tempElem.innerHTML = curHTML;
  454.     var userRows = tempElem.getElementsByClassName("table__row-inner-wrap");
  455.     return userRows;
  456. }
  457.  
  458. /**
  459.  * Reads Steam API for game details (game title)
  460.  * @param {Number} appID - Steam game ID to check ownership of
  461.  */
  462. function importJSONSteamGameDetail(appID) {
  463.     var link = "https://store.steampowered.com/api/appdetails?appids="+appID;
  464.     GM_log(logHeader + 'Checking store page [' + link + '] for game details.');
  465.     var jsonFile;
  466.     GM_xmlhttpRequest ({
  467.         method: "GET",
  468.         url: link,
  469.         timeout: 5000,
  470.         onload: function(response) {
  471.             if (response){
  472.                 try{
  473.                     jsonFile = JSON.parse(response.responseText);
  474.                 }catch(e){
  475.                     GM_log(logHeader + "Uncaught error: " + e.name + " -- " + e.message);
  476.                 }
  477.                 //GM_log(logHeader + jsonFile);
  478.                 if (jsonFile[appID.toString()].success) {
  479.                     gameTitle = jsonFile[appID.toString()].data.name;
  480.                     GM_log(logHeader + 'Game Title: ' + gameTitle);
  481.                     if (whichPage > 0 && document.getElementById('SGLCdlg-GameName').value.length === 0) {
  482.                         document.getElementById('SGLCdlg-GameName').value = gameTitle;
  483.                     }
  484.                 } else {
  485.                     /* We will not kill the search if the app ID is bad.
  486.                         If the game is simply no longer listed for sale, we still want to check ownership.
  487.                     */
  488.                     gameTitle = 'Unlisted/removed/invalid app ID';
  489.                     GM_log(logHeader + 'Game Title: ' + gameTitle);
  490.                     if (whichPage > 0 && document.getElementById('SGLCdlg-GameName').value.length === 0) {
  491.                         document.getElementById('SGLCdlg-GameName').value = appID;
  492.                     }
  493.                     //countToCheck = -1;
  494.                     //totalScanned = 0;
  495.                 }
  496.             }
  497.         },
  498.     });
  499. }
  500.  
  501. /**
  502.  * Adds hidden display to SteamGifts to review results/kickoff checking process
  503.  * Shamelessly stolen from Sighery's RaCharts Enhancer script
  504.  */
  505. function injectDialog() {
  506.     var dlg = document.createElement('div');
  507.     dlg.setAttribute('id', 'black-background');
  508.     var dlgMainDiv = document.createElement('div');
  509.     dlg.appendChild(dlgMainDiv);
  510.     document.body.insertBefore(dlg, document.body.children[0]);
  511.  
  512.     dlgMainDiv.setAttribute('id', 'SGLCdlg');
  513.     var dlgHeader = document.createElement('div');
  514.     dlgMainDiv.appendChild(dlgHeader);
  515.  
  516.     dlgHeader.setAttribute('id', 'SGLCdlg-header');
  517.     var dlgHdrSecDiv = document.createElement('div');
  518.     dlgHeader.appendChild(dlgHdrSecDiv);
  519.     dlgHdrSecDiv.setAttribute('id', 'SGLCdlg-header-title');
  520.     dlgHdrSecDiv.innerHTML = "Gaffi's SteamGifts Library Checker";
  521.  
  522.     var dlgHdrBttn = document.createElement('button');
  523.     dlgHeader.appendChild(dlgHdrBttn);
  524.     dlgHdrBttn.setAttribute('id', 'closeSGLC');
  525.  
  526.     dlgHdrBttn.addEventListener('click', function() {
  527.         var blackbg = document.getElementById('black-background');
  528.         var dlg = document.getElementById('SGLCdlg');
  529.  
  530.         blackbg.style.display = 'none';
  531.         dlg.style.display = 'none';
  532.     });
  533.  
  534.     var dlgHdrBttnI = document.createElement('i');
  535.     dlgHdrBttn.appendChild(dlgHdrBttnI);
  536.     dlgHdrBttnI.setAttribute('class', 'fa fa-times');
  537.     dlgHdrBttnI.style.fontSize = "25px";
  538.     dlgHdrBttnI.style.marginTop = "-6px";
  539.  
  540.     var dlgBody = document.createElement('div');
  541.     dlgMainDiv.appendChild(dlgBody);
  542.     dlgBody.setAttribute('id', 'SGLCdlg-body');
  543.  
  544.     var dlgTable = document.createElement('table');
  545.     dlgTable.setAttribute('style', 'width: 100%');
  546.  
  547.     var rowAPIKey = dlgTable.insertRow(0);
  548.     var rowAPIKeyLabel = rowAPIKey.insertCell(0);
  549.     var rowAPIKeyValue = rowAPIKey.insertCell(1);
  550.     var rowAppID = dlgTable.insertRow(1);
  551.     var rowAppIDLabel = rowAppID.insertCell(0);
  552.     var rowAppIDValue = rowAppID.insertCell(1);
  553.     var rowGameName = dlgTable.insertRow(2);
  554.     var rowGameNameLabel = rowGameName.insertCell(0);
  555.     var rowGameNameResult = rowGameName.insertCell(1);
  556.     var rowButtons = dlgTable.insertRow(3);
  557.     var rowButtonsCheck = rowButtons.insertCell(0);
  558.     var rowButtonsProgress = rowButtons.insertCell(1);
  559.  
  560.     dlgBody.appendChild(dlgTable);
  561.  
  562.     var dlgAPILab = document.createElement('label');
  563.     rowAPIKeyLabel.appendChild(dlgAPILab);
  564.     dlgAPILab.htmlFor = "APIKey";
  565.     dlgAPILab.innerHTML = "API Key:";
  566.     var dlgAPIInput = document.createElement('input');
  567.     rowAPIKeyValue.appendChild(dlgAPIInput);
  568.     dlgAPIInput.type = "textarea";
  569.     dlgAPIInput.setAttribute('id', 'SGLCdlg-APIKey');
  570.     dlgAPIInput.setAttribute('class', 'SGLCdlg-input-enabled input');
  571.     dlgAPIInput.value = apiKey;
  572.  
  573.     var dlgAppIDLab = document.createElement('label');
  574.     rowAppIDLabel.appendChild(dlgAppIDLab);
  575.     dlgAppIDLab.htmlFor = "SGLCdlg-AppID";
  576.     dlgAppIDLab.innerHTML = "App ID:";
  577.     var dlgAppIDInput = document.createElement('input');
  578.     rowAppIDValue.appendChild(dlgAppIDInput);
  579.     dlgAppIDInput.type = "textarea";
  580.     dlgAppIDInput.setAttribute('id', 'SGLCdlg-AppID');
  581.     dlgAppIDInput.setAttribute('class', 'SGLCdlg-input-enabled');
  582.  
  583.     var dlgGameNameLab = document.createElement('label');
  584.     rowGameNameLabel.appendChild(dlgGameNameLab);
  585.     dlgGameNameLab.htmlFor = "SGLCdlg-GameName";
  586.     dlgGameNameLab.innerHTML = "Game Name:";
  587.     var dlgGameNameResult = document.createElement('input');
  588.     rowGameNameResult.appendChild(dlgGameNameResult);
  589.     dlgGameNameResult.type = "textarea";
  590.     dlgGameNameResult.readOnly = true;
  591.     dlgGameNameResult.setAttribute('class', 'SGLCdlg-input-disabled input');
  592.     dlgGameNameResult.setAttribute('id', 'SGLCdlg-GameName');
  593.  
  594.     var dlgCheckBttnOwn = document.createElement('button');
  595.     dlgBody.appendChild(dlgCheckBttnOwn);
  596.     dlgCheckBttnOwn.setAttribute('id', 'SGLCdlg-checkbuttonown');
  597.     dlgCheckBttnOwn.setAttribute('class', 'SGLCdlg-button');
  598.     dlgCheckBttnOwn.setAttribute('style', 'float:left;');
  599.     dlgCheckBttnOwn.innerHTML = "Who owns?";
  600.     dlgCheckBttnOwn.addEventListener('click', clickButtonOwn);
  601.     rowButtonsCheck.appendChild(dlgCheckBttnOwn);
  602.  
  603.     var dlgCheckBttnWant = document.createElement('button');
  604.     dlgBody.appendChild(dlgCheckBttnWant);
  605.     dlgCheckBttnWant.setAttribute('id', 'SGLCdlg-checkbuttonwant');
  606.     dlgCheckBttnWant.setAttribute('class', 'SGLCdlg-button');
  607.     dlgCheckBttnWant.setAttribute('style', 'float:left;');
  608.     dlgCheckBttnWant.innerHTML = "Who wants?";
  609.     dlgCheckBttnWant.addEventListener('click', clickButtonWant);
  610.     rowButtonsCheck.appendChild(dlgCheckBttnWant);
  611.  
  612.     var dlgProgress = document.createElement('button');
  613.     dlgBody.appendChild(dlgProgress);
  614.     dlgProgress.setAttribute('id', 'SGLCdlg-progress');
  615.     dlgProgress.setAttribute('class', 'SGLCdlg-button');
  616.     dlgProgress.setAttribute('style','display:none;float:right;');
  617.     dlgProgress.innerHTML = "";
  618.     rowButtonsProgress.appendChild(dlgProgress);
  619.  
  620.     dlgBody.appendChild(document.createElement('br'));
  621.  
  622.     var dlgOutputTxt = document.createElement('textarea');
  623.     dlgOutputTxt.readOnly = true;
  624.     dlgOutputTxt.setAttribute('rows','10');
  625.     dlgOutputTxt.setAttribute('cols','50');
  626.     dlgOutputTxt.setAttribute('id', 'SGLCdlg-output');
  627.     dlgOutputTxt.value = '';
  628.     dlgBody.appendChild(dlgOutputTxt);
  629.  
  630.     dlgBody.appendChild(document.createElement('br'));
  631.  
  632.     var dlgCacheBttn = document.createElement('button');
  633.     dlgBody.appendChild(dlgCacheBttn);
  634.     dlgCacheBttn.setAttribute('id', 'SGLCdlg-cachebutton');
  635.     dlgCacheBttn.setAttribute('class', 'SGLCdlg-button');
  636.     dlgCacheBttn.setAttribute('style', 'float:left;');
  637.     dlgCacheBttn.innerHTML = "Reset Cache";
  638.     dlgCacheBttn.addEventListener('click', resetCache);
  639.  
  640.     dlgBody.appendChild(document.createElement('br'));
  641.  
  642.     var dlgInfo = document.createElement('h2');
  643.     dlgBody.appendChild(dlgInfo);
  644.     dlgInfo.style.float = "right";
  645.     var dlgInfoA = document.createElement('a');
  646.     dlgInfo.appendChild(dlgInfoA);
  647.     dlgInfoA.href = "https://www.steamgifts.com/discussion/HipoH/";
  648.     dlgInfoA.style.color = "#FFFFFF";
  649.     dlgInfoA.style.fontSize = "20px";
  650.     dlgInfoA.style.fontStyle = "italic";
  651.     dlgInfoA.style.textDecoration = "underline";
  652.     dlgInfoA.innerHTML = "Info";
  653.  
  654.     dlgBody.appendChild(document.createElement('br'));
  655. }
  656.  
  657. /**
  658.  * Adds styles to SteamGifts to review results
  659.  * Shamelessly stolen from Sighery's RaCharts Enhancer script
  660.  */
  661. function injectDlgStyle() {
  662.     var dialogCSS = [
  663.         "#black-background {",
  664.         "   display: none;",
  665.         "   width: 100%;",
  666.         "   height: 100%;",
  667.         "   position: fixed;",
  668.         "   top: 0px;",
  669.         "   left: 0px;",
  670.         "   background-color: rgba(0, 0, 0, 0.75);",
  671.         "   z-index: 8888;",
  672.         "}",
  673.         "#SGLCdlg{",
  674.         "   display: none;",
  675.         "   position: fixed;",
  676.         "   width: 500px;",
  677.         "   z-index: 9999;",
  678.         "   border-radius: 10px;",
  679.         "   background-color: #7c7d7e;",
  680.         "}",
  681.         "#SGLCdlg-header {",
  682.         "   background-color: #6D84B4;",
  683.         "   padding: 10px;",
  684.         "   padding-bottom: 30px;",
  685.         "   margin: 10px 10px 10px 10px;",
  686.         "   color: white;",
  687.         "   font-size: 20px;",
  688.         "}",
  689.         "#SGLCdlg-header-title {",
  690.         "   float: left;",
  691.         "}",
  692.         "#SGLCdlg-body{",
  693.         "   clear: both;",
  694.         "   background-color: #C3C3C3;",
  695.         "   color: white;",
  696.         "   font-size: 14px;",
  697.         "   padding: 10px;",
  698.         "   margin: 0px 10px 10px 10px;",
  699.         "}",
  700.         "#closeSGLC {",
  701.         "   background-color: transparent;",
  702.         "   color: white;",
  703.         "   float: right;",
  704.         "   border: none;",
  705.         "   font-size: 25px;",
  706.         "   margin-top: -5px;",
  707.         "   opacity: 0.7;",
  708.         "}",
  709.         "#SGLCdlg-progress {",
  710.         "   width: 300px;",
  711.         "}",
  712.         ".SGLCdlg-button{",
  713.         "   background-color: #fff;",
  714.         "   border: 2px solid #333;",
  715.         "   box-shadow: 1px 1px 0 #333,",
  716.         "       2px 2px 0 #333,",
  717.         "       3px 3px 0 #333,",
  718.         "       4px 4px 0 #333,",
  719.         "       5px 5px 0 #333;",
  720.         "   color: #333;",
  721.         "   display: inline-block;",
  722.         "   padding: 4px 6px;",
  723.         "   position: relative;",
  724.         "   text-decoration: none;",
  725.         "   text-transform: uppercase;",
  726.         "   -webkit-transition: .1s;",
  727.         "   -moz-transition: .1s;",
  728.         "   -ms-transition: .1s;",
  729.         "   -o-transition: .1s;",
  730.         "   transition: .1s;",
  731.         "}",
  732.         ".SGLCdlg-button:hover,",
  733.         ".SGLCdlg-button:focus {",
  734.         "   background-color: #edd;",
  735.         "}",
  736.         ".SGLCdlg-button:disabled {",
  737.         "opacity: 0.65;",
  738.         "cursor: not-allowed;",
  739.         "}",
  740.         ".SGLCdlg-button:active {",
  741.         "   box-shadow: 1px 1px 0 #333;",
  742.         "   left: 4px;",
  743.         "   top: 4px;",
  744.         "}",
  745.         ".SGLCdlg-input-disabled {",
  746.         "   background-color: #ddd !important;",
  747.         "   float: right;",
  748.         "   margin-left: 35px;",
  749.         "   width: 300px;",
  750.         "   line-height: inherit !important;",
  751.         "}",
  752.         ".SGLCdlg-input-enabled {",
  753.         "   float: right;",
  754.         "   margin-left: 35px;",
  755.         "   width: 300px;",
  756.         "   line-height: inherit !important;",
  757.         "}"
  758.     ].join("\n");
  759.     var node = document.createElement('style');
  760.     node.type = "text/css";
  761.     node.appendChild(document.createTextNode(dialogCSS));
  762.     document.getElementsByTagName('head')[0].appendChild(node);
  763. }
  764.  
  765. /**
  766.  * Adds button to Steam store to run checking process
  767.  * Button placement taken from VonRaven at https://www.steamgifts.com/go/comment/MU3ojjL, http://pastebin.com/kRKv53uv
  768.  */
  769. function injectInterfaceSteam() {
  770.     var refTarget, refParent;
  771.     refTarget = document.getElementsByClassName('apphub_AppName')[0];
  772.     refParent = document.getElementsByClassName('apphub_HeaderStandardTop')[0];
  773.  
  774.     GM_log(logHeader + 'Creating button/progress bar on Steam store...');
  775.     libraryDiv = document.createElement("DIV");
  776.     libraryDiv.id = "whitelist_ownership_checker";
  777.     libraryDiv.className = 'btnv6_blue_hoverfade btn_medium';
  778.     libraryDiv.innerHTML = "<span>SG Check</span>";
  779.     libraryDivOutput = document.createElement("DIV");
  780.     libraryDivOutput.id = "whitelist_ownership_output";
  781.     libraryDivOutput.className = 'btnv6_blue_hoverfade btn_medium';
  782.     libraryDivOutput.innerHTML = "<span>Results</span>";
  783.  
  784.     var libraryExtraDiv = document.createElement("DIV");
  785.     libraryExtraDiv.className = 'apphub_OtherSiteInfo';
  786.     libraryExtraDiv.style = 'margin-right:0.2em';
  787.     libraryExtraDiv.appendChild(libraryDiv);
  788.     libraryExtraDiv.appendChild(libraryDivOutput);
  789.     refParent.insertBefore(libraryExtraDiv, refTarget);
  790.     document.getElementById('whitelist_ownership_checker').addEventListener('click', startCheck, false);
  791.  
  792.     var curURL = window.location.href;
  793.     whichCheck = 0;
  794.     // This allows for searching on store pages ending with the appid (e.g. /123456/) as well as those ending with additional suffix data (e.g. /?snr=1_5_9__300)
  795.     if (curURL.indexOf('?') > 0) {
  796.         appInput = curURL.slice(curURL.lastIndexOf('/',curURL.lastIndexOf('?')-2)+1,curURL.lastIndexOf('/'));
  797.     } else {
  798.         var re = new RegExp("[0-9]{6}");
  799.         appInput = re.exec(curURL)[0];
  800.                
  801.         if (curURL.lastIndexOf('/')+1 != curURL.length) {
  802.             curURL += '/';
  803.         }
  804.         //appInput = curURL.slice(curURL.lastIndexOf('/',curURL.length-2)+1,curURL.lastIndexOf('/',curURL.length));
  805.     }
  806.     getUserCounts();
  807.     GM_log(logHeader + 'Library checking button loaded without errors.');
  808. }
  809.  
  810. /**
  811.  * Adds button to SteamGifts whitelist/group page to run checking process
  812.  */
  813. function injectInterfaceSG() {
  814.     var bFound=0;
  815.     var i=0;
  816.     var refTarget;
  817.     var searchElement = '';
  818.     var searchHTML = '';
  819.     switch (whichPage) {
  820.         case 1:
  821.             searchElement = 'sidebar__shortcut-inner-wrap';
  822.             searchHTML = 'data-tooltip="Visit Steam Group"><i class="fa fa-fw fa-steam"></i></a>';
  823.             break;
  824.         case 2:
  825.             searchElement = 'page__heading__breadcrumbs';
  826.             searchHTML = '<a href="/account">Account</a><i class="fa fa-angle-right"></i><a href="/account/manage/whitelist">Whitelist</a>';
  827.             break;
  828.     }
  829.  
  830.     while(bFound===0) {
  831.         refTarget = document.getElementsByClassName(searchElement)[i];
  832.         if (refTarget.innerHTML.indexOf(searchHTML) >= 0) {
  833.             bFound = 1;
  834.         } else i++;
  835.     }
  836.  
  837.     GM_log(logHeader + 'Creating button/progress bar on SteamGifts...');
  838.     libraryDiv = document.createElement("DIV");
  839.     libraryDiv.id = "whitelist_ownership_checker";
  840.     switch (whichPage) {
  841.         case 1:
  842.             // Create button on left-hand navigation panel of group page.
  843.             libraryDiv.className = 'sidebar__shortcut-inner-wrap';
  844.             libraryDiv.innerHTML = "<span><i class='fa fa-arrow-circle-right'></i> Check game ownership</span>";
  845.             break;
  846.         case 2:
  847.             // Create button at top of WL page
  848.             libraryDiv.className = 'form__submit-button';
  849.             libraryDiv.innerHTML = "<span><i class='fa fa-arrow-circle-right'></i> Check game ownership</span>";
  850.             break;
  851.     }
  852.     getUserCounts();
  853.  
  854.     refTarget.parentNode.appendChild(libraryDiv);
  855.  
  856.     libraryDiv.addEventListener('click', function() {
  857.         var blackbg = document.getElementById('black-background');
  858.         var dlg = document.getElementById('SGLCdlg');
  859.         blackbg.style.display = 'block';
  860.         dlg.style.display = 'block';
  861.  
  862.         var winWidth = window.innerWidth;
  863.         var winHeight = window.innerHeight;
  864.  
  865.         dlg.style.left = (winWidth/2) - 500/2 + 'px';
  866.         dlg.style.top = '150px';
  867.     });
  868.  
  869.     GM_log(logHeader + 'Library checking button loaded without errors.');
  870. }
  871.  
  872. /**
  873.  * Identifies the proper location of user data, depending on page.
  874.  */
  875. function locateUserData() {
  876.     if (countToCheck < 0) {
  877.         getUserCounts();
  878.     }
  879.     switch (whichPage) {
  880.         case 0: // Steam Store
  881.                 if (appInput) {
  882.                     GM_log(logHeader + 'Scanning ' + countToCheck + ' total whitelisted users for game ' + appInput);
  883.                     readAllUserPages(urlWhitelist + "/search?page=", 1);
  884.                 }
  885.             break;
  886.         case 1: // SG Group Page
  887.             if (countToCheck > userLimit) {
  888.                 GM_log(logHeader + 'Too many users in the list. (' + countToCheck + '/' + userLimit + ') Stopping.');
  889.                 document.getElementById('SGLCdlg-output').value = 'There are more than ' + userLimit + ' users in this list. The Steam API limits how many API calls can be made at (10,000 per day), but the script likely will not work with this many users because of memory issues I have yet to work out.\n\n(FYI: The Steam user count will likely reflect a different amount than what is displayed on the SG group page. This is normal and is a result of a mix of SG user caching and Steam users not being a part of the SG site.)';
  890.             } else if (countToCheck === 0) {
  891.                 GM_log(logHeader + '0 users found. Stopping.');
  892.                 document.getElementById('SGLCdlg-output').value = 'There were no users found. This is probably an error in the script, but please make sure you are on a proper group page before trying. If you think you have done everything correctly, please report this error.';
  893.             } else {
  894.                 GM_log(logHeader + 'Number of users in the list is good. Continuing...');
  895.                 appInput = document.getElementById('SGLCdlg-AppID').value;
  896.                 if (appInput) {
  897.                     GM_log(logHeader + 'appInput is good: ' + appInput);
  898.                     if (!gameTitle) {
  899.                         GM_log(logHeader + 'Getting game title...');
  900.                         importJSONSteamGameDetail(appInput);
  901.                     }
  902.                     GM_log(logHeader + 'Scanning through ' + countToCheck + ' group users...');
  903.  
  904.                     // Parse out different variations in URL for alternate group page info screens.
  905.                     // In order to check the users, we have to grab the user page specifically.
  906.                     var groupURL = '';
  907.                     var indexUsers = window.location.href.indexOf('/users');
  908.                     var indexStats = window.location.href.indexOf('/stats') ;
  909.                     var indexWishlist = window.location.href.indexOf('/wishlist') ;
  910.                     if (indexUsers > 0) {
  911.                         groupURL = window.location.href.slice(0,indexUsers) + '/users/search?page=';
  912.                     } else if (indexStats > 0) {
  913.                         groupURL = window.location.href.slice(0,indexStats) + '/users/search?page=';
  914.                     } else if (indexWishlist > 0) {
  915.                         groupURL = window.location.href.slice(0,indexWishlist) + '/users/search?page=';
  916.                     } else {
  917.                         groupURL = window.location.href + '/users/search?page=';
  918.                     }
  919.                     readAllUserPages(groupURL, 1);
  920.                 } else {
  921.                     GM_log(logHeader + 'appInput is no good...');
  922.                 }
  923.             }
  924.             break;
  925.         case 2: // SG WL Page
  926.             if (countToCheck > userLimit) {
  927.                 document.getElementById('SGLCdlg-output').value = 'There are more than ' + userLimit + ' users in this list. The Steam API limits how many API calls can be made at one time, and the script likely will not work with this many users. (Steam API count may reflect a different amount than what is displayed on the SG group page.)';
  928.             } else {
  929.                 appInput = document.getElementById('SGLCdlg-AppID').value;
  930.                 if (appInput) {
  931.                     GM_log(logHeader + 'Scanning ' + countToCheck + ' total whitelisted users for game ' + appInput);
  932.                     readAllUserPages(urlWhitelist + "/search?page=", 1);
  933.                 }
  934.             }
  935.             break;
  936.     }
  937. }
  938.  
  939. /**
  940.  * Updates overall count statistics for reporting at the end of the checking process.
  941.  * @param {Number} hasGame - Ownership status with three possible values: 0 = does not have game, 1 = has game, 2 = error in checking
  942.  */
  943. function processCount(hasGame) {
  944.     // If countToCheck = 0, then we have no whitelist, or we want to terminate the script.
  945.     // Asnyc calls keep running, so this check appears multiple times in the code.
  946.     if (countToCheck > 0) {
  947.         totalScanned += 1;
  948.         GM_log(logHeader + "Processing " + totalScanned + " out of " + countToCheck + " total users");
  949.         switch (hasGame) {
  950.             case 0:
  951.                 //Does not have game.
  952.                 break;
  953.             case 1:
  954.                 //Has game.
  955.                 totalHave +=1;
  956.                 break;
  957.             case 2:
  958.                 //Bad data or API Key!
  959.                 break;
  960.         }
  961.     }
  962.  
  963.     if (totalScanned >= countToCheck) {
  964.         GM_log(logHeader + 'Wrapping up... If this is an early termination, async calls may post multiple times.');
  965.         wrapUp();
  966.     }
  967.    
  968.     updateCompletionPercent();
  969. }
  970.  
  971. /**
  972.  * Updates the current status of the running process.
  973.  */
  974. function updateCompletionPercent(){
  975.     var repPercent = (100*totalScanned/countToCheck).toFixed(1);
  976.    
  977.     if (whichPage === 0) {
  978.         libraryDiv.innerHTML = "<span>Scanning: " + repPercent + "% (" + totalHave + " have out of " + totalScanned + " scanned so far)</span>";
  979.     } else {
  980.         var repCheckType = "";
  981.         var dlgProgress = document.getElementById('SGLCdlg-progress');
  982.         dlgProgress.setAttribute('style','display:block;float:right;');
  983.         if (whichCheck === 0) {
  984.             repCheckType = "own"
  985.         } else {
  986.             repCheckType = "want";
  987.         }
  988.         dlgProgress.innerHTML = "<span><i class='fa fa-arrow-circle-right'></i>Scanning " + repPercent + "%<p>(" + totalHave + " " + repCheckType + " out of " + totalScanned + " scanned so far)</span>";
  989.     }
  990. }
  991.  
  992. /**
  993.  * Recursive function reading all whitelist/group pages from first to last to read/process each user on the list.
  994.  * @param {string} currentURL - The base URL for the whitelist.
  995.  * @param {Number} currentPage - The current page to scan. This increments each iteration of the recursion until it reaches the last page.
  996.  */
  997. function readAllUserPages(currentURL, currentPage) {
  998.     // If countToCheck = 0, then we have no whitelist, or we want to terminate the script.
  999.     // Asnyc calls keep running, so this check appears multiple times in the code.
  1000.     if (countToCheck > 0) {
  1001.         var newPage = parseInt(currentPage);
  1002.         var checkURL = currentURL + currentPage;
  1003.         GM_log(logHeader + 'Scanning user list [' + checkURL + '] for users...');
  1004.         GM_xmlhttpRequest({
  1005.             method: "GET",
  1006.             url: checkURL,
  1007.             onload: function(response) {
  1008.                 if (response){
  1009.                     var lastPage = userPages;
  1010.                     var lastURL = currentURL + lastPage;
  1011.                     GM_log(logHeader + 'Good response on XML load for page ' + currentPage + ' of ' + lastPage + '.');
  1012.                     if (lastPage >= currentPage) {
  1013.                         GM_log(logHeader + currentPage + '/' + lastPage);
  1014.                         if (apiKey) {
  1015.                             var rows = getUserRows(response.responseText);
  1016.                             var appID = appInput.split(','); // Right now, only works with single appID. Probably will stay this way.
  1017.                             for (var i = 0; i < rows.length; i++) {
  1018.                                 if( rows[i].className == "table__row-inner-wrap is-faded"){
  1019.                                     inactive+=1;
  1020.                                     processCount(2);
  1021.                                     }
  1022.                                 else
  1023.                                     checkHasGameInData(rows[i], appID);
  1024.                             }
  1025.                         }
  1026.                         GM_log(logHeader + 'User page loaded. Reading user data...');
  1027.                         readAllUserPages(currentURL, newPage + 1);
  1028.                     }
  1029.                 } else {
  1030.                     GM_log(logHeader + 'Error loading WL page...');
  1031.                 }
  1032.             }
  1033.         });
  1034.     } else {
  1035.         wrapUp();
  1036.     }
  1037. }
  1038.  
  1039. /**
  1040.  * Reads through stored user data (preventing additional API calls) to see if a game is owned by a particular user.
  1041.  * @param {Number} steamID - Steam user ID to check ownership
  1042.  * @param {Number} appID - Steam game ID to check ownership of
  1043.  */
  1044. function readStoredUserData(steamID, appID){
  1045.     var userData = null;
  1046.     var userVerb = '';
  1047.     switch (whichCheck) {
  1048.         case 0:
  1049.             userData = findUserInJSON(USER_OWN_DATA.userData, steamID);
  1050.             userVerb = ' owns ';
  1051.             break;
  1052.         case 1:
  1053.             userData = findUserInJSON(USER_WISH_DATA.userData, steamID);
  1054.             userVerb = ' wants ';
  1055.             break;
  1056.     }
  1057.  
  1058.     if (userData) {
  1059.         if (findGameInJSON(userData, appID, steamID)) {
  1060.             GM_log(logHeader + 'User ' + steamID + userVerb + 'game ' + appID + ' = True');
  1061.             processCount(1);
  1062.         } else {
  1063.             GM_log(logHeader + 'User ' + steamID + userVerb + 'game ' + appID + ' = False');
  1064.             processCount(0);
  1065.         }
  1066.     } else {
  1067.         processCount(2);
  1068.     }
  1069. }
  1070.  
  1071. /**
  1072.  * Resets the library/whitelist cache.
  1073.  */
  1074. function resetCache(){
  1075.     var ownCache = GM_getValue(keyStorageOwnData);
  1076.     var wantCache = GM_getValue(keyStorageWishData);
  1077.     if (ownCache !== undefined) {
  1078.         GM_log(logHeader + ownCache.slice(0,100));
  1079.     } else {
  1080.         GM_log(logHeader + 'Ownership cache: N/A');
  1081.     }
  1082.     if (wantCache !== undefined) {
  1083.         GM_log(logHeader + wantCache.slice(0,100));
  1084.     } else {
  1085.         GM_log(logHeader + 'Wishlist cache: N/A');
  1086.     }
  1087.     GM_deleteValue(keyStorageOwnData);
  1088.     GM_deleteValue(keyStorageWishData);
  1089.     USER_OWN_DATA = null;
  1090.     USER_WISH_DATA = null;
  1091.     ownCache = GM_getValue(keyStorageOwnData);
  1092.     wantCache = GM_getValue(keyStorageWishData);
  1093.     if (ownCache !== undefined) {
  1094.         GM_log(logHeader + ownCache.slice(0,100));
  1095.     } else {
  1096.         GM_log(logHeader + 'Ownership cache: N/A');
  1097.     }
  1098.     if (wantCache !== undefined) {
  1099.         GM_log(logHeader + wantCache.slice(0,100));
  1100.     } else {
  1101.         GM_log(logHeader + 'Wishlist cache: N/A');
  1102.     }
  1103. }
  1104.  
  1105. /**
  1106.  * Kicks off checking routine, choosing between group and whitelist modes.
  1107.  */
  1108. function startCheck() {
  1109.     startedWrapUp = false;
  1110.     var user_own_data = GM_getValue(keyStorageOwnData);
  1111.     var user_wish_data = GM_getValue(keyStorageWishData);
  1112.  
  1113.     if (userPages <= 0) {
  1114.         GM_log(logHeader + '0 user pages... trying to load again.');
  1115.         userPages = Math.ceil(countToCheck/25);
  1116.     }
  1117.  
  1118.     GM_log(logHeader + 'SG User Data Last updated: ' + LAST_UPDATED + ' - Needs to be updated if last updated before: ' + cacheDate);
  1119.     if (Date.parse(LAST_UPDATED) < Date.parse(cacheDate) || LAST_UPDATED === null) {
  1120.         GM_log(logHeader + 'Past update date, creating new cache.');
  1121.         USER_OWN_DATA = newJSONTemplate;
  1122.         USER_WISH_DATA = newJSONTemplate;
  1123.         resetCache();
  1124.     } else {
  1125.         GM_log(logHeader + 'Not past update date, checking previous cache.');
  1126.         if (user_own_data) {
  1127.             GM_log(logHeader + 'Ownership ache exists.');
  1128.             USER_OWN_DATA = JSON.parse(user_own_data);
  1129.             if (USER_OWN_DATA.version != cacheVersion) {
  1130.                 GM_log(logHeader + 'Ownership cache version update. Resetting...');
  1131.                 USER_OWN_DATA = newJSONTemplate;
  1132.             }
  1133.         } else {
  1134.             GM_log(logHeader + 'Ownership cache does not exist. Creating new...');
  1135.             USER_OWN_DATA = newJSONTemplate;
  1136.         }
  1137.         if (user_wish_data) {
  1138.             GM_log(logHeader + 'Wishlist cache exists.');
  1139.             USER_WISH_DATA = JSON.parse(user_wish_data);
  1140.             if (USER_WISH_DATA.version != cacheVersion) {
  1141.                 GM_log(logHeader + 'Wishlilst cache version update. Resetting...');
  1142.                 USER_WISH_DATA = newJSONTemplate;
  1143.             }
  1144.         } else {
  1145.             GM_log(logHeader + 'Wishlist cache does not exist. Creating new...');
  1146.             USER_WISH_DATA = newJSONTemplate;
  1147.         }
  1148.     }
  1149.  
  1150.     if(!apiKey) {
  1151.         GM_log(logHeader + 'API Key is not populated.');
  1152.         if (whichPage > 0) {
  1153.             apiKey = document.getElementById('SGLCdlg-APIKey').value;
  1154.         } else {
  1155.             apiKey = prompt("A Steam API Key is required to perform the lookup. Please enter your Steam API key:\n\n(You can get/generate your API key here: https://steamcommunity.com/dev/apikey)", "https://steamcommunity.com/dev/apikey");
  1156.         }
  1157.         if(apiKey) {
  1158.             GM_setValue('SGLCdlg-APIKey', apiKey);
  1159.         }
  1160.         document.getElementById('SGLCdlg-checkbuttonown').disabled = false;
  1161.         document.getElementById('SGLCdlg-checkbuttonwant').disabled = false;
  1162.         document.getElementById('SGLCdlg-cachebutton').disabled = false;
  1163.     } else {
  1164.         GM_log(logHeader + 'API Key is populated.');
  1165.         gameTitle = null;
  1166.         totalScanned = 0;
  1167.         totalHave = 0;
  1168.  
  1169.         locateUserData();
  1170.     }
  1171. }
  1172.  
  1173. /**
  1174. * Finalize data, output, and storage.
  1175. */
  1176. function wrapUp() {
  1177.     GM_log(logHeader + 'Checking if already wrapped up...');
  1178.     if (!startedWrapUp) {
  1179.         GM_log(logHeader + "...Not yet, so let's do it.");
  1180.         startedWrapUp = true;
  1181.         if ((Date.parse(LAST_UPDATED) < Date.parse(cacheDate)) || LAST_UPDATED === null) {
  1182.             /** Make sure to set the updated date so we know when to do a full refresh */
  1183.             GM_log(logHeader + 'Setting current date as update date.');
  1184.             GM_setValue(keyStorageUpdated, new Date());
  1185.         }
  1186.  
  1187.         GM_log(logHeader + 'Finishing up...');
  1188.         switch (whichCheck) {
  1189.             case 0:
  1190.                 GM_log(logHeader + 'Writing ownership cache.');
  1191.                 try {
  1192.                     GM_deleteValue(keyStorageOwnData);
  1193.                     GM_setValue(keyStorageOwnData, JSON.stringify(USER_OWN_DATA));
  1194.                     USER_OWN_DATA = null;
  1195.                 }
  1196.                 catch(e){
  1197.                     GM_log(logHeader + e.message);
  1198.                 }
  1199.                 break;
  1200.             case 1:
  1201.                 GM_log(logHeader + 'Writing wishlist cache.');
  1202.                 try {
  1203.                     GM_deleteValue(keyStorageWishData);
  1204.                     GM_setValue(keyStorageWishData, JSON.stringify(USER_WISH_DATA));
  1205.                     USER_WISH_DATA = null;
  1206.                     }
  1207.                 catch(e){
  1208.                     GM_log(logHeader + e.message);
  1209.                 }
  1210.                 break;
  1211.         }
  1212.  
  1213.         if (!apiKey) {
  1214.             if (whichPage > 0) {
  1215.                 document.getElementById('SGLCdlg-output').value = "A Steam API Key is required to perform the lookup. Please enter your Steam API in the box provided:\n\n(You can get/generate your API key here: https://steamcommunity.com/dev/apikey)";
  1216.             } else {
  1217.                 prompt("There was a problem with the request. This is possibly due to a bad API key being provided, but it may also be something I did, instead.\n\nPlease check your API key and try again. If the problem continues, please report a bug (copy link below)!","https://github.com/Gaffi/SG-WL-Inventory/issues");
  1218.             }
  1219.         }
  1220.  
  1221.         // If countToCheck == 0, then we have no user list, or we want to terminate the script.
  1222.         // Asnyc calls keep running, so this check appears multiple times in the code.
  1223.         if (countToCheck > 0) {
  1224.             GM_log(logHeader + 'Good user list count, normal output.');
  1225.             if (whichPage === 0) {
  1226.                 libraryDivOutput.innerHTML = "<span>SG♥: " + totalHave + "/" + totalScanned + " (" + Number((100*totalHave/totalScanned).toFixed(2)) + "%)</span>";
  1227.             } else {
  1228.                 document.getElementById('SGLCdlg-GameName').value = gameTitle;
  1229.                 document.getElementById('SGLCdlg-progress').setAttribute('style','display:none;');
  1230.                 var groupType = '';
  1231.                 var checkType = '';
  1232.  
  1233.                 if (whichPage == 1) {
  1234.                     groupType = 'this group';
  1235.                 } else {
  1236.                     groupType = 'your whitelist';
  1237.                 }
  1238.  
  1239.                 if (whichCheck === 0) {
  1240.                     checkType = 'library';
  1241.                 } else {
  1242.                     checkType = 'wishlist';
  1243.                 }
  1244.  
  1245.                 document.getElementById('SGLCdlg-checkbuttonown').disabled = false;
  1246.                 document.getElementById('SGLCdlg-checkbuttonwant').disabled = false;
  1247.                 document.getElementById('SGLCdlg-cachebutton').disabled = false;
  1248.                
  1249.                 if( inactive > 0 )
  1250.                     totalScanned -= inactive;
  1251.  
  1252.                 document.getElementById('SGLCdlg-output').value = 'Out of ' + totalScanned + (totalScanned == 1 ? ' user ' : ' users ') + 'in ' + groupType + ', ' + totalHave + ' ' + (totalHave == 1 ? 'has "' : 'have "') + gameTitle + '" in their ' + checkType + ' (' + Number((100*totalHave/totalScanned).toFixed(2)) + '%).';
  1253.                
  1254.                 if( inactive > 0 )
  1255.                     document.getElementById('SGLCdlg-output').value += "\r\n" + inactive + " inactive users ignored.";
  1256.             }
  1257.         } else {
  1258.             GM_log(logHeader + 'Whitelist count = 0, null output.');
  1259.             if (whichPage === 0) {
  1260.                 libraryDiv.innerHTML = "<span>SG Check</span>";
  1261.             } else {
  1262.                 document.getElementById('SGLCdlg-GameName').value = '<not loaded>';
  1263.                 document.getElementById('SGLCdlg-progress').setAttribute('style','display:none;');
  1264.                 if (countToCheck == -1) {
  1265.                     document.getElementById('SGLCdlg-output').value = 'Unable to load game data (name) from Steam. This could be a server or API problem, or you entered an invalid appID. Please try again.\n\nIf you cannot resolve, please report the error. Thanks!';
  1266.                 } else {
  1267.                     document.getElementById('SGLCdlg-output').value = 'There was an error loading data from Steam. This could be a server or API problem. Please try again.\n\nIf you cannot resolve, please report the error. Thanks!';
  1268.                 }
  1269.                 document.getElementById('SGLCdlg-checkbuttonown').disabled = false;
  1270.                 document.getElementById('SGLCdlg-checkbuttonwant').disabled = false;
  1271.                 document.getElementById('SGLCdlg-cachebutton').disabled = false;
  1272.             }
  1273.         }
  1274.     }
  1275. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement