'use strict'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // ==UserScript== // @name Steam Bundle Sites Extension // @homepage https://github.com/clancy-chao/Steam-Bundle-Sites-Extension // @namespace http://tampermonkey.net/ // @version 2.4.0 // @description A steam bundle sites' tool kits. // @icon http://store.steampowered.com/favicon.ico // @author Bisumaruko, Cloud // @include http*://store.steampowered.com/* // @include https://www.indiegala.com/gift* // @include https://www.indiegala.com/profile* // @include https://www.indiegala.com/game* // @include https://www.fanatical.com/* // @include https://www.humblebundle.com/* // @include http*://*dailyindiegame.com/* // @include http*://bundle.ccyycn.com/order/* // @include https://groupees.com/purchases // @include https://groupees.com/profile/purchases/* // @include http*://*agiso.com/* // @include https://steamdb.steamcn.com/tooltip* // @include https://yuplay.ru/orders/*/ // @include https://yuplay.ru/product/*/ // @include http://gama-gama.ru/personal/settings/* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/7.18.0/sweetalert2.min.js // @resource sweetalert2CSS https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/7.18.0/sweetalert2.min.css // @resource currencyFlags https://cdnjs.cloudflare.com/ajax/libs/currency-flags/1.5.0/currency-flags.min.css // @resource flagIcon https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.min.css // @connect store.steampowered.com // @connect www.google.com // @connect www.google.com.tw // @connect www.google.com.au // @connect www.google.co.jp // @connect www.google.co.nz // @connect www.google.co.uk // @connect www.google.ca // @connect www.google.de // @connect www.google.it // @connect www.google.fr // @connect www.ecb.europa.eu // @connect steamdb.steamcn.com // @connect steamdb.info // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_getResourceText // @grant unsafeWindow // @run-at document-start // @downloadURL none // ==/UserScript== /* global swal */ // setup jQuery var $ = jQuery.noConflict(true); $.fn.pop = [].pop; $.fn.shift = [].shift; // inject external css styles GM_addStyle(GM_getResourceText('sweetalert2CSS')); GM_addStyle(GM_getResourceText('currencyFlags')); GM_addStyle(GM_getResourceText('flagIcon').replace(/\.\.\//g, 'https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/')); // inject script css styles GM_addStyle('\n pre.SBSE_errorMsg { height: 200px; text-align: left; white-space: pre-wrap; }\n\n /* settings */\n .SBSE_settings .name { text-align: right; vertical-align: top; }\n .SBSE_settings .value { text-align: left; }\n .SBSE_settings .value > * { height: 30px; margin: 0 20px 10px; }\n .SBSE_settings .switch { position: relative; display: inline-block; width: 60px; }\n .SBSE_settings .switch input { display: none; }\n .SBSE_settings .slider {\n position: absolute;\n top: 0; right: 0; bottom: 0; left: 0;\n background-color: #CCC;\n transition: 0.4s;\n cursor: pointer;\n }\n .SBSE_settings .slider:before {\n width: 26px; height: 26px;\n position: absolute;\n bottom: 2px; left: 2px;\n background-color: white;\n transition: 0.4s;\n content: "";\n }\n .SBSE_settings input:checked + .slider { background-color: #2196F3; }\n .SBSE_settings input:focus + .slider { box-shadow: 0 0 1px #2196F3; }\n .SBSE_settings input:checked + .slider:before { transform: translateX(30px); }\n .SBSE_settings > span { display: inline-block; color: white; cursor: pointer; }\n\n /* container */\n .SBSE_container {\n width: 100%; height: 200px;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n }\n .SBSE_container > textarea {\n width: 100%; height: 150px;\n padding: 5px;\n border: none;\n box-sizing: border-box;\n resize: none;\n outline: none;\n }\n .SBSE_container > div { width: 100%; padding-top: 5px; box-sizing: border-box; }\n .SBSE_container > div > button, .SBSE_container > div > a {\n width: 120px;\n position: relative;\n margin-right: 10px;\n line-height: 28px;\n transition: all 0.5s;\n box-sizing: border-box;\n outline: none;\n cursor: pointer;\n }\n .SBSE_container > div > a { display: inline-block; text-align: center; }\n .SBSE_container select { max-width:120px; height: 30px; }\n .SBSE_container label { margin-right: 10px; }\n #SBSE_BtnSettings {\n width: 20px; height: 20px;\n float: right;\n margin-top: 3px; margin-right: 0; margin-left: 10px;\n background-color: transparent;\n background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iMzJweCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzIgMzI7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzMiAzMiIgd2lkdGg9IjMycHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxnIGlkPSJMYXllcl8xIi8+PGcgaWQ9ImNvZyI+PHBhdGggZD0iTTMyLDE3Ljk2OXYtNGwtNC43ODEtMS45OTJjLTAuMTMzLTAuMzc1LTAuMjczLTAuNzM4LTAuNDQ1LTEuMDk0bDEuOTMtNC44MDVMMjUuODc1LDMuMjUgICBsLTQuNzYyLDEuOTYxYy0wLjM2My0wLjE3Ni0wLjczNC0wLjMyNC0xLjExNy0wLjQ2MUwxNy45NjksMGgtNGwtMS45NzcsNC43MzRjLTAuMzk4LDAuMTQxLTAuNzgxLDAuMjg5LTEuMTYsMC40NjlsLTQuNzU0LTEuOTEgICBMMy4yNSw2LjEyMWwxLjkzOCw0LjcxMUM1LDExLjIxOSw0Ljg0OCwxMS42MTMsNC43MDMsMTIuMDJMMCwxNC4wMzF2NGw0LjcwNywxLjk2MWMwLjE0NSwwLjQwNiwwLjMwMSwwLjgwMSwwLjQ4OCwxLjE4OCAgIGwtMS45MDIsNC43NDJsMi44MjgsMi44MjhsNC43MjMtMS45NDVjMC4zNzksMC4xOCwwLjc2NiwwLjMyNCwxLjE2NCwwLjQ2MUwxNC4wMzEsMzJoNGwxLjk4LTQuNzU4ICAgYzAuMzc5LTAuMTQxLDAuNzU0LTAuMjg5LDEuMTEzLTAuNDYxbDQuNzk3LDEuOTIybDIuODI4LTIuODI4bC0xLjk2OS00Ljc3M2MwLjE2OC0wLjM1OSwwLjMwNS0wLjcyMywwLjQzOC0xLjA5NEwzMiwxNy45Njl6ICAgIE0xNS45NjksMjJjLTMuMzEyLDAtNi0yLjY4OC02LTZzMi42ODgtNiw2LTZzNiwyLjY4OCw2LDZTMTkuMjgxLDIyLDE1Ljk2OSwyMnoiIHN0eWxlPSJmaWxsOiM0RTRFNTA7Ii8+PC9nPjwvc3ZnPg==);\n background-size: contain;\n background-repeat: no-repeat;\n background-origin: border-box;\n border: none;\n vertical-align: top;\n }\n\n /* spinner button affect */\n .SBSE_container > div > button:before {\n width: 20px; height: 20px;\n content: \'\';\n position: absolute;\n margin-top: 5px;\n right: 10px;\n border: 3px solid;\n border-left-color: transparent;\n border-radius: 50%;\n box-sizing: border-box;\n opacity: 0;\n transition: opacity 0.5s;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n animation-name: rotate;\n animation-timing-function: linear;\n }\n .SBSE_container > div > button.narrow.working {\n width: 100px;\n padding-right: 40px;\n transition: all 0.5s;\n }\n .SBSE_container > div > button.working:before {\n transition-delay: 0.5s;\n transition-duration: 1s;\n opacity: 1;\n }\n @keyframes rotate {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n /* icons */\n .SBSE_icon {\n width: 20px; height: 20px;\n display: none;\n border-radius: 50%;\n background-color: #E87A90;\n transform: rotate(45deg);\n }\n .SBSE_icon:before, .SBSE_icon:after {\n content: \'\';\n width: 3px; height: 14px;\n position: absolute;\n top: 50%; left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n border-radius: 5px;\n pointer-events: none;\n }\n .SBSE_icon:after { transform: translate(-50%, -50%) rotate(-90deg); }\n .SBSE_owned .SBSE_icon { background-color: #9CCC65; }\n .SBSE_owned .SBSE_icon:before, .SBSE_owned .SBSE_icon:after { transform: none; }\n .SBSE_owned .SBSE_icon:before {\n width: 3px; height: 11px;\n top: 4px; left: 10px;\n border-radius: 5px 5px 5px 0;\n }\n .SBSE_owned .SBSE_icon:after {\n width: 5px; height: 3px;\n top: 12px; left: 6px;\n border-radius: 5px 0 0 5px;\n }\n .SBSE_wished .SBSE_icon { transform: rotate(0); background-color: #29B6F6; }\n .SBSE_wished .SBSE_icon:before, .SBSE_wished .SBSE_icon:after {\n width: 6px; height: 10px;\n top: 5px; left: 10px;\n border-radius: 6px 6px 0 0;\n transform: rotate(-45deg);\n transform-origin: 0 100%;\n }\n .SBSE_wished .SBSE_icon:after {\n left: 4px;\n transform: rotate(45deg);\n transform-origin :100% 100%;\n }\n .isSteam .SBSE_icon { display: inline-block; }\n\n /* Steam Tooltip */\n .SBSE_tooltip {\n width: 308px;\n position: fixed;\n overflow: hidden;\n background: url(https://steamstore-a.akamaihd.net/public/images/v6/blue_body_darker_repeat.jpg) -700px center repeat-y scroll rgb(0, 0, 0);\n border: 0;\n box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);\n transition: all 0.5s;\n z-index: 999;\n }\n .SBSE_tooltip.SBSE_hide { display: none; }\n\n /* Tooltip */\n [tooltip]::before, [tooltip]::after {\n position: absolute;\n opacity: 0;\n transition: all 0.15s ease;\n }\n [tooltip]::before {\n width: max-content;\n content: attr(tooltip);\n top: calc(100% + 10px); left: 0;\n padding: 10px;\n color: #4a4c45;\n background-color: white;\n border-radius: 3px;\n box-shadow: 1px 2px 3px rgba(0,0,0,0.45);\n }\n [tooltip]::after {\n content: "";\n top: calc(100% + 5px); left: 10px;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n border-bottom: 5px solid white;\n }\n [tooltip]:hover::before, [tooltip]:hover::after { opacity: 1; }\n [tooltip]:not([tooltip-persistent])::before, [tooltip]:not([tooltip-persistent])::after { pointer-events: none; }\n'); // load up var regKey = /(?:(?:([A-Z0-9])(?!\1{4})){5}-){2,5}[A-Z0-9]{5}/g; var eol = "\r\n"; var has = Object.prototype.hasOwnProperty; var unique = function unique(a) { return [].concat(_toConsumableArray(new Set(a))); }; var config = { data: JSON.parse(GM_getValue('SBSE_config', '{}')), set: function set(key, value, callback) { this.data[key] = value; GM_setValue('SBSE_config', JSON.stringify(this.data)); if (typeof callback === 'function') callback(); }, get: function get(key) { return has.call(this.data, key) ? this.data[key] : null; }, init: function init() { if (!has.call(this.data, 'autoUpdateSessionID')) this.data.autoUpdateSessionID = true; if (!has.call(this.data, 'preselectIncludeTitle')) this.data.preselectIncludeTitle = false; if (!has.call(this.data, 'titleComesLast')) this.data.titleComesLast = false; if (!has.call(this.data, 'preselectJoinKeys')) this.data.preselectJoinKeys = false; if (!has.call(this.data, 'joinKeysASFStyle')) this.data.joinKeysASFStyle = true; if (!has.call(this.data, 'activateAllKeys')) this.data.activateAllKeys = false; if (!has.call(this.data, 'enableTooltips')) this.data.enableTooltips = this.get('language') !== 'english'; } }; var i18n = { data: { tchinese: { name: '繁體中文', updateSuccessTitle: '更新成功!', updateSuccess: '成功更新Steam sessionID', successStatus: '成功', successDetail: '無資料', skippedStatus: '跳過', activatedDetail: '已啟動', failStatus: '失敗', failTitle: '糟糕!', failDetailUnexpected: '發生未知錯誤,請稍後再試', failDetailInvalidKey: '序號錯誤', failDetailUsedKey: '序號已被使用', failDetailRateLimited: '啟動受限', failDetailCountryRestricted: '地區限制', failDetailAlreadyOwned: '產品已擁有', failDetailMissingBaseGame: '未擁有主程式', failDetailPS3Required: '需要PS3 啟動', failDetailGiftWallet: '偵測到禮物卡/錢包序號', failDetailParsingFailed: '處理資料發生錯誤,請稍後再試', failDetailRequestFailedNeedUpdate: '請求發生錯誤,請稍後再試
或者嘗試更新SessionID', noItemDetails: '無產品詳細資料', notLoggedInTitle: '未登入', notLoggedInMsg: '請登入Steam 以讓腳本紀錄SessionID', missingTitle: '未發現SessionID', missingMsg: '請問要更新SessionID 嗎?', emptyInput: '未發現Steam 序號', settingsTitle: '設定', settingsAutoUpdateSessionID: '自動更新SessionID', settingsSessionID: '我的SessionID', settingsSyncLibrary: '同步遊戲庫資料', settingsSyncLibraryButton: '同步', settingsLanguage: '語言', settingsPreselectIncludeTitle: '預選包括遊戲名', settingsTitleComesLast: '遊戲名置後', settingsPreselectJoinKeys: '預選合併序號', settingsJoinKeysASFStyle: '合併ASF 格式序號', settingsActivateAllKeys: '不跳過、啟動所有序號', settingsEnableTooltips: 'SteamCN 論壇提示框', HBAlreadyOwned: '遊戲已擁有', HBRedeemAlreadyOwned: '確定刮開 %title% Steam 序號?', HBActivationRestrictions: '啟動限制', HBDisallowedCountries: '限制以下地區啟動', HBExclusiveCountries: '僅限以下地區啟動', HBCurrentLocation: '當前位於:', DIGEasyBuyPurchase: '購買', DIGEasyBuySelectAll: '全選', DIGEasyBuySelectCancel: '取消', DIGEasyBuyHideOwned: '隱藏已擁有', DIGEasyBuyShowOwned: '顯示已擁有', DIGEasyBuyLoadAllPages: '加載所有頁', DIGEasyBuyLoading: '加載第%page%頁中', DIGEasyBuyLoadingComplete: '加載完成', DIGButtonPurchasing: '購買中', DIGInsufficientFund: '餘額不足,準備回到帳號頁', DIGMarketSearchResult: '目前市集上架中', DIGRateAllPositive: '全部好評', DIGClickToHideThisRow: '隱藏此上架遊戲', buttonReveal: '刮開', buttonRetrieve: '提取', buttonActivate: '啟動', buttonCopy: '複製', buttonReset: '清空', buttonExport: '匯出', checkboxIncludeGameTitle: '遊戲名', checkboxJoinKeys: '合併', checkboxSkipUsed: '跳過已使用', checkboxMarketListings: '上架於市集', selectFilterAll: '選取全部', selectFilterOwned: '選取已擁有', selectFilterNotOwned: '選取未擁有', selectConnector: '至', markAllAsUsed: '標記全部已使用', syncSuccessTitle: '同步成功', syncSuccess: '成功同步Steam 遊戲庫資料', syncFailTitle: '同步失敗', syncFail: '失敗同步Steam 遊戲庫資料', visitSteam: '前往Steam', lastSyncTime: '已於%seconds% 秒前同步收藏庫' }, schinese: { name: '简体中文', updateSuccessTitle: '更新成功', updateSuccess: '成功更新Steam sessionID', successStatus: '成功', successDetail: '无信息', activatedDetail: '已激活', skippedStatus: '跳过', failStatus: '失败', failTitle: '糟糕!', failDetailUnexpected: '发生未知错误,请稍后再试', failDetailInvalidKey: '激活码错误', failDetailUsedKey: '激活码已被使用', failDetailRateLimited: '激活受限', failDetailCountryRestricted: '地区限制', failDetailAlreadyOwned: '产品已拥有', failDetailMissingBaseGame: '未拥有基础游戏', failDetailPS3Required: '需要PS3 激活', failDetailGiftWallet: '侦测到礼物卡/钱包激活码', failDetailParsingFailed: '处理资料发生错误,请稍后再试', failDetailRequestFailedNeedUpdate: '请求发生错误,请稍后再试
或者尝试更新SessionID', noItemDetails: '无产品详细信息', notLoggedInTitle: '未登入', notLoggedInMsg: '请登入Steam 以让脚本记录SessionID', missingTitle: '未发现SessionID', missingMsg: '请问要更新SessionID 吗?', emptyInput: '未批配到Steam 激活码', settingsTitle: '设置', settingsAutoUpdateSessionID: '自动更新SessionID', settingsSessionID: '我的SessionID', settingsSyncLibrary: '同步游戏库资料', settingsSyncLibraryButton: '同步', settingsLanguage: '语言', settingsPreselectIncludeTitle: '预选包括游戏名', settingsTitleComesLast: '游戏名置后', settingsPreselectJoinKeys: '预选合并激活码', settingsJoinKeysASFStyle: '合并ASF 格式激活码', settingsActivateAllKeys: '不跳过、激活所有激活码', settingsEnableTooltips: 'SteamCN 论坛提示窗', HBAlreadyOwned: '游戏已拥有', HBRedeemAlreadyOwned: '确定刮开 %title% Steam 激活码?', HBActivationRestrictions: '激活限制', HBDisallowedCountries: '限制以下地区激活', HBExclusiveCountries: '仅限以下地区激活', HBCurrentLocation: '当前位于:', DIGEasyBuyPurchase: '购买', DIGEasyBuySelectAll: '全选', DIGEasyBuySelectCancel: '取消', DIGEasyBuyHideOwned: '隐藏已拥有', DIGEasyBuyShowOwned: '显示已拥有', DIGEasyBuyLoadAllPages: '加载所有页', DIGEasyBuyLoading: '加载第%page%页中', DIGEasyBuyLoadingComplete: '加载完成', DIGButtonPurchasing: '购买中', DIGInsufficientFund: '余额不足,准备回到账号页', DIGMarketSearchResult: '目前市集上架中', DIGRateAllPositive: '全部好评', DIGClickToHideThisRow: '隐藏此上架游戏', buttonReveal: '刮开', buttonRetrieve: '提取', buttonActivate: '激活', buttonCopy: '复制', buttonReset: '清空', buttonExport: '导出', checkboxIncludeGameTitle: '游戏名', checkboxJoinKeys: '合并', checkboxSkipUsed: '跳过已使用', checkboxMarketListings: '上架于市集', selectFilterAll: '选取全部', selectFilterOwned: '选取已拥有', selectFilterNotOwned: '选取未拥有', selectConnector: '至', markAllAsUsed: '标记全部已使用', syncSuccessTitle: '同步成功', syncSuccess: '成功同步Steam 游戏库资料', syncFailTitle: '同步失败', syncFail: '失败同步Steam 游戏库资料', visitSteam: '前往Steam', lastSyncTime: '已于%seconds% 秒前同步游戏库' }, english: { name: 'English', updateSuccessTitle: 'Update Successful!', updateSuccess: 'Steam sessionID is successfully updated', successStatus: 'Success', successDetail: 'No Detail', activatedDetail: 'Activated', skippedStatus: 'Skipped', failStatus: 'Fail', failTitle: 'Opps!', failDetailUnexpected: 'Unexpected Error', failDetailInvalidKey: 'Invalid Key', failDetailUsedKey: 'Used Key', failDetailRateLimited: 'Rate Limited', failDetailCountryRestricted: 'Country Restricted', failDetailAlreadyOwned: 'Product Already Owned', failDetailMissingBaseGame: 'Missing Base Game', failDetailPS3Required: 'PS3 Activation Required', failDetailGiftWallet: 'Gift Card/Wallet Code Detected', failDetailParsingFailed: 'Result parse failed', failDetailRequestFailedNeedUpdate: 'Request failed, please try again
or update sessionID', noItemDetails: 'No Item Details', notLoggedInTitle: 'Not Logged-In', notLoggedInMsg: 'Please login to Steam so sessionID can be saved', missingTitle: 'Missing SessionID', missingMsg: 'Do you want to update your Steam sessionID?', emptyInput: 'Could not find Steam code', settingsTitle: 'Settings', settingsAutoUpdateSessionID: 'Auto Update SessionID', settingsSessionID: 'Your sessionID', settingsSyncLibrary: 'Sync Library Data', settingsSyncLibraryButton: 'Sync', settingsLanguage: 'Language', settingsPreselectIncludeTitle: 'Pre-select Include Title', settingsTitleComesLast: 'Title Comes Last', settingsPreselectJoinKeys: 'Pre-select Join Keys', settingsJoinKeysASFStyle: 'Join Keys w/ ASF Style', settingsActivateAllKeys: 'No skip & activate all keys', settingsEnableTooltips: 'Tooltips from SteamCN', HBAlreadyOwned: 'Game Already Owned', HBRedeemAlreadyOwned: 'Are you sure to redeem %title% Steam Key?', HBActivationRestrictions: 'Activation Restrictions', HBDisallowedCountries: 'Cannot be activated in the following regions', HBExclusiveCountries: 'Can only be activated in the following regions', HBCurrentLocation: 'Current Location: ', DIGEasyBuyPurchase: 'Purchase', DIGEasyBuySelectAll: 'Select All', DIGEasyBuySelectCancel: 'Cancel', DIGEasyBuyHideOwned: 'Hide Owned', DIGEasyBuyShowOwned: 'Show Owned', DIGEasyBuyLoadAllPages: 'Load All Pages', DIGEasyBuyLoading: 'Loading page %page%', DIGEasyBuyLoadingComplete: 'Loaded', DIGButtonPurchasing: 'Purchassing', DIGInsufficientFund: 'Insufficient fund, returning to account page', DIGMarketSearchResult: 'Currently listing in marketplace', DIGRateAllPositive: 'Mark All Positive', DIGClickToHideThisRow: 'Hide this game from listings', buttonReveal: 'Reveal', buttonRetrieve: 'Retrieve', buttonActivate: 'Activate', buttonCopy: 'Copy', buttonReset: 'Reset', buttonExport: 'Export', checkboxIncludeGameTitle: 'Game Title', checkboxJoinKeys: 'Join', checkboxSkipUsed: 'Skip Used', checkboxMarketListings: 'Market Listings', selectFilterAll: 'Select All', selectFilterOwned: 'Select Owned', selectFilterNotOwned: 'Select Not Owned', selectConnector: 'to', markAllAsUsed: 'Mark All as Used', syncSuccessTitle: 'Sync Successful', syncSuccess: 'Successfully sync Steam library data', syncFailTitle: 'Sync failed', syncFail: 'Failed to sync Steam library data', visitSteam: 'Visit Steam', lastSyncTime: 'Library data synced %seconds% seconds ago' } }, language: null, set: function set() { var selectedLanguage = has.call(this.data, config.get('language')) ? config.get('language') : 'english'; this.language = this.data[selectedLanguage]; }, get: function get(key) { return has.call(this.language, key) ? this.language[key] : this.data.english[key]; }, init: function init() { this.set(); } }; var ISO2 = { name: { tchinese: { AD: '安道爾', AE: '阿拉伯聯合大公國', AF: '阿富汗', AG: '安地卡及巴布達', AI: '安圭拉', AL: '阿爾巴尼亞', AM: '亞美尼亞', AO: '安哥拉', AQ: '南極洲', AR: '阿根廷', AS: '美屬薩摩亞', AT: '奧地利', AU: '澳大利亞', AW: '阿魯巴', AX: '奧蘭', AZ: '亞塞拜然', BA: '波士尼亞與赫塞哥維納', BB: '巴貝多', BD: '孟加拉', BE: '比利時', BF: '布吉納法索', BG: '保加利亞', BH: '巴林', BI: '蒲隆地', BJ: '貝南', BL: '聖巴泰勒米', BM: '百慕達', BN: '汶萊', BO: '玻利維亞', BQ: '波奈', BR: '巴西', BS: '巴哈馬', BT: '不丹', BV: '布威島', BW: '波札那', BY: '白俄羅斯', BZ: '貝里斯', CA: '加拿大', CC: '科科斯(基林)群島', CD: '剛果民主共和國', CF: '中非共和國', CG: '剛果共和國', CH: '瑞士', CI: '象牙海岸', CK: '庫克群島', CL: '智利', CM: '喀麥隆', CN: '中國', CO: '哥倫比亞', CR: '哥斯大黎加', CS: '塞爾維亞與蒙特內哥羅', CU: '古巴', CV: '維德角', CW: '古拉索', CX: '聖誕島', CY: '賽普勒斯', CZ: '捷克', DE: '德國', DJ: '吉布地', DK: '丹麥', DM: '多米尼克', DO: '多明尼加', DZ: '阿爾及利亞', EC: '厄瓜多', EE: '愛沙尼亞', EG: '埃及', EH: '西撒哈拉', ER: '厄利垂亞', ES: '西班牙', ET: '衣索比亞', FI: '芬蘭', FJ: '斐濟', FK: '福克蘭群島', FM: '密克羅尼西亞聯邦', FO: '法羅群島', FR: '法國', GA: '加彭', GB: '英國', GD: '格瑞那達', GE: '喬治亞', GF: '法屬圭亞那', GG: '根西', GH: '迦納', GI: '直布羅陀', GL: '格陵蘭', GM: '甘比亞', GN: '幾內亞', GP: '瓜德羅普', GQ: '赤道幾內亞', GR: '希臘', GS: '南喬治亞與南桑威奇', GT: '瓜地馬拉', GU: '關島', GW: '幾內亞比索', GY: '蓋亞那', HK: '香港', HM: '赫德島和麥克唐納群島', HN: '宏都拉斯', HR: '克羅埃西亞', HT: '海地', HU: '匈牙利', ID: '印尼', IE: '愛爾蘭', IL: '以色列', IM: '曼島', IN: '印度', IO: '英屬印度洋領地', IQ: '伊拉克', IR: '伊朗', IS: '冰島', IT: '義大利', JE: '澤西', JM: '牙買加', JO: '約旦', JP: '日本', KE: '肯亞', KG: '吉爾吉斯', KH: '柬埔寨', KI: '吉里巴斯', KM: '葛摩', KN: '聖克里斯多福及尼維斯', KP: '北韓', KR: '南韓', KW: '科威特', KY: '開曼群島', KZ: '哈薩克', LA: '寮國', LB: '黎巴嫩', LC: '聖露西亞', LI: '列支敦斯登', LK: '斯里蘭卡', LR: '賴比瑞亞', LS: '賴索托', LT: '立陶宛', LU: '盧森堡', LV: '拉脫維亞', LY: '利比亞', MA: '摩洛哥', MC: '摩納哥', MD: '摩爾多瓦', ME: '蒙特內哥羅', MF: '法屬聖馬丁', MG: '馬達加斯加', MH: '馬紹爾群島', MK: '馬其頓共和國', ML: '馬利', MM: '緬甸', MN: '蒙古', MO: '澳門', MP: '北馬里亞納群島', MQ: '馬丁尼克', MR: '茅利塔尼亞', MS: '蒙哲臘', MT: '馬爾他', MU: '模里西斯', MV: '馬爾地夫', MW: '馬拉威', MX: '墨西哥', MY: '馬來西亞', MZ: '莫三比克', NA: '納米比亞', NC: '新喀里多尼亞', NE: '尼日', NF: '諾福克島', NG: '奈及利亞', NI: '尼加拉瓜', NL: '荷蘭', NO: '挪威', NP: '尼泊爾', NR: '諾魯', NU: '紐埃', NZ: '紐西蘭', OM: '阿曼', PA: '巴拿馬', PE: '秘魯', PF: '法屬玻里尼西亞', PG: '巴布亞紐幾內亞', PH: '菲律賓', PK: '巴基斯坦', PL: '波瀾', PM: '聖皮耶與密克隆群島', PN: '皮特肯群島', PR: '波多黎各', PS: '巴勒斯坦', PT: '葡萄牙', PW: '帛琉', PY: '巴拉圭', QA: '卡達', RE: '留尼旺', RO: '羅馬尼亞', RS: '塞爾維亞', RU: '俄羅斯', RW: '盧安達', SA: '沙烏地阿拉伯', SB: '索羅門群島', SC: '塞席爾', SD: '蘇丹', SE: '瑞典', SG: '新加坡', SH: '聖赫勒拿、亞森欣與垂斯坦昆哈', SI: '斯洛維尼亞', SJ: '斯瓦巴和揚馬延', SK: '斯洛伐克', SL: '獅子山共和國', SM: '聖馬利諾', SN: '塞內加爾', SO: '索馬利亞', SR: '蘇利南', SS: '南蘇丹', ST: '聖多美普林西比', SV: '薩爾瓦多', SX: '荷屬聖馬丁', SY: '敘利亞', SZ: '史瓦濟蘭', TC: '土克凱可群島', TD: '查德', TF: '法屬南部和南極領地', TG: '多哥', TH: '泰國', TJ: '塔吉克', TK: '托克勞', TL: '東帝汶', TM: '土庫曼', TN: '突尼西亞', TO: '東加', TR: '土耳其', TT: '千里達及托巴哥', TV: '吐瓦魯', TW: '臺灣', TZ: '坦尚尼亞', UA: '烏克蘭', UG: '烏干達', UM: '美國本土外小島嶼', US: '美國', UY: '烏拉圭', UZ: '烏茲別克', VA: '聖座', VC: '聖文森及格瑞那丁', VE: '委內瑞拉', VG: '英屬維京群島', VI: '美屬維京群島', VN: '越南', VU: '萬那杜', WF: '瓦利斯和富圖納', WS: '薩摩亞', XK: '科索沃', YE: '葉門', YT: '馬約特', ZA: '南非', ZM: '尚比亞', ZW: '辛巴威' }, schinese: { AD: '安道尔', AE: '阿拉伯联合酋长国', AF: '阿富汗', AG: '安提瓜和巴布达', AI: '安圭拉', AL: '阿尔巴尼亚', AM: '亚美尼亚', AO: '安哥拉', AQ: '南极洲', AR: '阿根廷', AS: '美属萨摩亚', AT: '奥地利', AU: '澳大利亚', AW: '阿鲁巴', AX: '奥兰群岛', AZ: '阿塞拜疆', BA: '波斯尼亚和黑塞哥维那', BB: '巴巴多斯', BD: '孟加拉', BE: '比利时', BF: '布基纳法索', BG: '保加利亚', BH: '巴林', BI: '布隆迪', BJ: '贝宁', BL: '圣巴托洛缪岛', BM: '百慕大', BN: '文莱', BO: '玻利维亚', BQ: '博奈尔', BR: '巴西', BS: '巴哈马', BT: '不丹', BV: '布韦岛', BW: '博兹瓦纳', BY: '白俄罗斯', BZ: '伯利兹', CA: '加拿大', CC: '科科斯(基林)群岛', CD: '刚果(金)', CF: '中非共和国', CG: '刚果(布)', CH: '瑞士', CI: '科特迪瓦', CK: '库克群岛', CL: '智利', CM: '喀麦隆', CN: '中国', CO: '哥伦比亚', CR: '哥斯达黎加', CS: '塞尔维亚和黑山', CU: '古巴', CV: '佛得角', CW: '库拉索', CX: '圣诞岛', CY: '塞浦路斯', CZ: '捷克', DE: '德国', DJ: '吉布提', DK: '丹麦', DM: '多米尼克', DO: '多米尼加', DZ: '阿尔及利亚', EC: '厄瓜多尔', EE: '爱沙尼亚', EG: '埃及', EH: '西撒哈拉', ER: '厄立特里亚', ES: '西班牙', ET: '埃塞俄比亚', FI: '芬兰', FJ: '斐济', FK: '福克兰群岛', FM: '密克罗尼西亚', FO: '法罗群岛', FR: '法国', GA: '加蓬', GB: '英国', GD: '格林纳达', GE: '格鲁吉亚', GF: '法属圭亚那', GG: '根西', GH: '加纳', GI: '直布罗陀', GL: '格陵兰', GM: '冈比亚', GN: '几内亚', GP: '瓜德鲁普', GQ: '赤道几内亚', GR: '希腊', GS: '南乔治亚岛和南桑威奇群岛', GT: '危地马拉', GU: '关岛', GW: '几内亚比绍', GY: '圭亚那', HK: '香港', HM: '赫德岛和麦克唐纳群岛', HN: '洪都拉斯', HR: '克罗地亚', HT: '海地', HU: '匈牙利', ID: '印尼', IE: '爱尔兰', IL: '以色列', IM: '马恩岛', IN: '印度', IO: '英属印度洋领地', IQ: '伊拉克', IR: '伊朗', IS: '冰岛', IT: '意大利', JE: '泽西岛', JM: '牙买加', JO: '约旦', JP: '日本', KE: '肯尼亚', KG: '吉尔吉斯', KH: '柬埔寨', KI: '基里巴斯', KM: '科摩罗', KN: '圣基茨和尼维斯', KP: '朝鲜', KR: '韩国', KW: '科威特', KY: '开曼群岛', KZ: '哈萨克斯坦', LA: '老挝', LB: '黎巴嫩', LC: '圣卢西亚', LI: '列支敦士登', LK: '斯里兰卡', LR: '利比里亚', LS: '莱索托', LT: '立陶宛', LU: '卢森堡', LV: '拉脱维亚', LY: '利比亚', MA: '摩洛哥', MC: '摩纳哥', MD: '摩尔多瓦', ME: '黑山', MF: '法属圣马丁', MG: '马达加斯加', MH: '马绍尔群岛', MK: '马其顿', ML: '马里', MM: '缅甸', MN: '蒙古', MO: '澳门', MP: '北马里亚纳群岛', MQ: '马提尼克', MR: '毛里塔尼亚', MS: '蒙塞拉特', MT: '马耳他', MU: '毛里求斯', MV: '马尔代夫', MW: '马拉维', MX: '墨西哥', MY: '马来西亚', MZ: '莫桑比克', NA: '纳米比亚', NC: '新喀里多尼亚', NE: '尼日尔', NF: '诺福克岛', NG: '尼日利', NI: '尼加拉瓜', NL: '荷兰', NO: '挪威', NP: '尼泊尔', NR: '瑙鲁', NU: '纽埃', NZ: '新西兰', OM: '阿曼', PA: '巴拿马', PE: '秘鲁', PF: '法属波利尼西亚a', PG: '巴布亚新几内亚', PH: '菲律宾', PK: '巴基斯坦', PL: '波兰', PM: '圣皮埃尔和密克隆', PN: '皮特凯恩群岛', PR: '波多黎各', PS: '巴勒斯坦', PT: '葡萄牙', PW: '帕劳', PY: '巴拉圭', QA: '卡塔尔', RE: '留尼旺島', RO: '罗马尼亚', RS: '塞尔维亚', RU: '俄罗斯', RW: '卢旺达', SA: '沙特阿拉伯', SB: '所罗门群岛', SC: '塞舌尔', SD: '苏丹', SE: '瑞典', SG: '新加坡', SH: '圣赫勒拿、阿森松与特斯坦达库尼亚', SI: '斯洛文尼', SJ: '斯瓦尔巴群岛和扬马延岛', SK: '斯洛伐克', SL: '塞拉利昂', SM: '圣马力诺', SN: '塞内加尔', SO: '索马里', SR: '苏里南', SS: '南苏丹', ST: '圣多美和普林西比', SV: '萨尔瓦多', SX: '荷属圣马丁', SY: '叙利亚', SZ: '斯威士兰', TC: '特克斯和凯科斯群岛', TD: '乍得', TF: '法属南部领土', TG: '多哥', TH: '泰国', TJ: '塔吉克斯坦', TK: '托克劳', TL: '东帝汶', TM: '土库曼斯坦', TN: '突尼斯', TO: '汤加', TR: '土耳其', TT: '特立尼达和多巴哥', TV: '图瓦卢', TW: '台湾', TZ: '坦桑尼亚', UA: '乌克兰', UG: '乌干达', UM: '美国本土外小岛屿', US: '美国', UY: '乌拉圭', UZ: '乌兹别克斯坦', VA: '圣座', VC: '圣文森特和格林纳丁斯', VE: '委内瑞拉', VG: '英属维尔京群岛', VI: '美属维尔京群岛', VN: '越南', VU: '瓦努阿图', WF: '瓦利斯和富图纳群岛', WS: '萨摩亚', XK: '科索沃', YE: '也门', YT: '马约特', ZA: '南非', ZM: '赞比亚', ZW: '津巴布韦' }, english: { AD: 'Andorra', AE: 'United Arab Emirates', AF: 'Afghanistan', AG: 'Antigua and Barbuda', AI: 'Anguilla', AL: 'Albania', AM: 'Armenia', AO: 'Angola', AQ: 'Antarctica', AR: 'Argentina', AS: 'American Samoa', AT: 'Austria', AU: 'Australia', AW: 'Aruba', AX: 'Aland Islands', AZ: 'Azerbaijan', BA: 'Bosnia and Herzegovina', BB: 'Barbados', BD: 'Bangladesh', BE: 'Belgium', BF: 'Burkina Faso', BG: 'Bulgaria', BH: 'Bahrain', BI: 'Burundi', BJ: 'Benin', BL: 'Saint Barthélemy', BM: 'Bermuda', BN: 'Brunei', BO: 'Bolivia', BQ: 'Bonaire', BR: 'Brazil', BS: 'Bahamas', BT: 'Bhutan', BV: 'Bouvet Island', BW: 'Botswana', BY: 'Belarus', BZ: 'Belize', CA: 'Canada', CC: 'Cocos (Keeling) Islands', CD: 'East Congo', CF: 'Central African Republic', CG: 'West Congo', CH: 'Switzerland', CI: 'Ivory Coast', CK: 'Cook Islands', CL: 'Chile', CM: 'Cameroon', CN: 'China', CO: 'Colombia', CR: 'Costa Rica', CS: 'Serbia and Montenegro', CU: 'Cuba', CV: 'Cabo Verde', CW: 'Curaçao', CX: 'Christmas Island', CY: 'Cyprus', CZ: 'Czechia', DE: 'Germany', DJ: 'Djibouti', DK: 'Denmark', DM: 'Dominica', DO: 'Dominican Republic', DZ: 'Algeria', EC: 'Ecuador', EE: 'Estonia', EG: 'Egypt', EH: 'Western Sahara', ER: 'Eritrea', ES: 'Spain', ET: 'Ethiopia', FI: 'Finland', FJ: 'Fiji', FK: 'Falkland Islands', FM: 'Micronesia', FO: 'Faroe Islands', FR: 'France', GA: 'Gabon', GB: 'United Kingdom', GD: 'Grenada', GE: 'Georgia', GF: 'French Guiana', GG: 'Guernsey', GH: 'Ghana', GI: 'Gibraltar', GL: 'Greenland', GM: 'Gambia', GN: 'Guinea', GP: 'Guadeloupe', GQ: 'Equatorial Guinea', GR: 'Greece', GS: 'South Georgia and the South Sandwich Islands', GT: 'Guatemala', GU: 'Guam', GW: 'Guinea-Bissau', GY: 'Guyana', HK: 'Hong Kong', HM: 'Heard Island and McDonald Islands', HN: 'Honduras', HR: 'Croatia', HT: 'Haiti', HU: 'Hungary', ID: 'Indonesia', IE: 'Ireland', IL: 'Israel', IM: 'Isle of Man', IN: 'India', IO: 'British Indian Ocean Territory', IQ: 'Iraq', IR: 'Iran', IS: 'Iceland', IT: 'Italy', JE: 'Jersey', JM: 'Jamaica', JO: 'Jordan', JP: 'Japan', KE: 'Kenya', KG: 'Kyrgyzstan', KH: 'Cambodia', KI: 'Kiribati', KM: 'Comoros', KN: 'Saint Kitts and Nevis', KP: 'North Korea', KR: 'South Korea', KW: 'Kuwait', KY: 'Cayman Islands', KZ: 'Kazakhstan', LA: 'Lao', LB: 'Lebanon', LC: 'Saint Lucia', LI: 'Liechtenstein', LK: 'Sri Lanka', LR: 'Liberia', LS: 'Lesotho', LT: 'Lithuania', LU: 'Luxembourg', LV: 'Latvia', LY: 'Libya', MA: 'Morocco', MC: 'Monaco', MD: 'Moldova', ME: 'Montenegro', MF: 'Saint Martin (French part)', MG: 'Madagascar', MH: 'Marshall Islands', MK: 'Macedonia', ML: 'Mali', MM: 'Myanmar', MN: 'Mongolia', MO: 'Macao', MP: 'Northern Mariana Islands', MQ: 'Martinique', MR: 'Mauritania', MS: 'Montserrat', MT: 'Malta', MU: 'Mauritius', MV: 'Maldives', MW: 'Malawi', MX: 'Mexico', MY: 'Malaysia', MZ: 'Mozambique', NA: 'Namibia', NC: 'New Caledonia', NE: 'Niger', NF: 'Norfolk Island', NG: 'Nigeria', NI: 'Nicaragua', NL: 'Netherlands', NO: 'Norway', NP: 'Nepal', NR: 'Nauru', NU: 'Niue', NZ: 'New Zealand', OM: 'Oman', PA: 'Panama', PE: 'Peru', PF: 'French Polynesia', PG: 'Papua New Guinea', PH: 'Philippines', PK: 'Pakistan', PL: 'Poland', PM: 'Saint Pierre and Miquelon', PN: 'Pitcairn', PR: 'Puerto Rico', PS: 'Palestine', PT: 'Portugal', PW: 'Palau', PY: 'Paraguay', QA: 'Qatar', RE: 'Reunion', RO: 'Romania', RS: 'Serbia', RU: 'Russia', RW: 'Rwanda', SA: 'Saudi Arabia', SB: 'Solomon Islands', SC: 'Seychelles', SD: 'Sudan', SE: 'Sweden', SG: 'Singapore', SH: 'Saint Helena, Ascension and Tristan da Cunha', SI: 'Slovenia', SJ: 'Svalbard and Jan Mayen', SK: 'Slovakia', SL: 'Sierra Leone', SM: 'San Marino', SN: 'Senegal', SO: 'Somalia', SR: 'Suriname', SS: 'South Sudan', ST: 'Sao Tome and Principe', SV: 'El Salvador', SX: 'Sint Maarten (Dutch part)', SY: 'Syria', SZ: 'Swaziland', TC: 'Turks and Caicos Islands', TD: 'Chad', TF: 'French Southern Territories', TG: 'Togo', TH: 'Thailand', TJ: 'Tajikistan', TK: 'Tokelau', TL: 'Timor-Leste', TM: 'Turkmenistan', TN: 'Tunisia', TO: 'Tonga', TR: 'Turkey', TT: 'Trinidad and Tobago', TV: 'Tuvalu', TW: 'Taiwan', TZ: 'Tanzania', UA: 'Ukraine', UG: 'Uganda', UM: 'United States Minor Outlying Islands', US: 'United States', UY: 'Uruguay', UZ: 'Uzbekistan', VA: 'Holy See', VC: 'Saint Vincent and the Grenadines', VE: 'Venezuela', VG: 'Virgin Islands, British', VI: 'Virgin Islands, U.S.', VN: 'Viet Nam', VU: 'Vanuatu', WF: 'Wallis and Futuna', WS: 'Samoa', XK: 'Kosovo', YE: 'Yemen', YT: 'Mayotte', ZA: 'South Africa', ZM: 'Zambia', ZW: 'Zimbabwe' } }, get: function get(code, language) { var data = this.name[language || config.get('language') || 'english']; return has.call(data, code) ? data[code] : code; } }; var xe = { exchangeRate: JSON.parse(GM_getValue('SBSE_xe', '{}')), currencies: { AUD: { english: 'Australian Dollar', tchinese: '澳幣', schinese: '澳元', symbol: 'AU$' }, CAD: { english: 'Canadian Dollar', tchinese: '加幣', schinese: '加元', symbol: 'CA$' }, CNY: { english: 'Chinese Yuan', tchinese: '人民幣', schinese: '人民币', symbol: 'CN¥' }, EUR: { english: 'Euro', tchinese: '歐元', schinese: '欧元', symbol: '€' }, GBP: { english: 'Great Britain Pound', tchinese: '英鎊', schinese: '英镑', symbol: '£' }, HKD: { english: 'Hong Kong Dollar', tchinese: '港幣', schinese: '港元', symbol: 'HK$' }, JPY: { english: 'Japanese Yen', tchinese: '日圓', schinese: '日元', symbol: 'JP¥' }, KRW: { english: 'South Korean Won', tchinese: '韓圓', schinese: '韩币', symbol: '₩' }, MYR: { english: 'Malaysian Ringgit', tchinese: '令吉', schinese: '林吉特', symbol: 'RM' }, NTD: { english: 'New Taiwan Dollar', tchinese: '台幣', schinese: '台币', symbol: 'NT$' }, NZD: { english: 'New Zealand Dollar', tchinese: '紐幣', schinese: '新西兰元', symbol: 'NZ$' }, RUB: { english: 'Russian Ruble', tchinese: '盧布', schinese: '卢布', symbol: 'руб' }, USD: { english: 'United States Dollar', tchinese: '美元', schinese: '美元', symbol: 'US$' } }, getRate: function getRate() { var self = this; GM_xmlhttpRequest({ method: 'GET', url: 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml', onload: function onload(res) { if (res.status === 200) { try { var exchangeRate = { lastUpdate: Date.now(), rates: {} }; res.response.split("\n").forEach(function (line) { if (line.includes('currency=')) { var currency = line.split('currency=\'').pop().slice(0, 3); var rate = line.trim().split('rate=\'').pop().slice(0, -3); exchangeRate.rates[currency] = parseFloat(rate); } }); // get NTD GM_xmlhttpRequest({ method: 'GET', url: 'https://www.google.com/search?q=1+EUR+%3D+NTD', onload: function onload(searchRes) { var rate = parseFloat(searchRes.response.split('
').pop().slice(0, 7).trim()); var NTDRate = isNaN(rate) ? exchangeRate.rates.HKD * 3.75 : rate; exchangeRate.rates.NTD = NTDRate; exchangeRate.rates.EUR = 1; self.exchangeRate = exchangeRate; GM_setValue('SBSE_xe', JSON.stringify(exchangeRate)); } }); } catch (e) { swal('Parsing Failed', 'An error occured when parsing exchange rate data, please reload to try again', 'error'); } } else { swal('Loading Failed', 'Unable to fetch exchange rate data, please reload to try again', 'error'); } } }); }, update: function update() { var _this = this; var targetCurrency = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'USD'; $('.SBSE_price').each(function (i, ele) { var originalCurrency = ele.dataset.currency; var originalValue = parseInt(ele.dataset.value, 10); var originalRate = _this.exchangeRate.rates[originalCurrency]; var targetRate = _this.exchangeRate.rates[targetCurrency]; var exchangedValue = originalValue / originalRate * targetRate; $(ele).text(_this.currencies[targetCurrency].symbol + (exchangedValue / 100).toFixed(2)); }); }, init: function init() { var updateTimer = 12 * 60 * 60 * 1000; // update every 12 hours if (Object.keys(this.exchangeRate).length === 0 || this.exchangeRate.lastUpdate < Date.now() - updateTimer) this.getRate(); } }; var steam = { library: JSON.parse(localStorage.getItem('SBSE_steam') || '{}'), sync: function sync() { var notify = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var self = this; GM_xmlhttpRequest({ method: 'GET', url: 'https://store.steampowered.com/dynamicstore/userdata/t=' + Math.random(), onload: function onload(res) { var data = JSON.parse(res.response); self.library.owned.app = data.rgOwnedApps; self.library.owned.sub = data.rgOwnedPackages; self.library.wished.app = data.rgWishlist; self.library.wished.sub = []; self.library.ignored.app = data.rgIgnoredApps; self.library.ignored.sub = data.rgIgnoredPackages; self.library.lastSync = Date.now(); self.set(); if (notify === true) { swal({ title: i18n.get('syncSuccessTitle'), text: i18n.get('syncSuccess'), type: 'success', timer: 3000 }); } }, onerror: function onerror() { swal({ title: i18n.get('syncFailTitle'), text: i18n.get('syncFail'), type: 'error', confirmButtonText: i18n.get('visitSteam'), showCancelButton: true }).then(function (result) { if (result.value === true) window.open('https://store.steampowered.com/'); }); } }); }, set: function set() { localStorage.setItem('SBSE_steam', JSON.stringify(this.library)); }, isOwned: function isOwned(o) { return this.library.owned.app.includes(o.app) || this.library.owned.sub.includes(o.sub); }, isWished: function isWished(o) { return this.library.wished.app.includes(o.app) || this.library.wished.sub.includes(o.sub); }, isIgnored: function isIgnored(o) { return this.library.ignored.app.includes(o.app) || this.library.ignored.sub.includes(o.sub); }, lastSync: function lastSync() { return this.library.lastSync; }, init: function init() { if (Object.keys(this.library).length === 0) { this.library.owned = { app: {}, sub: {} }; this.library.wished = { app: {}, sub: {} }; this.library.ignored = { app: {}, sub: {} }; this.set(); } // update steam library every 10 min var updateTimer = 10 * 60 * 1000; if (!this.lastSync() || this.lastSync() < Date.now() - updateTimer) this.sync(false); } }; // functions var getSessionID = function getSessionID() { GM_xmlhttpRequest({ method: 'GET', url: 'https://store.steampowered.com/', onload: function onload(res) { if (res.status === 200) { var accountID = res.response.match(/g_AccountID = (\d+)/).pop(); var sessionID = res.response.match(/g_sessionID = "(\w+)"/).pop(); if (accountID > 0) config.set('sessionID', sessionID);else { swal({ title: i18n.get('notLoggedInTitle'), text: i18n.get('notLoggedInMsg'), type: 'error', showCancelButton: true }).then(function (result) { if (result.value === true) window.open('https://store.steampowered.com/'); }); } } } }); }; var steamCNTooltip = { timeoutID: 0, load: function load(data) { var _this2 = this; if (config.get('enableTooltips')) { var $container = $('
'); (Array.isArray(data) ? data : [data]).forEach(function (d) { ['app', 'sub'].forEach(function (type) { if (has.call(d, type)) { var url = 'https://steamdb.steamcn.com/tooltip?v=4#' + type + '/' + d[type] + '#steam_info_' + type + '_' + d[type] + '_1'; $container.append($('').mouseenter(function () { clearTimeout(_this2.timeoutID); }).mouseout(_this2.hide)); } }); }); $('body').append($container); } }, show: function show(e) { var _this3 = this; var $target = $(e.currentTarget); var json = $target.closest('.SBSE_processed').attr('data-gameinfo'); if (json.length > 0 && config.get('enableTooltips')) { var data = JSON.parse(json); var opened = !!$('.SBSE_tooltip:not(.SBSE_hide)').length; ['app', 'sub'].forEach(function (type) { var $tooltip = $('#tooltip_' + (type + data[type])); if ($tooltip.length > 0 && !opened) { // load tooltip if (!$tooltip.attr('src')) $tooltip.attr('src', $tooltip.attr('data-url')); $tooltip.css({ top: e.clientY, left: e.clientX + 10 }).removeClass('SBSE_hide'); _this3.reposition($tooltip, $tooltip.height()); $tooltip[0].contentWindow.postMessage('show', '*'); // get height $target.one('mouseout', function () { _this3.timeoutID = setTimeout(_this3.hide.bind(steamCNTooltip), 500); }); } }); } }, hide: function hide() { var $tooltip = $('.SBSE_tooltip:not(.SBSE_hide)'); $tooltip.addClass('SBSE_hide'); $tooltip[0].contentWindow.postMessage('hide', '*'); }, reposition: function reposition($tooltip, height) { var $window = $(window); var $document = $(document); var offsetTop = $tooltip.offset().top - $document.scrollTop(); var offsetLeft = $tooltip.offset().left - $document.scrollLeft(); var overflowX = offsetLeft + $tooltip.width() - ($window.width() - 20); var overflowY = offsetTop + height - ($window.height() - 20); if (overflowY > 0) $tooltip.css('top', offsetTop - overflowY); if (overflowX > 0) $tooltip.css('left', offsetLeft - overflowX); }, listen: function listen() { var _this4 = this; window.addEventListener('message', function (e) { if (e.origin === 'https://steamdb.steamcn.com' && e.data.height && e.data.src) { var $tooltip = $('.SBSE_tooltip[src="' + e.data.src + '"]'); $tooltip.height(e.data.height); _this4.reposition($tooltip, e.data.height); } }); } }; var settings = { construct: function construct() { var panelHTML = '\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
' + i18n.get('settingsAutoUpdateSessionID') + '\n \n
' + i18n.get('settingsSessionID') + '\n \n
' + i18n.get('settingsSyncLibrary') + '\n \n
' + i18n.get('settingsLanguage') + '\n \n
' + i18n.get('settingsPreselectIncludeTitle') + '\n \n
' + i18n.get('settingsTitleComesLast') + '\n \n
' + i18n.get('settingsPreselectJoinKeys') + '\n \n
' + i18n.get('settingsJoinKeysASFStyle') + '\n \n
' + i18n.get('settingsActivateAllKeys') + '\n \n
' + i18n.get('settingsEnableTooltips') + '\n \n
\n
\n '; return panelHTML; }, display: function display() { swal({ title: i18n.get('settingsTitle'), html: this.construct() }); // apply settings var $panel = $(swal.getContent()); var $sessionID = $panel.find('.sessionID'); var $language = $panel.find('.language'); // toggles $panel.find('input[type=checkbox]').each(function (index, input) { var $input = $(input); $input.prop('checked', config.get(input.className)); $input.change(function (e) { swal.showLoading(); var setting = e.delegateTarget.className; var state = e.delegateTarget.checked; config.set(setting, state); if (setting === 'autoUpdateSessionID') $sessionID.attr('disabled', state); setTimeout(swal.hideLoading, 500); }); }); // sessionID input $sessionID.prop('disabled', config.get('autoUpdateSessionID')); $sessionID.change(function () { swal.showLoading(); config.set('sessionID', $sessionID.val().trim()); setTimeout(swal.hideLoading, 500); }); // sync library $panel.find('.syncLibrary').click(function () { steam.sync(); }); // language Object.keys(i18n.data).forEach(function (language) { $language.append(new Option(i18n.data[language].name, language)); }); $panel.find('option[value=' + config.get('language') + ']').prop('selected', true); $language.change(function () { swal.showLoading(); var newLanguage = $language.val(); config.set('language', newLanguage); i18n.set(); setTimeout(swal.hideLoading, 500); }); } }; var activator = { activated: JSON.parse(GM_getValue('SBSE_activated', '[]')), isActivated: function isActivated(key) { return this.activated.includes(key); }, pushActivated: function pushActivated(key) { this.activated.push(key); GM_setValue('SBSE_activated', JSON.stringify(this.activated)); }, keyDetails: {}, isOwned: function isOwned(key) { return has.call(this.keyDetails, key) ? this.keyDetails[key].owned : false; }, pushKeyDetails: function pushKeyDetails(data) { if (!has.call(this.keyDetails, data.key)) this.keyDetails[data.key] = data; }, getKeyDetails: function getKeyDetails(key) { return has.call(this.keyDetails, key) ? this.keyDetails[key] : null; }, results: [], resultDetails: function resultDetails(result) { // result from Steam if (result.sbse !== true) { // get status var status = i18n.get('failStatus'); var statusMsg = i18n.get('failDetailUnexpected'); var errorCode = result.purchase_result_details; var errors = { 14: i18n.get('failDetailInvalidKey'), 15: i18n.get('failDetailUsedKey'), 53: i18n.get('failDetailRateLimited'), 13: i18n.get('failDetailCountryRestricted'), 9: i18n.get('failDetailAlreadyOwned'), 24: i18n.get('failDetailMissingBaseGame'), 36: i18n.get('failDetailPS3Required'), 50: i18n.get('failDetailGiftWallet') }; if (result.success === 1) { status = i18n.get('successStatus'); statusMsg = i18n.get('successDetail'); } else if (result.success === 2) { if (has.call(errors, errorCode)) statusMsg = errors[errorCode]; } result.status = status + '/' + statusMsg; // get description var info = result.purchase_receipt_info; var chuncks = []; if (info && info.line_items) { info.line_items.forEach(function (item) { var chunk = []; if (item.packageid > 0) chunk.push('sub: ' + item.packageid); if (item.appid > 0) chunk.push('app: ' + item.appid); chunk.push(item.line_item_description); chuncks.push(chunk.join(' ')); }); } result.descripton = chuncks.join(', '); } var temp = [result.key]; if (result.status) temp.push(result.status); if (result.descripton) temp.push(result.descripton); return temp.join(' | '); }, activate: function activate(keys, callback) { var _this5 = this; this.results.length = 0; var updateResults = function updateResults() { $('.SBSE_container > textarea').val(_this5.results.concat(keys).join(eol)); }; var activateHandler = function activateHandler() { var key = keys.shift(); if (key) { if (_this5.isActivated(key)) { _this5.results.push(_this5.resultDetails({ sbse: true, key: key, status: i18n.get('skippedStatus') + '/' + i18n.get('activatedDetail'), descripton: i18n.get('noItemDetails') })); updateResults(); // next key activateHandler(); } else if (_this5.isOwned(key) && !config.get('activateAllKeys')) { var detail = _this5.getKeyDetails(key); var description = []; ['app', 'sub'].forEach(function (type) { if (has.call(detail, type)) description.push(type + ': ' + detail[type] + ' ' + detail.title); }); _this5.results.push(_this5.resultDetails({ sbse: true, key: key, status: i18n.get('skippedStatus') + '/' + i18n.get('failDetailAlreadyOwned'), descripton: description.join() })); updateResults(); // next key activateHandler(); } else { var self = _this5; GM_xmlhttpRequest({ method: 'POST', url: 'https://store.steampowered.com/account/ajaxregisterkey/', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Origin: 'https://store.steampowered.com', Referer: 'https://store.steampowered.com/account/registerkey' }, data: 'product_key=' + key + '&sessionid=' + config.get('sessionID'), onload: function onload(res) { if (res.status === 200) { var result = JSON.parse(res.response); // update activated var failCode = result.purchase_result_details; if (result.success === 1 || [14, 15, 9].includes(failCode)) { self.pushActivated(key); // dispatch activated event $(document).trigger('activated', [key, result]); } result.key = key; self.results.push(self.resultDetails(result)); updateResults(); // next key setTimeout(activateHandler.bind(self), 2000); } else { var errorMsg = []; errorMsg.push('
');
                                errorMsg.push('sessionID: ' + (config.get('sessionID') + eol));
                                errorMsg.push('autoUpdate: ' + (config.get('autoUpdateSessionID') + eol));
                                errorMsg.push('status: ' + (res.status + eol));
                                errorMsg.push('response: ' + (res.response + eol));
                                errorMsg.push('
'); swal({ title: i18n.get('failTitle'), html: i18n.get('failDetailRequestFailedNeedUpdate') + eol + errorMsg.join(''), type: 'error' }); getSessionID(); if (typeof callback === 'function') callback(); } } }); } } else if (typeof callback === 'function') callback(); }; activateHandler(); } }; var getContainer = function getContainer(handlers) { var $container = $('\n
\n \n
\n \n \n \n \n \n ' + i18n.get('buttonExport') + '\n \n \n \n \n
\n
\n '); if (typeof handlers.reveal !== 'function') handlers.reveal = function () {}; if (typeof handlers.retrieve !== 'function') { handlers.retrieve = function () { var data = handlers.extract(); var keys = []; var includeTitle = !!$('.SBSE_ChkTitle:checked').length; var joinKeys = !!$('.SBSE_ChkJoin:checked').length; var selected = $('.SBSE_SelFilter').val() || 'All'; var skipUsed = !!$('.SBSE_ChkSkipUsed:checked').length; var skipMarketListing = !$('.SBSE_ChkMarketListings:checked').length; var separator = joinKeys ? ',' : eol; var prefix = joinKeys && config.get('joinKeysASFStyle') ? '!redeem ' : ''; for (var i = 0; i < data.items.length; i += 1) { var item = data.items[i]; if (selected === 'Owned' && !item.owned) continue; if (selected === 'NotOwned' && item.owned) continue; if (skipUsed && item.used) continue; if (skipMarketListing && item.marketListing) continue; var temp = [item.key]; if (includeTitle) temp.unshift(item.title); if (config.get('titleComesLast')) temp.reverse(); keys.push(temp.join(', ')); } $('.SBSE_container > textarea').val(prefix + keys.join(separator)); }; } if (typeof handlers.activate !== 'function') { handlers.activate = function (e) { var $textarea = $container.find('textarea'); var keys = unique($textarea.val().match(regKey)); if (keys.length > 0) { var $activateBtn = $(e.currentTarget); $activateBtn.prop('disabled', true).addClass('working'); $textarea.attr('disabled', ''); $textarea.val(keys.join(eol)); activator.activate(keys, function () { $activateBtn.prop('disabled', false).removeClass('working'); $textarea.removeAttr('disabled'); }); } else $textarea.val(i18n.get('emptyInput')); }; } if (typeof handlers.copy !== 'function') { handlers.copy = function () { $('.SBSE_container > textarea').select(); document.execCommand('copy'); }; } if (typeof handlers.reset !== 'function') { handlers.reset = function () { $('.SBSE_container > textarea').val(''); }; } if (typeof handlers.export !== 'function') { handlers.export = function (e) { var data = handlers.extract(); if (data.items.length > 0) { var $exportBtn = $(e.currentTarget); $exportBtn.removeAttr('href').removeAttr('download'); var filename = data.filename.replace(/[\\/:*?"<>|!]/g, ''); var formattedData = data.items.map(function (line) { var temp = []; if (line.title) temp.push(line.title.replace(/,/g, ' ')); temp.push(line.key); return temp.join(); }).join(eol); $exportBtn.attr({ href: 'data:text/csv;charset=utf-8,\uFEFF' + encodeURIComponent(formattedData), download: filename + '.csv' }); } }; } if (typeof handlers.settings !== 'function') { handlers.settings = function () { settings.display(); }; } // bind event $container.find('button').click(function (e) { e.preventDefault(); }); $container.find('.SBSE_BtnReveal').click(handlers.reveal); $container.find('.SBSE_BtnRetrieve').click(handlers.retrieve); $container.find('.SBSE_BtnActivate').click(handlers.activate); $container.find('.SBSE_BtnCopy').click(handlers.copy); $container.find('.SBSE_BtnReset').click(handlers.reset); $container.find('.SBSE_BtnExport').click(handlers.export); $container.find('#SBSE_BtnSettings').click(handlers.settings); // apply settings if (config.get('preselectIncludeTitle')) $container.find('.SBSE_ChkTitle').prop('checked', true); if (config.get('preselectJoinKeys')) $container.find('.SBSE_ChkJoin').prop('checked', true); return $container; }; var siteHandlers = { indiegala: function indiegala() { // inject css GM_addStyle('\n .SBSE_container { margin-top: 10px; }\n .SBSE_container > textarea { border: 1px solid #CC001D; border-radius: 3px; }\n .SBSE_container > div > button, .SBSE_container > div > a { width: 100px; background-color: #CC001D; color: white; border-radius: 3px; }\n .SBSE_container > div > a:hover { color: white; }\n .swal2-popup .slider { margin: 0; }\n .SBSE_icon { vertical-align: middle; }\n '); var handlers = { extract: function extract() { var source = location.pathname === '/profile' ? 'div[id*="_sale_"].collapse.in' : document; var bundleTitle = $('[aria-expanded="true"] > div#bundle-title, #bundle-title, #indie_gala_2 > div > span').eq(0).text().trim(); var data = { title: bundleTitle, filename: 'IndieGala ' + bundleTitle + ' Keys', items: [] }; $(source).find('.game-key-string').each(function (i, ele) { var $ele = $(ele); var key = $ele.find('.keys').val(); if (key) { var d = JSON.parse($(ele).closest('.SBSE_processed').attr('data-gameinfo') || '{}'); if (Object.keys(d).length === 0) { var $a = $ele.find('.title_game > a'); var matched = $a.attr('href').match(/steam.+\/(app|sub)\/(\d+)/); d.title = $a.text().trim(); if (matched) d[matched[1]] = parseInt(matched[2], 10); } d.key = key; activator.pushKeyDetails(d); data.items.push(d); } }); return data; }, reveal: function reveal(e) { var source = location.pathname === '/profile' ? 'div[id*="_sale_"].collapse.in' : document; var $revealBtn = $(e.currentTarget); var selected = $('.SBSE_SelFilter').val() || 'All'; var handler = function handler($games, callback) { var game = $games.shift(); if (game) { var $game = $(game); var code = $game.attr('id').split('_').pop(); var id = $game.attr('onclick').match(/steampowered\.com\/(app|sub)\/(\d+)/)[2]; var d = JSON.parse($game.closest('.SBSE_processed').attr('data-gameinfo') || '{}'); if (selected === 'All' || selected === 'Owned' && d.owned || selected === 'NotOwned' && !d.owned) { $.ajax({ method: 'GET', url: '/myserials/syncget', dataType: 'json', data: { code: code, cache: false, productId: id }, beforeSend: function beforeSend() { $('#permbutton_' + code + ', #fetchlink_' + code + ', #info_key_' + code).hide(); $('#fetching_' + code).fadeIn(); $('#ajax_loader_' + code).show(); $('#container_activate_' + code).html(''); }, success: function success(data) { $('#ajax_loader_' + code + ', #fetching_' + code + ', #info_key_' + code).hide(); $('#serial_' + code).fadeIn(); $('#serial_n_' + code).val(data.serial_number); $game.parent().prev().find('.btn-convert-to-trade').remove(); handler($games, callback); }, error: function error() { swal(i18n.get('failTitle'), i18n.get('failDetailUnexpected'), 'error'); } }); } else handler($games, callback); } else callback(); }; $revealBtn.addClass('working'); handler($(source).find('a[id^=fetchlink_]'), function () { $revealBtn.removeClass('working'); $('.SBSE_BtnRetrieve').click(); }); } }; var process = function process() { var tooltipsData = []; $('.game-key-string').each(function (i, ele) { var $ele = $(ele); var $a = $ele.find('.title_game > a'); var d = { title: $a.text().trim() }; var matched = $a.attr('href').match(/steam.+\/(app|sub)\/(\d+)/); if (matched) d[matched[1]] = parseInt(matched[2], 10); // check if owned & wished d.owned = steam.isOwned(d); d.wished = steam.isWished(d); if (d.owned) $ele.addClass('SBSE_owned'); if (d.wished) $ele.addClass('SBSE_wished'); // append icon $a.after($('').mouseenter(steamCNTooltip.show.bind(steamCNTooltip))); tooltipsData.push(d); $ele.attr('data-gameinfo', JSON.stringify(d)).addClass('SBSE_processed isSteam'); }); // load SteamCN tooltip steamCNTooltip.load(tooltipsData); }; var $container = getContainer(handlers); process(); // insert container $('#library-contain').eq(0).before($container); // support for new password protected gift page var $node = $('#gift-contents'); if ($node.length > 0) { var observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { Array.from(mutation.addedNodes).forEach(function (addedNode) { if (addedNode.id === 'library-contain') { process(); $node.prepend($container); observer.disconnect(); } }); }); }); observer.observe($node[0], { childList: true }); } }, fanatical: function fanatical() { var _this6 = this; // inject css GM_addStyle('\n .SBSE_container { margin-top: 10px; }\n .SBSE_container > textarea { background-color: #434343; color: #eee; }\n .SBSE_container > div > button, .SBSE_container > div > a { width: 80px; }\n .SBSE_container > div > button, .SBSE_container select, .SBSE_container > div > a { border: 1px solid transparent; background-color: #1c1c1c; color: #eee; }\n .SBSE_container > div > button:hover, .SBSE_container select:hover, .SBSE_container > div > a:hover { color: #A8A8A8; }\n .SBSE_container > div > a { text-decoration: none; }\n .SBSE_container label { color: #DEDEDE; }\n .SBSE_container span { margin-right: 0; margin-left: 10px; float: right; }\n .SBSE_container span { margin-top: 5px; }\n\n /* product page */\n .cardBlock { width: 100%; padding: 0 .875rem 0 .875rem; }\n .cardBlock > div { padding: 1rem; }\n .cardBlock .currencyToggler {\n width: 100%; height: 40px;\n margin-bottom: 10px;\n font-size: 20px;\n border-radius: 3px;\n }\n .starDeal { padding: 1rem; }\n .starDeal > div { display: flex; align-items: center; justify-content: space-evenly; }\n .starDeal .currencyToggler {\n width: 300px; height: 40px;\n font-size: 20px;\n border-radius: 3px;\n }\n .pricingDetail { background-color: transparent; }\n .pricingDetail th { padding-top: 10px; }\n .pricingDetail .cheapest { border-bottom: 1px solid #ff9800; font-weight: bold; }\n .pricingDetail .currency-flag { vertical-align: text-bottom; }\n .swal2-popup table { background-color: white; }\n .SBSE_icon { margin-top: -16px; align-self: flex-end; }\n '); var APIData = null; var fetchAPIData = function () { var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(s, c) { var slug, callback, JSONString, res; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: slug = s; callback = c; if (typeof s === 'function') { callback = s; slug = location.href.split('/').pop(); } JSONString = GM_getValue('Fanatical-' + slug, ''); if (!(JSONString.length === 0)) { _context.next = 16; break; } _context.next = 7; return fetch('https://www.fanatical.com/api/products/' + slug); case 7: res = _context.sent; if (!res.ok) { _context.next = 15; break; } _context.next = 11; return res.text(); case 11: JSONString = _context.sent; GM_setValue('Fanatical-' + slug, JSONString); _context.next = 16; break; case 15: JSONString = '{}'; case 16: APIData = JSON.parse(JSONString); if (typeof callback === 'function') callback(); case 18: case 'end': return _context.stop(); } } }, _callee, _this6); })); return function fetchAPIData(_x3, _x4) { return _ref.apply(this, arguments); }; }(); var productHandler = function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() { var language, $priceExt, $currencyToggler, $pricingDetail, selectedCurrency, isStarDeal, starDeal, res, discount, i, $prices; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!(Object.keys(APIData).length > 0)) { _context2.next = 33; break; } language = config.get('language'); $priceExt = $('\n
\n
\n \n
\n
\n
\n '); $currencyToggler = $priceExt.find('.currencyToggler'); $pricingDetail = $priceExt.find('.pricingDetail'); selectedCurrency = GM_getValue('SBSE_selectedCurrency', 'CNY'); isStarDeal = !!$('.stardeal-purchase-info').length; starDeal = {}; if (!isStarDeal) { _context2.next = 17; break; } $priceExt.toggleClass('cardBlock starDeal'); // fetch star-deal data _context2.next = 12; return fetch('https://www.fanatical.com/api/star-deal'); case 12: res = _context2.sent; if (!res.ok) { _context2.next = 17; break; } _context2.next = 16; return res.json(); case 16: starDeal = _context2.sent; case 17: Object.keys(xe.currencies).forEach(function (currency) { var selected = currency === selectedCurrency ? ' selected' : ''; $currencyToggler.append($('')); }); $currencyToggler.change(function () { xe.update($currencyToggler.val()); GM_setValue('SBSE_selectedCurrency', $currencyToggler.val()); }); // bundle page APIData.bundles.forEach(function (tier, index) { if (APIData.bundles.length > 1) $pricingDetail.append('Tier ' + (index + 1) + ''); Object.keys(tier.price).forEach(function (currency) { var value = tier.price[currency]; $pricingDetail.append('\n \n
\n ' + (xe.currencies[currency].symbol + value / 100) + '\n \u2248 \n \n '); }); }); // game page if (location.href.includes('/game/') || location.href.includes('/dlc/')) { discount = 1; if (has.call(APIData, 'current_discount') && new Date(APIData.current_discount.until).getTime() > Date.now()) discount = 1 - APIData.current_discount.percent; if (isStarDeal) discount = 1 - $('.discount-percent').text().replace(/\D/g, '') / 100; Object.keys(APIData.price).forEach(function (currency) { var value = (APIData.price[currency] * discount).toFixed(2); // if star-deal data loaded successfully if (has.call(starDeal, 'promoPrice')) value = starDeal.promoPrice[currency]; $pricingDetail.append('\n \n
\n ' + (xe.currencies[currency].symbol + (value / 100).toFixed(2)) + '\n \u2248 \n \n '); }); } $('.product-commerce-container').append($priceExt); $('.stardeal-purchase-info').after($priceExt); xe.update(selectedCurrency); // highlight the cheapest i = 1; case 25: if (!(i < 10)) { _context2.next = 33; break; } $prices = $('.tier' + i + ' .SBSE_price'); if (!($prices.length === 0)) { _context2.next = 29; break; } return _context2.abrupt('break', 33); case 29: $($prices.toArray().sort(function (a, b) { return a.textContent.replace(/\D/g, '') - b.textContent.replace(/\D/g, ''); }).shift()).closest('tr').addClass('cheapest'); case 30: i += 1; _context2.next = 25; break; case 33: case 'end': return _context2.stop(); } } }, _callee2, _this6); })); return function productHandler() { return _ref2.apply(this, arguments); }; }(); var handlers = { extract: function extract() { var bundleTitle = $('h5').eq(0).text().trim(); var data = { title: bundleTitle, filename: 'Fanatical ' + bundleTitle + ' Keys', items: [] }; $('.account-content dl:has(input)').each(function (i, dl) { var $dl = $(dl); var key = $dl.find('input').val(); if (key) { var d = JSON.parse($dl.closest('.SBSE_processed').attr('data-gameinfo') || '{}'); if (Object.keys(d).length === 0) { d.title = $dl.find('dd').eq(1).text().trim(); } d.key = key; activator.pushKeyDetails(d); data.items.push(d); } }); return data; }, reveal: function reveal(e) { var $revealBtn = $(e.currentTarget); var selected = $('.SBSE_SelFilter').val() || 'All'; var handler = function handler($games, callback) { var game = $games.shift(); if (game) { var d = JSON.parse($(game).closest('.SBSE_processed').attr('data-gameinfo') || '{}'); if (selected === 'All' || selected === 'Owned' && d.owned || selected === 'NotOwned' && !d.owned) { game.click(); setTimeout(handler.bind(null, $games, callback), 300); } else setTimeout(handler.bind(null, $games, callback), 1); } else setTimeout(callback, 500); }; $revealBtn.addClass('working'); handler($('.account-content dl button'), function () { $revealBtn.removeClass('working'); $('.SBSE_BtnRetrieve').click(); }); } }; var process = function process($node) { var title = $node.find('h5').eq(0).text(); var slug = title.trim().toLowerCase().replace(/ /g, '-').replace(/[^a-z0-9-]/g, ''); // empty textarea $('.SBSE_container textarea').val(''); if (slug.length > 0) { fetchAPIData(slug, function () { if (Object.keys(APIData).length > 0) { var tooltipsData = []; var matchGame = function matchGame(data) { if (has.call(data, 'steam') && data.steam.id) { var $gameTitle = $node.find('dd > div:contains(' + data.name + ')').filter(function (index, name) { return data.name === name.textContent.trim(); }); var $dl = $gameTitle.closest('dl'); var d = { title: data.name, app: parseInt(data.steam.id, 10) }; d.owned = steam.isOwned(d); d.wished = steam.isWished(d); // check if owned & wished if (d.owned) $dl.addClass('SBSE_owned'); if (d.wished) $dl.addClass('SBSE_wished'); // wrap link $gameTitle.contents().filter(function (i, n) { return n.nodeType === 3; }).wrap(''); // insert filler if ($gameTitle.find('.drm-container-steam').length === 0) { $gameTitle.append('
'); } // append icon $gameTitle.append($('').mouseenter(steamCNTooltip.show.bind(steamCNTooltip))); tooltipsData.push(d); $dl.addClass('SBSE_processed isSteam').attr('data-gameinfo', JSON.stringify(d)); } }; matchGame(APIData); APIData.bundles.forEach(function (tier) { tier.games.forEach(matchGame); }); // load SteamCN tooltip steamCNTooltip.load(tooltipsData); } }); } }; var $container = getContainer(handlers); $container.find('button').addClass('narrow'); // narrow buttons $container.find('a').attr('href', ''); // dodge from master css selector new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { Array.from(mutation.addedNodes).filter(function (x) { return x.nodeType === 1; }).forEach(function (node) { var $node = $(node); // url changed if (node.matches('[property="og:url"]')) { var currentURL = location.href; if (currentURL.includes('/orders/')) { // insert container var $anchor = $('h3:contains(Order Keys)'); if ($('.SBSE_container').length === 0 && $anchor.length > 0) $anchor.eq(0).before($container); } if (currentURL.includes('/bundle/') || currentURL.includes('/game/') || currentURL.includes('/dlc/')) fetchAPIData(productHandler); } // order contents loaded if ($node.find('dl').length > 0) process($node); }); }); }).observe($('html')[0], { childList: true, subtree: true }); }, humblebundle: function humblebundle() { var _this7 = this; // inject css GM_addStyle('\n .SBSE_container > div { position: relative; }\n .SBSE_container > textarea {\n border: 1px solid #CFCFCF;\n border-radius: 5px;\n color: #4a4c45;\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n }\n .SBSE_container > div > button, .SBSE_container > div > a {\n width: 70px;\n border: 1px solid #C9CCD3;\n border-radius: 3px;\n background-color: #C5C5C5;\n background: linear-gradient(to top, #cacaca, #e7e7e7);\n color: #4a4c45 !important;\n }\n .SBSE_container > div > button:hover, .SBSE_container > div > a:hover {\n border: 1px solid #b7bac0;\n background-color: #fafcff;\n color: #555961 !important;\n }\n .SBSE_container > div > button.narrow.working { width: 76px; padding-right: 36px; }\n #SBSE_BtnSettings { position: absolute; right: 0; }\n .SBSE_owned .sr-unredeemed-steam-button {\n background-color: #F3F3F3;\n background: linear-gradient(to top, #E8E8E8, #F6F6F6);\n }/*\n .SBSE_owned .heading-text h4 > span:not(.steam-owned):last-child::after {\n content: \'\\f085\';\n font-family: hb-icons;\n color: #17A1E5;\n }*/\n .SBSE_activationRestrictions { float: right; margin-right: 5px; cursor: pointer; }\n .swal2-icon-text { font-size: inherit; }\n .flag-icon { width: 4em; height: 3em; border-radius: 3px; }\n .flag-icon-unknown { border: 1px solid; text-align: center; line-height: 3em; }\n '); var atDownload = location.pathname === '/downloads'; var fetchKey = function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3($node, machineName, callback) { var res, d; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: _context3.next = 2; return fetch('https://www.humblebundle.com/humbler/redeemkey', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Origin: 'https://www.humblebundle.com', Referer: location.href }, body: 'keytype=' + machineName + '&key=' + unsafeWindow.gamekeys[0] + '&keyindex=0', credentials: 'same-origin' }); case 2: res = _context3.sent; if (!res.ok) { _context3.next = 10; break; } _context3.next = 6; return res.json(); case 6: d = _context3.sent; if (d.success) { $node.closest('.container').html('\n
\n
' + d.key + '
\n \n
Redeem
\n Redeem on Steam\n
\n
\n
\n '); } else swal(i18n.get('failTitle'), JSON.stringify(d), 'error'); _context3.next = 11; break; case 10: $node.click(); case 11: if (typeof callback === 'function') callback(); case 12: case 'end': return _context3.stop(); } } }, _callee3, _this7); })); return function fetchKey(_x5, _x6, _x7) { return _ref3.apply(this, arguments); }; }(); var handlers = { extract: function extract() { var bundleTitle = $('title').text().split(' (').shift(); var data = { title: bundleTitle, filename: 'Humble Bundle ' + bundleTitle + ' Keys', items: [] }; $('.keyfield.redeemed .keyfield-value').each(function (i, ele) { var $ele = $(ele); var key = $ele.text().trim(); if (key) { var d = JSON.parse($ele.closest('.SBSE_processed').attr('data-gameinfo') || '{}'); if (Object.keys(d).length === 0) { var $titleEle = $ele.closest(atDownload ? '.container' : '.redeemer-cell').prev().find('h4'); d.title = $titleEle.contents().eq(0).text().trim(); } d.key = key; activator.pushKeyDetails(d); data.items.push(d); } }); return data; }, reveal: function reveal(e) { var $revealBtn = $(e.currentTarget); var selected = $('.SBSE_SelFilter').val() || 'All'; var handler = function handler($games, callback) { var game = $games.shift(); if (game) { var $game = $(game); var machineName = $game.closest('.key-redeemer').attr('data-machineName'); var d = JSON.parse($(game).closest('.SBSE_processed').attr('data-gameinfo') || '{}'); if (atDownload && machineName) { if (selected === 'All' || selected === 'Owned' && d.owned || selected === 'NotOwned' && !d.owned) { fetchKey($game, machineName, function () { handler($games, callback); }); } else setTimeout(handler.bind(null, $games, callback), 1); } else { game.click(); $('.sr-warning-modal-confirm-button').click(); setTimeout(handler.bind(null, $games, callback), 200); } } else callback(); }; $revealBtn.addClass('working'); handler($('.key-redeemer.isSteam .keyfield:not(.redeemed)'), function () { $revealBtn.removeClass('working'); $('.SBSE_BtnRetrieve').click(); }); } }; var process = function () { var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4($node) { var gameKey, json, res, data, tooltipsData; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: gameKey = unsafeWindow.gamekeys[0] || location.href.split('key=').pop().split('&').shift(); json = GM_getValue(gameKey, ''); if (!(json.length === 0)) { _context4.next = 10; break; } _context4.next = 5; return fetch('https://www.humblebundle.com/api/v1/order/' + gameKey + '?all_tpkds=true', { method: 'GET', credentials: 'same-origin' }); case 5: res = _context4.sent; if (!res.ok) { _context4.next = 10; break; } _context4.next = 9; return res.text(); case 9: json = _context4.sent; case 10: _context4.prev = 10; data = JSON.parse(json); tooltipsData = []; data.tpkd_dict.all_tpks.forEach(function (game) { var $keyRedeemer = $node.find('.key-redeemer:has(.heading-text[data-title="' + game.human_name + '"])'); if ($keyRedeemer.length > 0) { if (game.key_type === 'steam') { $keyRedeemer.addClass('isSteam'); var d = { title: game.human_name, app: parseInt(game.steam_app_id, 10) }; d.owned = steam.isOwned(d); d.wished = steam.isWished(d); // apply owned effect on game title if (d.owned) $keyRedeemer.addClass('SBSE_owned'); if (d.wished) $keyRedeemer.addClass('SBSE_wished'); // store data $keyRedeemer.attr({ 'data-machineName': game.machine_name, 'data-humanName': game.human_name, 'data-gameinfo': JSON.stringify(d) }); tooltipsData.push(d); } // activation restrictions var html = ''; var disallowed = game.disallowed_countries.map(function (c) { return ISO2.get(c); }); var exclusive = game.exclusive_countries.map(function (c) { return ISO2.get(c); }); var separator = config.get('language').includes('chinese') ? '、' : ', '; if (disallowed.length > 0) html += '

' + i18n.get('HBDisallowedCountries') + '
' + disallowed.join(separator) + '

'; if (exclusive.length > 0) html += '

' + i18n.get('HBExclusiveCountries') + '
' + exclusive.join(separator) + '

'; if (disallowed.length > 0 || exclusive.length > 0) { $('' + i18n.get('HBActivationRestrictions') + '').click(function () { swal({ title: game.human_name + '
' + i18n.get('HBActivationRestrictions'), html: html, type: 'info' }); }).insertBefore($keyRedeemer.find('.heading-text > h4')); } $keyRedeemer.addClass('SBSE_processed'); } }); // override default popups document.addEventListener('click', function (e) { var $target = $(e.target).closest('.keyfield:not(.redeemed)'); var $keyRedeemer = $target.closest('.key-redeemer.isSteam'); var machineName = $keyRedeemer.attr('data-machineName'); if ($target.length > 0 && $keyRedeemer.length > 0 && machineName) { e.stopPropagation(); if ($keyRedeemer.hasClass('SBSE_owned')) { swal({ title: i18n.get('HBAlreadyOwned'), text: i18n.get('HBRedeemAlreadyOwned').replace('%title%', $keyRedeemer.attr('data-humanName')), type: 'question', showCancelButton: true }).then(function (result) { if (result.value) fetchKey($target, machineName); }); } else fetchKey($target, machineName); } }, true); // load SteamCN tooltip steamCNTooltip.load(tooltipsData); _context4.next = 21; break; case 18: _context4.prev = 18; _context4.t0 = _context4['catch'](10); throw _context4.t0; case 21: case 'end': return _context4.stop(); } } }, _callee4, _this7, [[10, 18]]); })); return function process(_x8) { return _ref4.apply(this, arguments); }; }(); var $container = getContainer(handlers); var $keyManager = $('.js-key-manager-holder'); // narrow buttons $container.find('div > button').addClass('narrow'); // at home page if ($keyManager.length > 0) { var observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { Array.from(mutation.addedNodes).forEach(function (addedNode) { if (addedNode.className === 'header') { observer.disconnect(); $(addedNode).after($container); } }); }); }); observer.observe($keyManager[0], { childList: true }); // at download page } else { var _observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { Array.from(mutation.addedNodes).forEach(function () { var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5(addedNode) { var $node; return regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: $node = $(addedNode); if ($node.hasClass('key-list') || $node.find('.key-list').length > 0) { _observer.disconnect(); $node.closest('.whitebox-redux').before($container); // fetch game heading & wrap heading $node.find('.heading-text > h4').each(function (i, heading) { heading.parentElement.dataset.title = heading.innerText.trim(); $(heading.firstChild).wrap(''); $(heading).append($('').mouseenter(steamCNTooltip.show.bind(steamCNTooltip))); }); // fetch & process key data process($node); } case 2: case 'end': return _context5.stop(); } } }, _callee5, _this7); })); return function (_x9) { return _ref5.apply(this, arguments); }; }()); }); }); _observer.observe(document.body, { childList: true, subtree: true }); } // append user's region var countryCode = unsafeWindow.models.request.country_code; if (countryCode) { var code = countryCode.toLowerCase(); var countryName = ISO2.get(countryCode); var $flag = $(''); if (GM_getResourceText('flagIcon').includes(code + '.svg')) { $flag.toggleClass('flag-icon-unknown flag-icon-' + code).attr('tooltip', i18n.get('HBCurrentLocation') + countryName); } else $flag.text('?'); $('.navbar-content').prepend($flag); } }, dailyindiegame: function dailyindiegame() { var _this8 = this; var MPHideList = JSON.parse(GM_getValue('SBSE_DIGMPHideList') || '[]'); var pathname = location.pathname; if (pathname.includes('/account_page') || pathname.includes('/account_update')) { // force sync library steam.sync(false); // inject css GM_addStyle('\n .SBSE_container { padding: 5px; border: 1px solid #424242; }\n .SBSE_container > textarea { border: 1px solid #000; }\n .SBSE_container > div > button {\n border: none;\n background-color: #FD5E0F;\n color: rgb(49, 49, 49);\n font-family: Ropa Sans;\n font-size: 15px;\n font-weight: 600;\n }\n '); var handlers = { extract: function extract() { var data = { title: 'DailyIndieGame Keys', filename: 'DailyIndieGame Keys', items: [] }; $('#TableKeys tr').each(function (i, tr) { var $tds = $(tr).children(); var key = $tds.eq(4).text().trim(); if (key.includes('-')) { var d = { title: $tds.eq(2).text().trim(), key: key, marketListing: $tds.eq(6).text().includes('Cancel trade') }; activator.pushKeyDetails(d); data.items.push(d); } }); return data; }, reveal: function reveal() { var $form = $('#form3'); $('.quickaction').val(1); $.ajax({ method: 'POST', url: $form.attr('action'), data: $form.serializeArray(), success: function success() { location.reload(); } }); } }; var $container = getContainer(handlers); $container.find('.SBSE_SelFilter').hide(); // hide filter selector $container.find('.SBSE_BtnExport').remove(); // remove export button $container.find('#SBSE_BtnSettings').before('\n \n '); // append checkbox for market keys $('#TableKeys').eq(0).before($container); // rate all positive var $awaitRatings = $('a[href^="account_page_0_ratepositive"]'); if ($awaitRatings.length > 0) { $('#TableKeys td:contains(Rate TRADE)').text(i18n.get('DIGRateAllPositive')).css('cursor', 'pointer').click(function () { $awaitRatings.each(function () { var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6(i, a) { var res; return regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: _context6.next = 2; return fetch(a.href, { method: 'GET', credentials: 'same-origin' }); case 2: res = _context6.sent; if (res.ok) $(a).parent('td').html('Positive'); case 4: case 'end': return _context6.stop(); } } }, _callee6, _this8); })); return function (_x10, _x11) { return _ref6.apply(this, arguments); }; }()); }); } // DIG EasyBuy } else if (pathname.includes('/account_digstore') || pathname.includes('/account_trades') || pathname.includes('/account_tradesXT') || pathname.includes('/store_update') || pathname.includes('/storeXT_update')) { // inject css styles GM_addStyle('\n .DIGEasyBuy_row { height: 30px; }\n .DIGEasyBuy button { padding: 4px 8px; outline: none; cursor: pointer; }\n .DIGEasyBuy_checked { background-color: #222; }\n .DIGEasyBuy_hideOwned tr.SBSE_hide { display: none; }\n .DIGEasyBuy_hideOwned tr.SBSE_hide + .SBSE_searchResults { display: none; }\n .SBSE_searchResults td { padding: 0 }\n .SBSE_searchResults iframe {\n width: 100%; height: 300px;\n display: none;\n background-color: white;\n border: none;\n }\n .SBSE_owned a[href*="steam"] .DIG3_14_Gray { color: #9ccc65; }\n .SBSE_wished a[href*="steam"] .DIG3_14_Gray { color: #29b6f6; }\n .SBSE_ignored a[href*="steam"] .DIG3_14_Gray { text-decoration: line-through;}\n #form3 #sortby { width: 250px; }\n '); // setup row data & event var easyBuySetup = function easyBuySetup(i, ele) { var $game = $(ele); var $row = $game.closest('tr'); $row.attr('data-id', $game.attr('href').replace(/\D/g, '')); $row.attr('data-price', parseInt($row.find('td:contains(DIG Points)').text(), 10) || 0); $row.click(function () { $row.toggleClass('DIGEasyBuy_checked'); }); $row.addClass('DIGEasyBuy_row'); }; $('a[href^="account_buy"]').each(easyBuySetup); // check if owned / manually hid var check = function check(i, a) { var $a = $(a); var $tr = $a.closest('tr'); var data = a.pathname.slice(1).split('/'); var steamID = parseInt(data[1], 10); var id = parseInt($tr.attr('data-id'), 10); var d = _defineProperty({}, data[0], steamID); if (steam.isOwned(d)) $tr.addClass('SBSE_owned SBSE_hide'); if (steam.isWished(d)) $tr.addClass('SBSE_wished'); if (steam.isIgnored(d)) $tr.addClass('SBSE_ignored'); if (MPHideList.includes(id)) $tr.addClass('SBSE_hide'); // append manual hide feature $tr.children().eq(0).attr('title', i18n.get('DIGClickToHideThisRow')).click(function (e) { e.stopPropagation(); if (id > 0) { MPHideList.push(id); GM_setValue('SBSE_DIGMPHideList', JSON.stringify(MPHideList)); $tr.addClass('SBSE_hide'); } }); // no appID found, pre-load Google search result if (steamID === -1 && !MPHideList.includes(id)) { var $game = $a.find('span'); var gameTitle = encodeURIComponent($game.text().trim()).replace(/%20/g, '+'); var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; GM_xmlhttpRequest({ method: 'GET', url: 'https://www.google.com/search?q=steam+' + gameTitle, onload: function onload(res) { var html = res.responseText; // inset style var index = html.indexOf(''); var style = '\n \n '; html = html.slice(0, index) + style + html.slice(index); // stripe script tags html = html.replace(/[\s\S]*?<\/script>/gi, ''); // manipulate urls html = html.replace(/\/images\//g, 'https://www.google.com/images/').replace(/\/url\?/g, 'https://www.google.com/url?'); $tr.after('\n \n