Guest User

Dota 2 & CSGO Lounge item price displayer

a guest
Jun 26th, 2014
583
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name Dota 2 & CSGO Lounge item price displayer
  3. // @namespace http://www.enygma.ro
  4. // @version 2.2
  5. // @author Enygma
  6. // @description Displays an item's lowest price offer from the Steam Community Market and helps to copy an item's name or to quickly open the market listings for an item.
  7. // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
  8. // @include /^http(s)?://(www.)?dota2lounge.com//
  9. // @include /^http(s)?://(www.)?csgolounge.com//
  10. // @updateURL http://userscripts.org/scripts/source/182588.user.js
  11. // @downloadURL http://userscripts.org/scripts/source/182588.user.js
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_addStyle
  14. // ==/UserScript==
  15.  
  16. // Determine on which site is the script being executed (dota2lounge or csgolounge)
  17. if (document.URL.match(/^http(s)?:\/\/(www.)?dota2lounge.com\//)) {
  18. // Dota2 app ID on Steam's community market website.
  19. appID = 570;
  20.  
  21. // Generic item placeholder names used by the d2l website and not existing in the Steam Market.
  22. genericItemPlaceholderNames = ["Offers", "Any Common", "Any Uncommon", "Any Rare", "Any Mythical", "Any Legendary",
  23. "Any Ancient", "Any Immortal", "Real Money", "+ More", "Any Set"];
  24. } else if (document.URL.match(/^http(s)?:\/\/(www.)?csgolounge.com\//)) {
  25. // CS:GO app ID on Steam's community market website.
  26. appID = 730;
  27.  
  28. // Generic item placeholder names used by the csgolounge website and not existing in the Steam Market.
  29. genericItemPlaceholderNames = ["Any Offers", "Real Money", "Dota Items", "TF2 Items"];
  30. }
  31.  
  32. // Main event listener for hovering items.
  33. document.addEventListener("mouseover", function (event) {
  34. var itemElement = getItemElement(event);
  35. if (!itemElement) {
  36. return;
  37. }
  38.  
  39. attachExtraPanelAndListeners(itemElement);
  40. getLowestPrice(itemElement);
  41. })
  42.  
  43. // Get the hovered item, if any.
  44. var getItemElement = function(mouseEvent) {
  45. var targetElement = mouseEvent.target;
  46. var itemElement = null;
  47.  
  48. // Hover either the item element or its picture (child element).
  49. if (hasClass(targetElement, "item")) {
  50. itemElement = targetElement;
  51. } else if (hasClass(targetElement.parentNode, "item")) {
  52. itemElement = targetElement.parentNode;
  53. } else {
  54. return null;
  55. }
  56.  
  57. // Avoid returning empty item slots.
  58. var itemNameElement = itemElement.querySelector(".name");
  59. if (!itemNameElement) {
  60. return null;
  61. }
  62.  
  63. // Avoid returning generic item placeholders.
  64. var itemName = getItemName(itemElement);
  65. if (genericItemPlaceholderNames.indexOf(itemName) > -1) {
  66. return null;
  67. }
  68.  
  69. return itemElement;
  70. }
  71.  
  72. // Add to the specified item element an extra panel that contains the price information and a click handler to facilitate copying the item's name
  73. var attachExtraPanelAndListeners = function(itemElement) {
  74. var itemNamePanel = itemElement.querySelector(".name");
  75. // If the extra panel already exists, stop here.
  76. var extraPanel = itemNamePanel.querySelector(".extraPanel");
  77. if (extraPanel) {
  78. return;
  79. }
  80.  
  81. // Otherwise, create our own panel to append...
  82. extraPanel = document.createElement('div');
  83. extraPanel.innerHTML = "<span class='scriptStatus'>Ready</span>" +
  84. "<button type='button' class='extraButton refreshButton' title='Refresh'/>" +
  85. "<button type='button' class='extraButton steamMarketListingsButton' title='Show listings for the item on Steam Market'/>";
  86. extraPanel.setAttribute("class", "extraPanel");
  87.  
  88. // ...and append it.
  89. itemNamePanel.appendChild(extraPanel);
  90. // Set click event handler for the item's name panel so that the item name can be copied to the clipboard easier.
  91. itemNamePanel.addEventListener("click", copyItemNameHandler, false);
  92. // Set click event handler for the refresh button that re-fetches the item's price.
  93. var refreshButton = extraPanel.querySelector(".refreshButton");
  94. refreshButton.addEventListener("click", function(event) {
  95. event.stopPropagation();
  96. getLowestPrice(itemElement, true);
  97. }, false);
  98. // Set click event handler for the Steam market listings button that opens in a new tab.
  99. var steamMarketListingsButton = extraPanel.querySelector(".steamMarketListingsButton");
  100. steamMarketListingsButton.addEventListener("click", function(event) {
  101. event.stopPropagation();
  102. showSteamMarketListings(itemElement);
  103. }, false);
  104. }
  105.  
  106. // Get the lowest price for an item from the Steam market.
  107. var getLowestPrice = function(itemElement, override) {
  108. var itemNameElement = itemElement.querySelector(".name");
  109. // Don`t try to get the price if we've already retrieved it.
  110. if (!override && itemNameElement.querySelector(".scriptStatus").innerHTML != "Ready") {
  111. return;
  112. }
  113.  
  114. itemNameElement.querySelector(".scriptStatus").innerHTML = "Loading...";
  115. var url = getSteamMarketListingsURL(itemElement);
  116. GM_xmlhttpRequest({
  117. method: "GET",
  118. url: url,
  119. onload: function (response) {
  120. var httpResponse = response.responseText;
  121. var match = lowestPriceWithFeeRegExp.exec(httpResponse);
  122. var priceWithFee = "<span class='" + (match ?
  123. "itemMarketable'>" + match[1] :
  124. "itemNotMarketable'>Not Marketable") +
  125. "</span>";
  126. match = lowestPriceWithoutFeeRegExp.exec(httpResponse);
  127. var priceWithoutFee = match ? match[1] + " - without fee (seller receives)" : "";
  128. itemNameElement.querySelector(".scriptStatus").innerHTML = "<span title='" + priceWithoutFee + "'>" + priceWithFee + "</span>";
  129. }
  130. });
  131. }
  132.  
  133. // Computes the URL used to access the Steam market listings for a given item.
  134. var getSteamMarketListingsURL = function(itemElement) {
  135. var itemName = getItemName(itemElement);
  136. var itemNameEncoded = encodeURIComponent(itemName);
  137. var url = "http://steamcommunity.com/market/listings/" + appID + "/" + itemNameEncoded + "/";
  138.  
  139. return url;
  140. }
  141.  
  142. // Extract the item's name from a DOM item element.
  143. var getItemName = function(itemElement) {
  144. var itemNameElement = itemElement.querySelector(".name");
  145. var itemName = itemNameElement.querySelector("b").innerHTML.trim();
  146.  
  147. return itemName;
  148. }
  149.  
  150. // Cached RegExps used to read the item's value from the Steam page.
  151. var lowestPriceWithFeeRegExp = /<span class="market_listing_price market_listing_price_with_fee">\s*(.*?)\s*<\/span>/i;
  152. var lowestPriceWithoutFeeRegExp = /<span class="market_listing_price market_listing_price_without_fee">\s*(.*?)\s*<\/span>/i;
  153.  
  154. // Event handler to facilitate copying an item's name.
  155. var copyItemNameHandler = function(event) {
  156. var clickedElement = event.target;
  157.  
  158. // Avoid executing this handler if the "Remove item" button is clicked in a trade.
  159. if (excludedTags.indexOf(clickedElement.tagName) > -1 || excludedTags.indexOf(clickedElement.parentNode.tagName) > -1) {
  160. return;
  161. }
  162.  
  163. // Stop the element's parent (item) from getting the click event. This stops the item from being selected.
  164. event.stopPropagation();
  165.  
  166. // Make sure we select the item name element.
  167. var itemNameElement = clickedElement;
  168. while (!hasClass(itemNameElement, "name")) {
  169. itemNameElement = itemNameElement.parentNode;
  170. }
  171.  
  172. // Get and display the item's name.
  173. var itemName = itemNameElement.querySelector("b").innerHTML.trim();
  174. window.prompt("Press CTRL+C to copy the item's name:", itemName);
  175. }
  176.  
  177. // Tags that, if clicked on in an item name panel, should not execute the copyItemNameHandler.
  178. var excludedTags = ["A", "IMG"];
  179.  
  180. // Opens a new tab with the Steam market listings of a given item.
  181. var showSteamMarketListings = function(itemElement) {
  182. var url = getSteamMarketListingsURL(itemElement);
  183. var win = window.open(url, "_blank");
  184. if (win) {
  185. // Browser has allowed it to be opened.
  186. win.focus();
  187. } else {
  188. // Broswer has blocked it.
  189. alert("Please allow popups for this site in order to open the Steam market listings.");
  190. }
  191. }
  192.  
  193. // Helper method to check if an element has the specified class name.
  194. var hasClass = function(element, cls) {
  195. return element && (" " + element.className + " ").indexOf( " " + cls + " " ) > -1;
  196. }
  197.  
  198. // Style.
  199. GM_addStyle(".itemNotMarketable { color : red } .itemMarketable { color: green } .extraButton { margin-left: 0.3em; vertical-align: top; margin-top: -0.1em; border: 0; padding: 0; width: 16px; height: 16px; }");
  200. GM_addStyle(".refreshButton { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABOUlEQVQ4jc2RsUoDQRCGv32CXECzdjaWRiOCVSA+RdqAL6BFesUXOPUFbCWKJ2thkcRgxCa3cJUEQuCwExRjCi1sxiKXsElO6wz81e58888/sPhlESwxlhNaeP/+zRnO/wCMNaBDIbVZG/ztppLcLYdpgK3uSFgGc05WAnbX7pTcD5FCQ8lyMDOlQ4mQaO8lcRI6Q7wATxsGR32k9YUc9RFtiL1gZsoTq1jk7D3JxLEeFNtKLj6ZqNhWkppHSOvxO3GRFlb3J3mc2VEb/I2mktM3Jtp5UKINgUuProYJoMO+C8jWyGhDXO0hl0Ok2hutma2RcR1UsMjx6ySoA9fJkqGUryu5+UDydSW5azbn1wiJyjFSjp3bO4lrg19opJzacZEhJMIi688juYBkFT+9eRpUGYOmbr6Q9QvwBrFqSdh8NgAAAABJRU5ErkJggg==) no-repeat left center; }");
  201. GM_addStyle(".steamMarketListingsButton { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sIBhUuIxK7S5QAAAFbSURBVDjLY7x27QaDoYGhOQMDwwkGHEBEVJiBgYGBwcLalOHE0dMMb16/ZWBgYGA4f+E8IwM7G+d/fDg4LPD/8VNH/yOD46eO/ufh5P3Pzsb5H68B0tIycM08nLxwDDOEKANgmheumf3//////xeumQ0XJ2hAcFgg3ABkAOPHRsf9Z2LAA0rr8+HsRWvnwGl+IX6EIly29/T0wG3ctm0bShjk5mcjvBAcFojT7/hAbHQcxACYQElx6f+S4tL/e/bvxKtx4rT+/9LSMnDLGLApkpaWwTCopLgUq1cZcNkE88bxU0dRbETHTLDQxQUcbFzgSRcbYEmLymPYE3qYIbsqiWFq2zyGyOgIuOTJawcZCAEWBgYGhlWrV0PieMlCBhkZWQYGBgaGtbuWMKyZt5U4A2CGyCvKMaxZv5KBgYGBYc28DQzLVywnaADjlcvXGYyNjf4zkAHOnj3HDAAt54OFwXNyhAAAAABJRU5ErkJggg==) no-repeat left center; }");
RAW Paste Data