Fanatical 跨区价格查询

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

当前为 2018-04-07 提交的版本,查看 最新版本

  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.  
  59. var observer = new MutationObserver(function (mutations, me) {
  60. var content = document.querySelector('.content');
  61. if (content) {
  62. subObserver.observe(content, config);
  63. me.disconnect();
  64. }
  65. });
  66. observer.observe(target, config);
  67. })();
  68.  
  69. function addNormalButton(container) {
  70. var outsideContainer = document.createElement('div');
  71. outsideContainer.className = 'col-12 col-md-6 col-lg-12';
  72. container.appendChild(outsideContainer);
  73. var priceContainer = document.createElement('div');
  74. priceContainer.className = 'p-3 pl-md-1 pl-lg-3 card-block';
  75. priceContainer.id = 'checkPrice';
  76. outsideContainer.appendChild(priceContainer);
  77. var button = document.createElement('button');
  78. button.className = 'mt-3 cart-btn btn btn-primary btn-lg btn-block';
  79. button.id = 'checkPriceButton';
  80. button.onclick = checkPrice;
  81. var buttonText = document.createElement('b');
  82. buttonText.id = 'checkPriceButtonText';
  83. buttonText.appendChild(document.createTextNode('Check Price'));
  84. button.appendChild(buttonText);
  85. priceContainer.appendChild(button);
  86. var checkPriceList = document.createElement('div');
  87. checkPriceList.id = 'checkPriceList';
  88. checkPriceList.className = 'mt-3';
  89. priceContainer.appendChild(checkPriceList);
  90. }
  91.  
  92. function addStarDealButton(container) {
  93. var priceContainer = document.createElement('div');
  94. priceContainer.id = 'checkPrice';
  95. container.appendChild(priceContainer);
  96. var button = document.createElement('button');
  97. button.className = 'cart-btn btn btn-primary btn-lg';
  98. button.id = 'checkPriceButton';
  99. button.onclick = checkPrice;
  100. button.style = 'height: 48px; margin-left: 10px;';
  101. var buttonText = document.createElement('b');
  102. buttonText.id = 'checkPriceButtonText';
  103. buttonText.appendChild(document.createTextNode('Check Price'));
  104. button.appendChild(buttonText);
  105. priceContainer.appendChild(button);
  106. var checkPriceList = document.createElement('div');
  107. checkPriceList.id = 'checkPriceList';
  108. var title = document.getElementsByClassName('purchase-info-title')[0];
  109. title.appendChild(checkPriceList);
  110. }
  111.  
  112. function checkPrice() {
  113. var buttonText = document.getElementById('checkPriceButtonText');
  114. buttonText.innerText = 'Checking Price...';
  115. if (urlType == 'bundle') {
  116. var bundleName = document.URL.split('/')[5];
  117. GM_xmlhttpRequest({
  118. method: "GET",
  119. url: "https://api.fanatical.com/api/products/" + bundleName,
  120. onload: function (response) {
  121. var bundleData = JSON.parse(response.responseText);
  122. priceList.length = 0;
  123. for (var i = 0; i < bundleData.bundles.length; i++) {
  124. var bundlePrice = {};
  125. for (var j = 0; j < regionList.length; j++) {
  126. var priceItem = {
  127. 'price': bundleData.bundles[i].price[regionList[j]] / 100,
  128. 'targetCur': 0
  129. };
  130. bundlePrice[regionList[j]] = priceItem;
  131. }
  132. priceList.push(bundlePrice);
  133. }
  134. fetchCurrency(buttonText);
  135. }
  136. });
  137. } else if (urlType == 'game' || urlType == 'dlc') {
  138. var gameName = document.URL.split('/')[5];
  139. GM_xmlhttpRequest({
  140. method: "GET",
  141. url: "https://api.fanatical.com/api/products/" + gameName,
  142. onload: function (response) {
  143. var gameData = JSON.parse(response.responseText);
  144. var discount = 1.0;
  145. if('current_discount' in gameData && 'percent'in gameData.current_discount){
  146. discount = 1 - gameData.current_discount.percent;
  147. }
  148. priceList.length = 0;
  149. gamePrice = {};
  150. for (var i = 0; i < regionList.length; i++) {
  151. var priceItem = {
  152. 'price': gameData.price[regionList[i]] * discount / 100,
  153. 'targetCur': 0
  154. };
  155. gamePrice[regionList[i]] = priceItem;
  156. }
  157. priceList.push(gamePrice);
  158. fetchCurrency(buttonText);
  159. }
  160. });
  161. }
  162. }
  163.  
  164. function fetchCurrency(buttonText) {
  165. for (var k = 0; k < regionList.length; k++) {
  166. GM_xmlhttpRequest({
  167. method: "GET",
  168. url: "https://finance.google.cn/finance/converter?a=1&from=" + regionList[k] + "&to=" + targetCur,
  169. context: {
  170. 'region': regionList[k],
  171. },
  172. onload: function (response) {
  173. var responseDocument = new DOMParser().parseFromString(response.responseText, "text/html");
  174. var result = responseDocument.getElementById('currency_converter_result').innerText;
  175. curList[response.context.region] = extractCurrency(result);
  176. if (Object.keys(curList).length >= regionList.length) {
  177. buttonText.innerText = 'Finished!';
  178. if (urlType == 'bundle') {
  179. displayBundleResult();
  180. } else if (urlType == 'game' || urlType == 'dlc') {
  181. displayGameResult();
  182. }
  183. }
  184. }
  185. });
  186. }
  187. }
  188.  
  189. function extractCurrency(str) {
  190. return parseFloat(str.trim().split(' ')[3]);
  191. }
  192.  
  193. function displayBundleResult() {
  194. var cheapList = [];
  195. for (var i = 0; i < priceList.length; i++) {
  196. var cheapPrice = 10000.0;
  197. var cheapRegion = 'USD';
  198. for (var j = 0; j < regionList.length; j++) {
  199. var priceItem = priceList[i][regionList[j]];
  200. priceItem.targetCur = (curList[regionList[j]] * priceItem.price);
  201. if (priceItem.targetCur < cheapPrice) {
  202. cheapPrice = priceItem.targetCur;
  203. cheapRegion = regionList[j];
  204. }
  205. }
  206. cheapList.push(cheapRegion);
  207. }
  208. // RENDER
  209. var c = document.getElementById('checkPriceList');
  210. while (c.firstChild) {
  211. c.removeChild(c.firstChild);
  212. }
  213. for (var k = 0; k < priceList.length; k++) {
  214. var container = document.createElement('div');
  215. container.className = 'mt-3';
  216. c.appendChild(container);
  217. var titleText = document.createElement('b');
  218. titleText.appendChild(document.createTextNode('Tier ' + (k + 1).toString()));
  219. var title = document.createElement('h4');
  220. title.appendChild(titleText);
  221. container.appendChild(title);
  222. for (var l = 0; l < regionList.length; l++) {
  223. var priceText;
  224. if (regionList[l] == cheapList[k]) {
  225. priceText = document.createElement('b');
  226. } else {
  227. priceText = document.createElement('span');
  228. }
  229. var priceValue = priceList[k][regionList[l]];
  230. priceText.appendChild(document.createTextNode(priceValue.price.toFixed(2) + ' ' + regionList[l] + ' = ' + priceValue.targetCur.toFixed(2) + ' ' + targetCur));
  231. container.appendChild(priceText);
  232. container.appendChild(document.createElement('br'));
  233. }
  234. }
  235. }
  236.  
  237. function displayGameResult() {
  238. var cheapPrice = 10000.0;
  239. var cheapRegion = 'USD';
  240. for (var j = 0; j < regionList.length; j++) {
  241. var priceItem = priceList[0][regionList[j]];
  242. priceItem.targetCur = (curList[regionList[j]] * priceItem.price);
  243. if (priceItem.targetCur < cheapPrice) {
  244. cheapPrice = priceItem.targetCur;
  245. cheapRegion = regionList[j];
  246. }
  247. }
  248. // RENDER
  249. var c = document.getElementById('checkPriceList');
  250. while (c.firstChild) {
  251. c.removeChild(c.firstChild);
  252. }
  253. var container = document.createElement('div');
  254. container.className = 'mt-3';
  255. c.appendChild(container);
  256. for (var l = 0; l < regionList.length; l++) {
  257. var priceText;
  258. if (regionList[l] == cheapRegion) {
  259. priceText = document.createElement('b');
  260. } else {
  261. priceText = document.createElement('span');
  262. }
  263. var priceValue = priceList[0][regionList[l]];
  264. priceText.appendChild(document.createTextNode(priceValue.price.toFixed(2) + ' ' + regionList[l] + ' = ' + priceValue.targetCur.toFixed(2) + ' ' + targetCur));
  265. container.appendChild(priceText);
  266. container.appendChild(document.createElement('br'));
  267. }
  268. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址