Fanatical 跨区价格查询

查询不同区域的Fanatical游戏/慈善包的价格

安装此脚本
作者推荐脚本

您可能也喜欢Steam Bundle Sites Extension

安装此脚本
  1. // ==UserScript==
  2. // @name Fanatical Price Checker
  3. // @name:zh-CN Fanatical 跨区价格查询
  4. // @name:zh-TW Fanatical 跨區價格查詢
  5. // @namespace https://www.fanatical.com/
  6. // @version 0.3.1
  7. // @description Check the price of different regions for Fanatical.
  8. // @description:zh-CN 查询不同区域的Fanatical游戏/慈善包的价格
  9. // @description:zh-TW 查詢不同區域的Fanatical遊戲/慈善包的價格
  10. // @icon https://cdn.fanatical.com/production/icons/android-chrome-192x192.png
  11. // @author Thesharing
  12. // @license MIT
  13. // @include /^https?://www\.fanatical\.com/en/bundle/.+$
  14. // @include /^https?://www\.fanatical\.com/en/game/.+$
  15. // @include /^https?://www\.fanatical\.com/en/dlc/.+$
  16. // @grant GM_xmlhttpRequest
  17. // @run-at document-idle
  18. // ==/UserScript==
  19.  
  20. var totalNum = 0;
  21. var priceList = [];
  22. var regionList = ["USD", "CAD", "EUR", "GBP"];
  23. var curList = {};
  24. var urlType = document.URL.split('/')[4];
  25. var targetCur = "CNY";
  26.  
  27. (function () {
  28. 'use strict';
  29. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  30. var target = document.querySelector('#root');
  31. var config = {
  32. attributes: true,
  33. childList: true,
  34. characterData: true
  35. };
  36. var continuousObserver = new MutationObserver(function (mutations, me) {
  37. var normalPageContainer = document.getElementsByClassName('product-commerce-container');
  38. var starDealPageContainer = document.getElementsByClassName('purchase-info-container');
  39. if (starDealPageContainer.length > 0){
  40. console.log('STARDEAL');
  41. addStarDealButton(starDealPageContainer[0]);
  42. }
  43. if (normalPageContainer.length > 0) {
  44. console.log('NORMAL');
  45. addNormalButton(normalPageContainer[0]);
  46. }
  47. });
  48.  
  49. var subObserver = new MutationObserver(function (mutations, me) {
  50. var normalPageContainer = document.getElementsByClassName('product-commerce-container');
  51. if (normalPageContainer.length > 0) {
  52. addNormalButton(normalPageContainer[0]);
  53. var subContent = document.querySelector('.content').querySelector('div');
  54. continuousObserver.observe(subContent, config);
  55. me.disconnect();
  56. }
  57. });
  58. var observer = new MutationObserver(function (mutations, me) {
  59. var content = document.querySelector('.content');
  60. if (content) {
  61. subObserver.observe(content, config);
  62. me.disconnect();
  63. }
  64. });
  65. observer.observe(target, config);
  66. })();
  67.  
  68. function addNormalButton(container) {
  69. var outsideContainer = document.createElement('div');
  70. outsideContainer.className = 'col-12 col-md-6 col-lg-12';
  71. container.appendChild(outsideContainer);
  72. var priceContainer = document.createElement('div');
  73. priceContainer.className = 'p-3 pl-md-1 pl-lg-3 card-block';
  74. priceContainer.id = 'checkPrice';
  75. outsideContainer.appendChild(priceContainer);
  76. var button = document.createElement('button');
  77. button.className = 'mt-3 cart-btn btn btn-primary btn-lg btn-block';
  78. button.id = 'checkPriceButton';
  79. button.onclick = checkPrice;
  80. var buttonText = document.createElement('b');
  81. buttonText.id = 'checkPriceButtonText';
  82. buttonText.appendChild(document.createTextNode('Check Price'));
  83. button.appendChild(buttonText);
  84. priceContainer.appendChild(button);
  85. var checkPriceList = document.createElement('div');
  86. checkPriceList.id = 'checkPriceList';
  87. checkPriceList.className = 'mt-3';
  88. priceContainer.appendChild(checkPriceList);
  89. }
  90.  
  91. function addStarDealButton(container) {
  92. var priceContainer = document.createElement('div');
  93. priceContainer.id = 'checkPrice';
  94. container.appendChild(priceContainer);
  95. var button = document.createElement('button');
  96. button.className = 'cart-btn btn btn-primary btn-lg';
  97. button.id = 'checkPriceButton';
  98. button.onclick = checkPrice;
  99. button.style = 'height: 48px; margin-left: 10px;';
  100. var buttonText = document.createElement('b');
  101. buttonText.id = 'checkPriceButtonText';
  102. buttonText.appendChild(document.createTextNode('Check Price'));
  103. button.appendChild(buttonText);
  104. priceContainer.appendChild(button);
  105. var checkPriceList = document.createElement('div');
  106. checkPriceList.id = 'checkPriceList';
  107. var title = document.getElementsByClassName('purchase-info-title')[0];
  108. title.appendChild(checkPriceList);
  109. }
  110.  
  111. function checkPrice() {
  112. var buttonText = document.getElementById('checkPriceButtonText');
  113. buttonText.innerText = 'Checking Price...';
  114. if (urlType == 'bundle') {
  115. var bundleName = document.URL.split('/')[5];
  116. GM_xmlhttpRequest({
  117. method: "GET",
  118. url: "https://api.fanatical.com/api/products/" + bundleName,
  119. onload: function (response) {
  120. var bundleData = JSON.parse(response.responseText);
  121. priceList.length = 0;
  122. for (var i = 0; i < bundleData.bundles.length; i++) {
  123. var bundlePrice = {};
  124. for (var j = 0; j < regionList.length; j++) {
  125. var priceItem = {
  126. 'price': bundleData.bundles[i].price[regionList[j]] / 100,
  127. 'targetCur': 0
  128. };
  129. bundlePrice[regionList[j]] = priceItem;
  130. }
  131. priceList.push(bundlePrice);
  132. }
  133. fetchCurrency(buttonText);
  134. }
  135. });
  136. } else if (urlType == 'game' || urlType == 'dlc') {
  137. var gameName = document.URL.split('/')[5];
  138. GM_xmlhttpRequest({
  139. method: "GET",
  140. url: "https://api.fanatical.com/api/products/" + gameName,
  141. onload: function (response) {
  142. var gameData = JSON.parse(response.responseText);
  143. var discount = 1.0;
  144. if('current_discount' in gameData && 'percent'in gameData.current_discount){
  145. discount = 1 - gameData.current_discount.percent;
  146. }
  147. priceList.length = 0;
  148. gamePrice = {};
  149. for (var i = 0; i < regionList.length; i++) {
  150. var priceItem = {
  151. 'price': gameData.price[regionList[i]] * discount / 100,
  152. 'targetCur': 0
  153. };
  154. gamePrice[regionList[i]] = priceItem;
  155. }
  156. priceList.push(gamePrice);
  157. fetchCurrency(buttonText);
  158. }
  159. });
  160. }
  161. }
  162.  
  163. function fetchCurrency(buttonText) {
  164. for (var k = 0; k < regionList.length; k++) {
  165. GM_xmlhttpRequest({
  166. method: "GET",
  167. url: "https://finance.google.cn/finance/converter?a=1&from=" + regionList[k] + "&to=" + targetCur,
  168. context: {
  169. 'region': regionList[k],
  170. },
  171. onload: function (response) {
  172. var responseDocument = new DOMParser().parseFromString(response.responseText, "text/html");
  173. var result = responseDocument.getElementById('currency_converter_result').innerText;
  174. curList[response.context.region] = extractCurrency(result);
  175. if (Object.keys(curList).length >= regionList.length) {
  176. buttonText.innerText = 'Finished!';
  177. if (urlType == 'bundle') {
  178. displayBundleResult();
  179. } else if (urlType == 'game' || urlType == 'dlc') {
  180. displayGameResult();
  181. }
  182. }
  183. }
  184. });
  185. }
  186. }
  187.  
  188. function extractCurrency(str) {
  189. return parseFloat(str.trim().split(' ')[3]);
  190. }
  191.  
  192. function displayBundleResult() {
  193. var cheapList = [];
  194. for (var i = 0; i < priceList.length; i++) {
  195. var cheapPrice = 10000.0;
  196. var cheapRegion = 'USD';
  197. for (var j = 0; j < regionList.length; j++) {
  198. var priceItem = priceList[i][regionList[j]];
  199. priceItem.targetCur = (curList[regionList[j]] * priceItem.price);
  200. if (priceItem.targetCur < cheapPrice) {
  201. cheapPrice = priceItem.targetCur;
  202. cheapRegion = regionList[j];
  203. }
  204. }
  205. cheapList.push(cheapRegion);
  206. }
  207. // RENDER
  208. var c = document.getElementById('checkPriceList');
  209. while (c.firstChild) {
  210. c.removeChild(c.firstChild);
  211. }
  212. for (var k = 0; k < priceList.length; k++) {
  213. var container = document.createElement('div');
  214. container.className = 'mt-3';
  215. c.appendChild(container);
  216. var titleText = document.createElement('b');
  217. titleText.appendChild(document.createTextNode('Tier ' + (k + 1).toString()));
  218. var title = document.createElement('h4');
  219. title.appendChild(titleText);
  220. container.appendChild(title);
  221. for (var l = 0; l < regionList.length; l++) {
  222. var priceText;
  223. if (regionList[l] == cheapList[k]) {
  224. priceText = document.createElement('b');
  225. } else {
  226. priceText = document.createElement('span');
  227. }
  228. var priceValue = priceList[k][regionList[l]];
  229. priceText.appendChild(document.createTextNode(priceValue.price.toFixed(2) + ' ' + regionList[l] + ' = ' + priceValue.targetCur.toFixed(2) + ' ' + targetCur));
  230. container.appendChild(priceText);
  231. container.appendChild(document.createElement('br'));
  232. }
  233. }
  234. }
  235.  
  236. function displayGameResult() {
  237. var cheapPrice = 10000.0;
  238. var cheapRegion = 'USD';
  239. for (var j = 0; j < regionList.length; j++) {
  240. var priceItem = priceList[0][regionList[j]];
  241. priceItem.targetCur = (curList[regionList[j]] * priceItem.price);
  242. if (priceItem.targetCur < cheapPrice) {
  243. cheapPrice = priceItem.targetCur;
  244. cheapRegion = regionList[j];
  245. }
  246. }
  247. // RENDER
  248. var c = document.getElementById('checkPriceList');
  249. while (c.firstChild) {
  250. c.removeChild(c.firstChild);
  251. }
  252. var container = document.createElement('div');
  253. container.className = 'mt-3';
  254. c.appendChild(container);
  255. for (var l = 0; l < regionList.length; l++) {
  256. var priceText;
  257. if (regionList[l] == cheapRegion) {
  258. priceText = document.createElement('b');
  259. } else {
  260. priceText = document.createElement('span');
  261. }
  262. var priceValue = priceList[0][regionList[l]];
  263. priceText.appendChild(document.createTextNode(priceValue.price.toFixed(2) + ' ' + regionList[l] + ' = ' + priceValue.targetCur.toFixed(2) + ' ' + targetCur));
  264. container.appendChild(priceText);
  265. container.appendChild(document.createElement('br'));
  266. }
  267. }