// ==UserScript== // @name JTMate - Cash Back And Coupons // @name:ar JTMate - استرداد نقدي وكوبونات // @name:bg JTMate - Кешбек и купони // @name:ckb JTMate - گەڕاندنەوەی پارە و کوپۆن // @name:cs JTMate - Cashback a kupóny // @name:da JTMate - Cashback og kuponer // @name:de JTMate - Cashback und Gutscheine // @name:el JTMate - Επιστροφή χρημάτων και κουπόνια // @name:en JTMate - Cash Back And Coupons // @name:eo JTMate - Repagoj kaj kuponoj // @name:es JTMate - Reembolso y cupones // @name:es-419 JTMate - Cashback y cupones // @name:fi JTMate - Cashback ja kupongit // @name:fr JTMate - Cashback et coupons // @name:fr-CA JTMate - Remises en argent et coupons // @name:he JTMate - קאשבק וקופונים // @name:hr JTMate - Povrat novca i kuponi // @name:hu JTMate - Pénzvisszatérítés és kuponok // @name:id JTMate - Cashback dan kupon // @name:it JTMate - Cashback e coupon // @name:ja JTMate - キャッシュバックとクーポン // @name:ka JTMate - ქეშბექი და კუპონები // @name:ko JTMate - 캐시백 및 쿠폰 // @name:nb JTMate - Cashback og kuponger // @name:nl JTMate - Cashback en kortingsbonnen // @name:pl JTMate - Cashback i kupony // @name:pt-BR JTMate - Cashback e cupons // @name:ro JTMate - Cashback și cupoane // @name:ru JTMate - Кэшбэк и купоны // @name:sk JTMate - Cashback a kupóny // @name:sr JTMate - Повраћај новца и купони // @name:sv JTMate - Cashback och kuponger // @name:th JTMate - เงินคืนและคูปอง // @name:tr JTMate - Nakit iadesi ve kuponlar // @name:uk JTMate - Кешбек і купони // @name:ug JTMate - نەق پۇل قايتۇرۇش ۋە كۇپونلار // @name:vi JTMate - Hoàn tiền và mã giảm giá // @name:zh-CN JTMate - 购物助手 // @name:zh-TW JTMate - 購物助手 // @description Automatically finds and applies the best coupon code and cashback. // @description:ar يبحث تلقائيًا عن أفضل رمز قسيمة ويطبق أفضل استرداد نقدي عند إتمام الشراء. // @description:bg Автоматично намира и прилага най-добрия код за купон и най-добрия кешбек при плащане. // @description:ckb بە شێوەی خۆکار باشترین کۆدی کوپۆن و باشترین گەڕاندنەوەی پارە دەدۆزێتەوە و لە کاتی پارەداندا بەکاری دەهێنێت. // @description:cs Při placení automaticky najde a použije nejlepší kód kupónu i cashback. // @description:da Finder automatisk og anvender den bedste kuponkode og cashback ved checkout. // @description:de Findet automatisch den besten Gutscheincode und das beste Cashback und wendet beides beim Checkout an. // @description:el Βρίσκει αυτόματα και εφαρμόζει τον καλύτερο κωδικό κουπονιού και το καλύτερο cashback στο checkout. // @description:en Automatically finds and applies the best coupon code and cashback. // @description:eo Aŭtomate trovas kaj aplikas la plej bonan kuponkodon kaj cashback ĉe pagado. // @description:es Encuentra y aplica automáticamente el mejor código de cupón y el mejor cashback al finalizar la compra. // @description:es-419 Encuentra y aplica automáticamente el mejor código de cupón y el mejor cashback al finalizar la compra. // @description:fi Löytää ja käyttää automaattisesti parhaan kuponkoodin ja cashbackin kassalla. // @description:fr Trouve et applique automatiquement le meilleur code promo et le meilleur cashback au moment du paiement. // @description:fr-CA Trouve et applique automatiquement le meilleur code promo et le meilleur cashback au passage à la caisse. // @description:he מאתר ומחיל אוטומטית את קוד הקופון הטוב ביותר ואת הקאשבק הטוב ביותר בשלב התשלום. // @description:hr Automatski pronalazi i primjenjuje najbolji kod kupona i najbolji cashback pri naplati. // @description:hu Automatikusan megkeresi és alkalmazza a legjobb kuponkódot és cashbacket fizetéskor. // @description:id Secara otomatis menemukan dan menerapkan kode kupon terbaik dan cashback terbaik saat checkout. // @description:it Trova e applica automaticamente il miglior codice coupon e il miglior cashback al checkout. // @description:ja チェックアウト時に最適なクーポンコードとキャッシュバックを自動で見つけて適用します。 // @description:ka გადახდისას ავტომატურად პოულობს და იყენებს საუკეთესო კუპონის კოდსა და საუკეთესო ქეშბექს. // @description:ko 결제 시 최적의 쿠폰 코드와 캐시백을 자동으로 찾아 적용합니다. // @description:nb Finner og bruker automatisk den beste kupongkoden og cashback i kassen. // @description:nl Vindt en past automatisch de beste couponcode en cashback toe bij het afrekenen. // @description:pl Automatycznie znajduje i stosuje najlepszy kod kuponu oraz najlepszy cashback przy finalizacji zakupu. // @description:pt-BR Encontra e aplica automaticamente o melhor código de cupom e o melhor cashback no checkout. // @description:ro Găsește și aplică automat cel mai bun cod de cupon și cel mai bun cashback la checkout. // @description:ru Автоматически находит и применяет лучший промокод и лучший кэшбэк при оформлении заказа. // @description:sk Pri platbe automaticky nájde a použije najlepší kód kupónu aj cashback. // @description:sr Аутоматски проналази и примењује најбољи код купона и најбољи cashback при наплати. // @description:sv Hittar och tillämpar automatiskt den bästa kupongkoden och cashback i kassan. // @description:th ค้นหาและใช้รหัสคูปองและแคชแบ็กที่ดีที่สุดโดยอัตโนมัติในขั้นตอนชำระเงิน // @description:tr Ödeme sırasında en iyi kupon kodunu ve en iyi cashback'i otomatik olarak bulur ve uygular. // @description:uk Автоматично знаходить і застосовує найкращий код купона та найкращий кешбек під час оформлення замовлення. // @description:ug چىكىتلاشتا ئەڭ ياخشى كۇپون كودى ۋە ئەڭ ياخشى نەق پۇل قايتۇرۇشنى ئاپتوماتىك تېپىپ قوللىنىدۇ. // @description:vi Tự động tìm và áp dụng mã giảm giá tốt nhất và hoàn tiền tốt nhất khi thanh toán. // @description:zh-CN 自动查找并应用最佳优惠券代码和返现 // @description:zh-TW 自動搜尋並套用最佳優惠券代碼及現金回饋 // @namespace jtmate_shopping_assistant // @version 1.1.2 // @author Jtmate // @icon data:image/png;base64,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 // @match *://*/* // @exclude *://www.lazada.com/* // @exclude *://shopee.com/* // @connect jtm.pub // @connect jtmate.com // @license MIT // @run-at document-idle // @antifeature referral-link // @noframes // @grant GM_registerMenuCommand // @grant GM_openInTab // @grant GM.openInTab // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_setClipboard // ==/UserScript== (function () { 'use strict'; /*! * Copyright (c) 2024 - 2026, Jtmate. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ const ScriptConst = { "lang": (() => { const navLang = navigator.language || navigator.userLanguage || "en"; if (navLang.startsWith("zh")) { return navLang === "zh-CN" || navLang === "zh-TW" ? navLang : "zh-CN"; } return navLang.slice(0, 2).toLowerCase() || "en"; })(), "isDev": false, "isDebug": false, "version": "1.0.1", "number": "13", "currentHost": window.location.host, "currentUrl": window.location.href }; const PlatformConst = { "x": { "p": "x", "match": /twitter|x\.com$/ }, "youtube": { "p": "youtube", "match": /youtube\.com$/ }, "google": { "p": "google", "match": /google\.com$/ }, "tiktok": { "p": "tiktok", "match": /www\.tiktok\.com/ }, "cobalt": { "p": "cobalt", "match": /cobalt\.tools/ } }; const Logger = { log: function(level = "info", ...messages) { } }; const Tools = { decryptStr: function(str) { try { if (!str) { return str; } let result = atob(str); return result.split("").reverse().join(""); } catch (e) { } return null; }, encryptStr: function(str) { try { if (!str) { return str; } let result = str.split("").reverse().join(""); return btoa(result); } catch (e) { } return null; }, getOtherPlatform: function() { let platform = null; const currentHost = window.location.host; for (let key in PlatformConst) { if (PlatformConst[key].match.test(currentHost)) { platform = PlatformConst[key].p; break; } } return platform; }, removeAnchorsByNode: function(node) { const tagName = node.tagName; if (!tagName) return; const exist = ["A", "IMG", "DIV", "SPAN", "LABEL", "TABLE", "TR", "TD", "CANVAS"].some((name) => name === tagName); if (exist) { node.removeAttribute("data-spm-anchor-id"); for (let i = 0; i < node.childNodes.length; i++) { this.removeAnchorsByNode(node.childNodes[i]); } } }, openInTab: function(url, options = { "active": true, "insert": true, "setParent": true }) { if (typeof GM_openInTab === "function") { GM_openInTab(url, options); } else { GM.openInTab(url, options); } }, onPageLoad: function(callback) { if (document.readyState === "complete") { callback(); } else { window.addEventListener("DOMContentLoaded", callback, { once: true }); window.addEventListener("load", callback, { once: true }); } }, request: function(method, url, param, headers = { "Content-Type": "application/json;charset=UTF-8" }, timeout = 20 * 1e3) { if (!url) { return Promise.reject({ "code": "exception", "result": null }); } return new Promise((resolve, reject) => { const config = { method: method.toUpperCase(), url, timeout, onload: function(response) { if (response.status >= 200 && response.status < 300) { resolve({ "code": "success", "result": response.responseText }); } else { reject({ "code": "error", "result": response.statusText }); } }, ontimeout: function(error) { reject({ "code": "error", "result": error }); }, onerror: function(error) { reject({ "code": "error", "result": error }); } }; if (config.method === "POST") { config.headers = headers ?? { "Content-Type": "application/json" }; if (JSON.stringify(config.headers).indexOf("application/json") != -1) { config.data = JSON.stringify(param); } else { config.data = param; } } else if (config.method === "GET") { config.headers = headers ?? { "Content-Type": "application/json" }; config.data = param; } GM_xmlhttpRequest(config); }); }, crossRequest: function(method = "GET", url, param = {}, headers = { "Content-Type": "application/json;charset=UTF-8" }, timeout = 20 * 1e3) { if (!url) { return Promise.reject({ "code": "exception", "result": null }); } const config = { method: method.toUpperCase(), headers }; const controller = new AbortController(); const signal = controller.signal; config.signal = signal; if (config.method === "POST") { config.headers = headers ?? { "Content-Type": "application/json" }; config.body = JSON.stringify(param); } const timeoutId = setTimeout(() => controller.abort(), timeout); return fetch(url, config).then((response) => response.ok ? response.text() : Promise.reject(response.statusText)).then((result) => { clearTimeout(timeoutId); return { "code": "success", "result": result }; }).catch((error) => { clearTimeout(timeoutId); if (error.name === "AbortError") { return { "code": "error", "result": "Request timeout" }; } return { "code": "error", "result": error }; }); }, getGoodsIdByLink: function(url = window.location.href) { if (url.indexOf("?") != -1) { url = url.split("?")[0]; } if (url.indexOf("#") != -1) { url = url.split("#")[0]; } const suffix = "html|htm|id|p"; let regex = new RegExp("\\/([^\\/]*?)\\.(" + suffix + ")"); if (/lazada\./.test(url)) { regex = new RegExp("-i(\\d+)(?:-s(\\d+))?\\.html"); } else if (/ebay\./.test(url)) { regex = new RegExp("\\/itm\\/(\\d+)"); } else if (/banggood\./.test(url)) { regex = new RegExp("-p-(\\d+)\\.html"); } else if (/amazon\./.test(url)) { regex = new RegExp("\\/(?:dp|gp\\/product|gp\\/aw\\/d|gp\\/offer-listing)\\/([A-Za-z0-9]{8,15})"); } const match = url.match(regex); return match ? match[1] : null; }, getParamterBySearch: function(paramsString = window.location.href, tag) { if (paramsString.indexOf("?") != -1) { paramsString = paramsString.split("?")[1]; } const params = new URLSearchParams(paramsString); return params.get(tag); }, waitForElementByInterval: function(selector, target = document.body, allowEmpty = true, delay = 10, maxDelay = 10 * 1e3) { return new Promise((resolve, reject) => { let totalDelay = 0; let element = target.querySelector(selector); let result = allowEmpty ? !!element : !!element && !!element.innerHTML; if (result) { resolve(element); } const elementInterval = setInterval(() => { if (totalDelay >= maxDelay) { clearInterval(elementInterval); resolve(null); } element = target.querySelector(selector); result = allowEmpty ? !!element : !!element && !!element.innerHTML; if (result) { clearInterval(elementInterval); resolve(element); } else { totalDelay += delay; } }, delay); }); }, randomNumber: function() { return Math.ceil(Math.random() * 1e8); }, elementInContainer: function(container, element) { return container.contains(element); }, mustGetElement: async function(handler) { const getElements = async (h) => { const names = h.split("@").filter((s) => s.length); const promises = names.map((eleName) => { if (eleName === "body") return Promise.resolve(document.body); if (eleName === "html") return Promise.resolve(document.documentElement); return this.waitForElementByInterval(eleName, document.body, true, 10, 1500); }); return promises.length ? Promise.race(promises) : null; }; let element = await getElements(handler); if (element) return element; return new Promise((resolve) => { const waitInterval = setInterval(async () => { const el = await getElements(handler); if (el) { clearInterval(waitInterval); resolve(el); } }, 2e3); }); }, loopTask: function(callback, delay = 1500) { callback(); setInterval(() => { callback(); }, delay); }, distinguishRemoveAndTry: function(distinguish, callback) { const distinguishElements = distinguish.map((name) => document.querySelector("*[name='" + name + "']")); const validateRs = distinguishElements.some((ele) => ele === null || ele === void 0); if (validateRs) { distinguishElements.reverse().forEach((element) => { if (element) { element.remove(); } }); callback(); } }, getDomain: function(url) { try { const hostname = new URL(url).hostname; const parts = hostname.split("."); if (parts.length > 2) { return `${parts[parts.length - 2]}.${parts[parts.length - 1]}`; } return hostname; } catch (error) { return null; } }, getCommonMarketplace: function(url = window.location.href) { try { const domainParts = new URL(url).hostname.split("."); const countryCode = domainParts[domainParts.length - 1]; return countryCode; } catch (error) { } return null; }, getDocumentBody: function() { return new Promise((resolve, reject) => { if (document.body) { resolve(document.body); return; } const checkBody = setInterval(function() { if (document.body) { clearInterval(checkBody); resolve(document.body); } }, 50); }); } }; const Toast = { show: function(params) { let time = params.time; let background = params.background; let color = params.color; let position = params.position; let defaultMarginValue = 50; if (time == void 0 || time == "") { time = 1500; } if (position == void 0 || position == "") { position = "center-bottom"; } const style = document.createElement("style"); style.textContent = `@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-moz-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-o-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-ms-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-webkit-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-moz-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-o-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@-ms-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.toast-style-kk998y{position:fixed;background:rgba(0,0,0,0.7);color:#fff;font-size:14px;line-height:1;padding:10px;border-radius:3px;left:50%;transform:translateX(-50%);-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-o-transform:translateX(-50%);-ms-transform:translateX(-50%);z-index:999999999999999999999999999;white-space:nowrap}.fadeOut{animation:fadeOut .5s}.fadeIn{animation:fadeIn .5s}`; const el = document.createElement("div"); if (background != void 0 && background != "") { el.style.backgroundColor = background; } if (color != void 0 && color != "") { el.style.color = color; } el.setAttribute("class", "toast-style-kk998y"); el.innerText = params.message; el.style.zIndex = 999999999; if (position === "center-bottom") { el.style.bottom = defaultMarginValue + "px"; } else { el.style.top = defaultMarginValue + "px"; } document.body.appendChild(el); document.head.appendChild(style); el.classList.add("fadeIn"); setTimeout(function() { el.classList.remove("fadeIn"); el.classList.add("fadeOut"); el.addEventListener("animationend", function() { document.body.removeChild(el); document.head.removeChild(style); }); el.addEventListener("webkitAnimationEnd", function() { document.body.removeChild(el); document.head.removeChild(style); }); }, time); } }; const SupportData = { supports: null, support: null }; const StorageKeys = { activatePositionTop: "inspect_activate_position_top", token: "inspect_token", exchangeInfo: "exchange_info", supports: "supports_key", featureControl: { windowShow: "window_show" }, history: { goodsHistory: "goooods_history_key", offset: "goooods_wrapper_key", maximumRecordsKey: "goooods_max_records_key" }, langue: { custom: "custom_langue_key", objects: "langue_data_objects_key" } }; const DefaultValue = { lang: ScriptConst.lang, history: { historyStorage: { "aliexpress": [], "amazon": [], "shein": [], "shopee": [], "lazada": [], "ebay": [], "bestbuy": [], "banggood": [], "wish": [] }, offsetWrapper: { right: 10, bottom: 10 }, records: { min: 10, max: 500, default: 100 }, toolbarGoodsNum: 4 }, exchangeInfoLocal: { certificate: "https://www.jtmate.com/api/certificate", redirect: "https://www.jtmate.com/mid/redirect?url=" }, updateSupportsDelay: 1e3 * 60 * 5, updateExchangeInfoDelay: 1e3 * 60 * 10 }; const getRequestUrl = () => { const baseUrl = "https://o.jtm.pub"; return { supports: { method: "GET", url: baseUrl + "/api/load/conf?origin=support" }, exchangeInfo: { method: "GET", url: baseUrl + "/api/exchange/info" }, detectCoupon: { method: "POST", url: baseUrl + "/api/detect/coupon" }, detectInfo: { method: "POST", url: baseUrl + "/api/detect/info" }, getLangue: { method: "POST", url: baseUrl + "/api/load/lang" }, couponQuery: { method: "GET", url: baseUrl + "/api/coupon/query" }, couponChange: { method: "GET", url: baseUrl + "/api/coupon/change" }, couponExist: { method: "GET", url: baseUrl + "/api/coupon/exist" }, couponExistConf: { method: "GET", url: baseUrl + "/api/load/conf" }, searchEnginExistConf: { method: "GET", url: baseUrl + "/api/load/conf?origin=se" }, engineScreen: { method: "POST", url: baseUrl + "/api/engine/screen" } }; }; const StorageUtil = { getValue: function(key, defaultValue) { return GM_getValue(key, defaultValue); }, setValue: function(key, value) { GM_setValue(key, value); }, deleteValue: function(key) { GM_deleteValue(key); } }; const RequestUtil = { request: function(method, url, params) { return Tools.request(method, url, params); }, _addExtraParams: function(params) { if (!params.hasOwnProperty("url")) { params.url = encodeURIComponent(window.location.href); } if (!params.hasOwnProperty("v")) { params.v = ScriptConst.version; } if (!params.hasOwnProperty("no")) { params.no = ScriptConst.number; } const token = StorageUtil.getValue(StorageKeys.token, ""); params.token = token; return params; }, _baseQuery: function(scopName, params) { params = this._addExtraParams(params); const { method, url } = getRequestUrl()[scopName]; let finalUrl = url; if (method.toUpperCase() === "GET") { finalUrl = finalUrl + "?" + Object.entries(params).map(([key, value]) => `${key}=${value}`).join("&"); params = null; } return this.request(method, finalUrl, params); }, getCouponQuery: function(params) { return this._baseQuery("couponQuery", params); }, getCouponChange: function(params) { return this._baseQuery("couponChange", params); } }; const ItemSearchBaseObj = { visitUrl: window.location.href, searchAttribute: "loop-task-i9v---search", baseUrl: "https://oversea.mimixiaoke.com", cacheRequestMap: {}, requestAndSaveSate: function(method, url, param) { return new Promise((resolve, reject) => { const key = "key_" + new Date().getTime(); const xhr = new XMLHttpRequest(); this.cacheRequestMap[key] = xhr; if (method === "GET") { let queryString = ""; if (param) { const params = new URLSearchParams(param); queryString = "?" + params.toString(); } xhr.open(method, url + queryString); xhr.send(); } else if (method === "POST") { xhr.open(method, url); xhr.setRequestHeader("Content - Type", "application/json"); xhr.send(JSON.stringify(param)); } else { resolve({ "code": "error", "requestKey": key, "result": null }); return; } xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { try { resolve({ "code": "success", "requestKey": key, "result": xhr.responseText }); } catch (e) { resolve({ "code": "error", "requestKey": key, "result": null }); } } else { resolve({ "code": "error", "requestKey": key, "result": null }); } } }; }); }, requestConf: function() { return new Promise((resolve, reject) => { Tools.request("GET", this.baseUrl + "/api/load/conf", null).then((data) => { if (data.code == "success" && !!data.result) { resolve(data.result); } else { resolve(null); } }); }); }, pickupGoodsItem: function(platform, confString) { const visitHref = window.location.href; const selectorElementList = new Array(); let confFilter = confString; try { confFilter = confFilter.replace(/\\\\/g, "\\"); } catch (e) { } const confJson = JSON.parse(confFilter)[platform]; for (let i = 0; i < confJson.length; i++) { const itemJson = confJson[i]; if (!itemJson.hasOwnProperty("elements") || !itemJson.hasOwnProperty("matches")) { continue; } const { elements, matches } = itemJson; const isMatch = matches.map((reg) => new RegExp(reg, "i").test(visitHref)).some((res) => res); if (isMatch) { for (let j = 0; j < elements.length; j++) { selectorElementList.push({ "element": elements[j]["element"], "findA": elements[j]["findA"], "page": elements[j]["page"], "price": elements[j]["price"] }); } } } return selectorElementList; }, getGoodsLinkByElement: function(element, findTag) { let searchElement = null; if (findTag == "this") { searchElement = element; } else if (/^child@/.test(findTag)) { searchElement = element.querySelector(findTag.replace(/^child@/, "")); } return searchElement; }, getGoodsPriceByElement: function(element, tag) { if (!element || !tag) { return ""; } const goodsPrice = element.querySelector(tag); let price = goodsPrice == null ? "" : goodsPrice.innerText; if (price) { price = price.replace(/\s|,/g, ""); } return price; }, getGoodsPrice: function(content) { content = content.replace(/,/g, ""); const amount = content.match(/(?:₱|\$|฿|₫|Rp|RM|¥)\n?\d+(?:(?:\.\d{1,3})*)?/); let price = amount ? amount[0] : ""; if (price && price.indexOf("Rp") != -1) { price = price.replace(/\./g, ""); } price = price.replace(/\n|,/g, ""); return price; }, isElementDisplayed: function(element) { if (element.offsetParent !== null) { return true; } const style = window.getComputedStyle(element); return style.display !== "none"; }, calcRequestGroup: function(array, itemsPerGroup = 10) { const groups = []; for (let i = 0; i < array.length; i += itemsPerGroup) { groups.push(array.slice(i, i + itemsPerGroup)); } return groups; } }; const Aliexpress = { languageStorageKey: "aliexpress-language-key", currencyStorageKey: "aliexpress-currency-key", marketplaceStorageKey: "aliexpress-marketplace-key", checkDomInsertRs: true, getLang: function() { const host = window.location.host; let lang = "en"; if (/^(us|ko|uk|fr|de|it|ca|au|jp|ja|he|kr|ru|br|in|es|mx|pl|tr|ar|id|th|vn|sg|my|ph|be|nl|se|ch|no|dk|at|ie|fi|pt|gr|hu|cz|bg|ro|ua|il|sa|eg|ir|pk|iq|af|ly|et|gh|ke|ng|za|tz|mg|mw|zm|bw|sn|cm|ci|gh|ma|tn|mr|mu|om|kw|qa|bh|ae|lb|jo|sy|lb|il|ps|kr|cl|pe|uy|ec|ve|bo|gt|pa|hn|ni|cr|sv|gt|sl|lr|sd|er|dj|et|mw|mz|ao|tz|zm|zw|mw|na|bw|ls|mg|km)\.aliexpress\.com$/.test(host)) { lang = host.split(".")[0]; } else if (/^www\.aliexpress\.com$/.test(host)) { lang = "en"; } else if (/^aliexpress\.ru$/.test(host)) { lang = "ru"; } GM_setValue(this.languageStorageKey, lang); return lang; }, getMarketplace: async function(marketplaceHandler) { let countryCode = ""; const host = window.location.host; if (/^(us|ko|uk|fr|de|it|ca|au|jp|ja|he|kr|ru|br|in|es|mx|pl|tr|ar|id|th|vn|sg|my|ph|be|nl|se|ch|no|dk|at|ie|fi|pt|gr|hu|cz|bg|ro|ua|il|sa|eg|ir|pk|iq|af|ly|et|gh|ke|ng|za|tz|mg|mw|zm|bw|sn|cm|ci|gh|ma|tn|mr|mu|om|kw|qa|bh|ae|lb|jo|sy|lb|il|ps|kr|cl|pe|uy|ec|ve|bo|gt|pa|hn|ni|cr|sv|gt|sl|lr|sd|er|dj|et|mw|mz|ao|tz|zm|zw|mw|na|bw|ls|mg|km)\.aliexpress\.com$/.test(host)) { countryCode = host.split(".")[0]; } else { countryCode = host.split(".").slice(-1)[0]; } let marketplace = GM_getValue(this.marketplaceStorageKey, null); const defaultMarketplace = { countryCode, className: "", html: "" }; if (marketplaceHandler && !/\.ru/.test(host)) { const handlerElement = await Tools.waitForElementByInterval(marketplaceHandler, document.body, true, 50, 2 * 1e3); if (handlerElement) { marketplace = { countryCode, className: handlerElement.className ?? "", html: handlerElement.outerHTML ?? "" }; GM_setValue(this.marketplaceStorageKey, marketplace); } } if (!marketplace) { marketplace = defaultMarketplace; } return encodeURIComponent(JSON.stringify(marketplace)); }, getCurrency: function() { const host = window.location.host; return new Promise((resolve, reject) => { if (host.indexOf("aliexpress.ru") != -1) { resolve("unknown"); } else { const element = document.querySelector("div[class^='ship-to--menuItem--']") || document.querySelector("div[class^='countryFlag--']"); if (element) { let currency = element.textContent; if (currency) { currency = encodeURIComponent(currency); GM_setValue(this.currencyStorageKey, currency); resolve(currency); } else { resolve("unknown"); } } else { resolve("unknown"); } } }); }, detail: async function(marketplaceHandler) { const visitUrl = window.location.href; const validate = [/\/item\/[^\/]*?\.html\?/, /\/item\/[^\/]*?\.html$/].map((reg) => reg.test(visitUrl)).some((rs) => rs == true); if (!validate) return; const language = this.getLang(); const currency = await this.getCurrency(); const marketplace = await this.getMarketplace(marketplaceHandler); const id = Tools.getGoodsIdByLink(visitUrl); try { const params = { "ids": id, "qu": "", "p": SupportData.support.p, "lang": language, "mul": false, "currency": currency, "marketplace": marketplace }; const data = await RequestUtil.getCouponQuery(params); if (data.code == "success" && !!data.result) { const json = JSON.parse(data.result); Logger.log("info", "detail request json=", json); await this.detailAnalyze(json, language, currency, marketplace); } } catch (e) { } }, detailAnalyze: async function(json, language, currency, marketplace) { this.checkDomInsertRs = false; try { if (!json) return; let couponResult = null; let qrcodeResult = null; if (!!json.data && !!json.data.css && !!json.data.html && !!json.data.handler) { const { handler, css, html, templateId, distinguish, hint } = json.data; var mid = null; if (json.data.hasOwnProperty("mid")) { mid = json.data["mid"]; } GM_addStyle(css); const element = await Tools.mustGetElement(handler); Logger.log("info", "coupon insert:element", element); if (element) { couponResult = { "element": element, "html": html, "templateId": templateId, "distinguish": distinguish, "hint": hint, "mid": mid }; } } if (!!json.id && !!json.mscan && !!json.mscan.html && !!json.mscan.mount) { const { iden, html, mount, distinguish } = json.mscan; const id = json.id; const promiseResultArray = []; const elementPromise = Tools.mustGetElement(mount); const params = { "id": id, "lang": language, "platform": SupportData.support.p, "currency": currency, "marketplace": marketplace }; const reqPromise = RequestUtil.getCouponChange(params); promiseResultArray.push(elementPromise, reqPromise); const allResult = await Promise.all(promiseResultArray); let element = null, qrcodeData = null; for (let i = 0; i < allResult.length; i++) { if (allResult[i]) { if (allResult[i].hasOwnProperty("code")) { qrcodeData = allResult[i]; } else { element = allResult[i]; } } } Logger.log("info", "qrcocd insert:element", element); if (element && qrcodeData) { qrcodeResult = { "element": element, "html": html, "iden": iden, "qrcodeData": qrcodeData, "distinguish": distinguish }; } } Tools.loopTask(() => { if (couponResult) { Tools.distinguishRemoveAndTry(couponResult.distinguish, () => { this.detailCouponAnalyze(couponResult); }); } if (qrcodeResult) { Tools.distinguishRemoveAndTry(qrcodeResult.distinguish, () => { this.detailMscanAnalyze(qrcodeResult); }); } }); } catch (error) { } finally { this.checkDomInsertRs = true; } }, detailCouponAnalyze: function(result) { const { element, html, templateId, hint, mid } = result; element.insertAdjacentHTML("afterend", html); const templateIdEle = document.querySelector("div[id='" + templateId + "']"); if (templateIdEle) { const couponCodeElement = templateIdEle.querySelector(".coupon-code"); if (couponCodeElement) { const promoCode = Tools.decryptStr(couponCodeElement.getAttribute("data-encryptcode")); templateIdEle.addEventListener("click", () => { GM_setClipboard(promoCode, "txt", () => { Toast.show({ "message": hint, "background": "#D3031C" }); if (mid && mid.hasOwnProperty("target") && mid.hasOwnProperty("link") && mid.hasOwnProperty("delay")) { const { target, link, delay } = mid, linkDecrypt = Tools.decryptStr(link); setTimeout(() => { if (target === "_blank") { Tools.openInTab(linkDecrypt); } else if (target === "_self") { window.location.href = linkDecrypt; } else if (target === "_replace") { window.location.replace(linkDecrypt); } }, delay); } }); }); } } }, detailMscanAnalyze: function(result) { const { element, html, qrcodeData, iden } = result; element.insertAdjacentHTML("afterend", html); if (!!qrcodeData && qrcodeData.code === "success" && !!qrcodeData.result) { const mscanImg = JSON.parse(qrcodeData.result).mscanImg; if (!!mscanImg) { const canvasElement = document.getElementById("mscan" + iden); if (canvasElement) { var cxt = canvasElement.getContext("2d"); var imgData = new Image(); imgData.src = mscanImg; imgData.onload = function() { cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height); }; } } } }, trade: async function() { const visitUrl = window.location.href; const validate = SupportData.support.trade.map((reg) => reg.test(visitUrl)).some((rs) => rs == true); if (!validate) return; const language = await GM_getValue(this.languageStorageKey, navigator.language); const currency = await GM_getValue(this.currencyStorageKey, "USD"); const marketplace = await this.getMarketplace(); const ids = Tools.getParamterBySearch(window.location.search, "objectId") || Tools.getParamterBySearch(window.location.search, "availableProductShopcartIds") || Tools.getParamterBySearch(window.location.search, "itemId"); const params = { "ids": ids, "qu": "", "p": SupportData.support.p, "lang": language, "mul": true, "currency": currency, "marketplace": marketplace }; const res = await RequestUtil.getCouponQuery(params); if (res.code == "success" && !!res.result) { const json = JSON.parse(res.result); await this.tradeAnalyze(json, language); } }, tradeAnalyze: async function(json, language) { if (!json || !json.handler || !json.css || !json.templateId) { return; } const { handler, css, html, templateId, distinguish } = json; GM_addStyle(css); let element = await Tools.mustGetElement(handler); Tools.loopTask(() => { if (!element) { return; } Tools.distinguishRemoveAndTry(distinguish, () => { element.insertAdjacentHTML("afterend", html); const templateIdEle = document.querySelector("#" + templateId + ">.item"); if (templateIdEle) { const promoCode = Tools.decryptStr(templateIdEle.querySelector(".copy").getAttribute("data-encryptcode")); templateIdEle.addEventListener("click", () => { GM_setClipboard(promoCode, "txt", () => { Toast.show({ "message": "copied", "background": "#D3031C" }); }); }); const arrowElement = document.querySelector(".pl-summary__item-arrow-pc"); if (arrowElement) { arrowElement.click(); } } }); }); }, removeAnchor: function() { setInterval(() => { const anchors = document.querySelectorAll("div[name^='ali-gogo-coupon-']"); anchors.forEach((element) => { Tools.removeAnchorsByNode(element); }); }, 3e3); }, start: async function() { const { support } = SupportData; const visitUrl = window.location.href; if (support.detail.test(visitUrl)) { this.detail(support.marketplace); } this.trade(); this.removeAnchor(); } }; const AliexpressSearch = { loopIsComplete: true, cacheLinkDoms: {}, isInbusinessPage: function() { return /inbusiness\.aliexpress\.com\/web\/search-products/.test(ItemSearchBaseObj.visitUrl); }, isItemLink: function(url) { return SupportData.support.detail.test(url); }, pickUpWholesale: async function(selectors, language, currency, marketplace, couponExistPer) { const items = []; try { selectors.forEach((elementObj) => { if (elementObj.element) { const elements = document.querySelectorAll(elementObj.element + ":not([" + ItemSearchBaseObj.searchAttribute + "='true'])"); Logger.log("info", "search coupon elements======>", elements.length); const findA = elementObj.findA; elements.forEach((element) => { if (element && ItemSearchBaseObj.isElementDisplayed(element) && !element.getAttribute(ItemSearchBaseObj.searchAttribute)) { const goodsLink2 = ItemSearchBaseObj.getGoodsLinkByElement(element, findA); let id = null; if (this.isItemLink(goodsLink2)) { id = Tools.getGoodsIdByLink(goodsLink2.getAttribute("href")); this.cacheLinkDoms[id] = goodsLink2; } if (id) { items.push({ "id": id, "platform": SupportData.support.p, "handler": element, "findA": findA, "from": "wholesale" }); } } }); } }); if (items.length > 0) { await this.search(items, language, currency, marketplace, couponExistPer); } } catch (e) { } }, pickUpInbusiness: async function(language, currency, marketplace, couponExistPer) { const validate = this.isInbusinessPage(); if (!validate) return; try { const iceContainerElement = document.querySelector("#ice-container"); const loadMoreElement = await Tools.waitForElementByInterval("#loadMore", iceContainerElement); if (loadMoreElement) { const array = new Array(); const containerElement = loadMoreElement.previousElementSibling; if (containerElement && containerElement.tagName === "DIV") { const childNodes = containerElement.childNodes; childNodes.forEach((child) => { if (child.tagName === "A" && ItemSearchBaseObj.isElementDisplayed(child) && !child.getAttribute(ItemSearchBaseObj.searchAttribute)) { const id = Tools.getGoodsIdByLink(child.getAttribute("href")); if (id) { array.push({ "id": id, "platform": SupportData.support.p, "handler": child, "from": "inbusiness" }); this.cacheLinkDoms[id] = goodsLink; } } }); } await this.search(array, language, currency, marketplace, couponExistPer); } } catch (e) { } }, search: function(array, language, currency, marketplace, couponExistPer) { const groups = ItemSearchBaseObj.calcRequestGroup(array, couponExistPer); const len = groups.length; return new Promise((resolve, reject) => { if (len <= 0) { resolve("complete"); return; } const promises = []; for (let i = 0; i < groups.length; i++) { promises.push(this.createItemHtml(groups[i], language, currency, marketplace)); } Promise.all(promises).then((data) => { resolve("complete"); }); }); }, createItemHtml: function(group, language, currency, marketplace) { return new Promise((resolve, reject) => { try { if (Array.isArray(group) && group.length === 0) { resolve("exception"); return; } let reqId = ""; const platform = group[0].platform; for (var i = 0; i < group.length; i++) { if (group[i].handler.getAttribute(ItemSearchBaseObj.searchAttribute)) { continue; } reqId += group[i].id + ","; group[i].handler.setAttribute(ItemSearchBaseObj.searchAttribute, "true"); } if (reqId.endsWith(",")) { reqId = reqId.slice(0, -1); } Logger.log("info", "request start >>>>>>>>>>>>>", group); const searchUrl = ItemSearchBaseObj.baseUrl + "/api/coupon/exist?platform=" + platform + "&ids=" + reqId + "&lang=" + language + "&no=13&v=1.0.1¤cy=" + currency + "&marketplace=" + marketplace; Logger.log("info", "request searchUrl >>>>>>>>>>>>>:", searchUrl); ItemSearchBaseObj.requestAndSaveSate("GET", searchUrl, null).then((data) => { Logger.log("info", "request finish >>>>>>>>>>>>>"); delete ItemSearchBaseObj.cacheRequestMap[data.requestKey]; if (data.code != "success" || !data.result) { resolve("exception"); return; } const json = JSON.parse(data.result); Logger.log("info", "json", json); let isBroken = false; for (let key in json) { const { encryptLink, tip } = json[key]; const item = group.find((obj) => obj.id === key); if (!item) { continue; } let handler = null, findA = null; if (item.hasOwnProperty("handler") && item.hasOwnProperty("findA")) { handler = item.handler; findA = item.findA; } if (!handler || !findA) { continue; } let decryptUrl = null; if (encryptLink) { try { const decryptLink = atob(encryptLink); decryptUrl = decryptLink.split("").reverse().join(""); } catch (e) { } } const elementA = ItemSearchBaseObj.getGoodsLinkByElement(handler, findA); const currentId = elementA ? Tools.getGoodsIdByLink(elementA.getAttribute("href")) : ""; if (currentId != key) { group.forEach((gItem) => { const ele = gItem.handler; ele.removeAttribute(ItemSearchBaseObj.searchAttribute); const tipElement = ele.querySelector("div[name^='ali-gogo-coupon-']"); if (tipElement) { tipElement.remove(); } }); Logger.log("info", "exception currentGoodsId != request id"); isBroken = true; break; } else { if (tip) { handler.style.position = "relative"; handler.insertAdjacentHTML("beforeend", tip); Logger.log("info", "exist coupon >>>>>>>>>>>>>", key); } if (decryptUrl) { this.relativeJ(handler, decryptUrl); Logger.log("info", "good job >>>>>>>>>>>>>", key); } } } resolve(isBroken ? "broken" : "complete"); }); } catch (e) { resolve("exception"); } }); }, relativeJ: function(handler, decryptUrl) { const clickTipAttribute = "tip-vjd1jd89fcv-i"; let elements = null; if (handler.tagName == "A") { elements = [handler]; } else { elements = handler.querySelectorAll("a"); } elements.forEach((elementA) => { const href = elementA.getAttribute("href"); if (this.isItemLink(href)) { if (elementA.getAttribute(clickTipAttribute)) { return; } elementA.setAttribute(clickTipAttribute, "true"); elementA.addEventListener("click", function(e) { let isPreventDefault = true; const target = e.target; const tagName = target.tagName.toUpperCase(); if (tagName == "A") { const href2 = target.getAttribute("href"); if (!this.isItemLink(href2)) { isPreventDefault = false; } } if (isPreventDefault) { Array.from(target.classList).forEach((className) => { const iscontains = ["icon", "-btn-"].map((name) => className.indexOf(name) != -1).some((result) => result); if (iscontains) { isPreventDefault = false; } }); } if (isPreventDefault) { e.preventDefault(); e.stopPropagation(); Tools.openInTab(decryptUrl); } }); } }); }, isRun: function() { let run = false; if (window.location.host.indexOf("aliexpress.") != -1) { run = !/\/(item|trade|checkout)\//.test(window.location.pathname); } return run; }, changePageEvent: function() { let hookDivTimer = null, removeTagIsComplete = true; const onInitDom = () => { if (!removeTagIsComplete) return; removeTagIsComplete = false; const attr = ItemSearchBaseObj.searchAttribute; document.querySelectorAll(`*[${attr}='true']`).forEach((el) => { el.removeAttribute(attr); const tip = el.querySelector("*[name^='ali-gogo-coupon-']"); if (tip) { tip.remove(); } }); removeTagIsComplete = true; this.cacheLinkDoms = {}; }; const checkObjectValues = () => { const obj = this.cacheLinkDoms; const keys = Object.keys(obj); let notContain = 0; for (let i = 0; i < keys.length; i++) { const key = keys[i]; const el = obj[key]; try { const href = el.getAttribute("href"); if (!href.includes(key)) { if (++notContain > 2) return true; } } catch (e) { } } return false; }; const observer = new MutationObserver((mutations) => { const hasDelete = mutations.some( (m) => m.target === document.body && m.removedNodes.length > 0 ); if (!hasDelete) return; if (hookDivTimer) clearTimeout(hookDivTimer); hookDivTimer = setTimeout(() => { hookDivTimer = null; if (checkObjectValues()) onInitDom(); }, 500); }); observer.observe(document.body, { childList: true, subtree: false }); }, start: async function() { const { support } = SupportData; if (!this.isRun()) { return; } const language = Aliexpress.getLang(); const currency = await Aliexpress.getCurrency(); const marketplace = await Aliexpress.getMarketplace(support.marketplace); const confString = await ItemSearchBaseObj.requestConf(); if (!confString) { return; } const couponExistPer = support.couponExistPer || 10; const selectors = ItemSearchBaseObj.pickupGoodsItem(SupportData.support.p, confString); setInterval(async () => { if (this.loopIsComplete) { this.loopIsComplete = false; await this.pickUpInbusiness(language, currency, marketplace, couponExistPer); await this.pickUpWholesale(selectors, language, currency, marketplace, couponExistPer); this.loopIsComplete = true; } }, 1700); if (selectors.length != 0 && window.location.pathname != "/") { this.changePageEvent(); } } }; const Ebay = { detail: async function() { const visitUrl = window.location.href; const id = Tools.getGoodsIdByLink(visitUrl); const varG = Tools.getParamterBySearch(window.location.href, "var"); if (!id) { return; } const marketplace = Tools.getCommonMarketplace(visitUrl); var idsG = id; if (!!varG) { idsG += "@" + varG; } try { const params = { "ids": idsG, "qu": "", "p": SupportData.support.p, "marketplace": marketplace, "mul": false }; const data = await RequestUtil.getCouponQuery(params); if (data.code == "success" && !!data.result) { const json = JSON.parse(data.result); Logger.log("info", "detail request json=", json); await this.detailAnalyze(json, marketplace); } } catch (e) { } }, detailAnalyze: async function(json, marketplace) { let couponResult = null; let qrcodeResult = null; if (!!json.data && !!json.data.css && !!json.data.html && !!json.data.handler) { const { handler, css, html, templateId, distinguish, hint } = json.data; var mid = null; if (json.data.hasOwnProperty("mid")) { mid = json.data["mid"]; } GM_addStyle(css); const element = await Tools.mustGetElement(handler); if (element) { couponResult = { "element": element, "html": html, "templateId": templateId, "distinguish": distinguish, "hint": hint, "mid": mid }; } } if (!!json.id && !!json.mscan && !!json.mscan.html && !!json.mscan.mount) { const { iden, html, mount, distinguish } = json.mscan; const id = json.id; const promiseResultArray = []; const elementPromise = Tools.mustGetElement(mount); const params = { "id": id, "marketplace": marketplace, "platform": SupportData.support.p }; const reqPromise = RequestUtil.getCouponChange(params); promiseResultArray.push(elementPromise, reqPromise); const allResult = await Promise.all(promiseResultArray); let element = null, qrcodeData = null; for (let i = 0; i < allResult.length; i++) { if (allResult[i]) { if (allResult[i].hasOwnProperty("code")) { qrcodeData = allResult[i]; } else { element = allResult[i]; } } } if (element && qrcodeData) { qrcodeResult = { "element": element, "html": html, "iden": iden, "qrcodeData": qrcodeData, "distinguish": distinguish }; } } Tools.loopTask(() => { if (couponResult) { Tools.distinguishRemoveAndTry(couponResult.distinguish, () => { this.detailCouponAnalyze(couponResult); }); } if (qrcodeResult) { Tools.distinguishRemoveAndTry(qrcodeResult.distinguish, () => { this.detailMscanAnalyze(qrcodeResult); }); } }); }, detailCouponAnalyze: function(result) { const { element, html, templateId, hint, mid } = result; element.insertAdjacentHTML("afterend", html); const templateIdEle = document.querySelector("div[id='" + templateId + "']"); if (templateIdEle) { const couponCodeElement = templateIdEle.querySelector(".coupon-code"); if (couponCodeElement) { const promoCode = Tools.decryptStr(couponCodeElement.getAttribute("data-encryptcode")); templateIdEle.addEventListener("click", () => { GM_setClipboard(promoCode, "txt", () => { Toast.show({ "message": hint, "background": "#D3031C" }); if (mid && mid.hasOwnProperty("target") && mid.hasOwnProperty("link") && mid.hasOwnProperty("delay")) { const { target, link, delay } = mid, linkDecrypt = Tools.decryptStr(link); setTimeout(() => { if (target === "_blank") { Tools.openInTab(linkDecrypt); } else if (target === "_self") { window.location.href = linkDecrypt; } else if (target === "_replace") { window.location.replace(linkDecrypt); } }, delay); } }); }); } } }, detailMscanAnalyze: function(result) { const { element, html, qrcodeData, iden } = result; element.insertAdjacentHTML("afterend", html); if (!!qrcodeData && qrcodeData.code === "success" && !!qrcodeData.result) { const mscanImg = JSON.parse(qrcodeData.result).mscanImg; if (!!mscanImg) { const canvasElement = document.getElementById("mscan" + iden); if (canvasElement) { var cxt = canvasElement.getContext("2d"); var imgData = new Image(); imgData.src = mscanImg; imgData.onload = function() { cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height); }; } } } }, start: async function() { const { support } = SupportData; const visitUrl = window.location.href; if (support.detail.test(visitUrl)) { this.detail(); } } }; const EbaySearch = { loopIsComplete: true, isRun: function() { let run = false; if (window.location.host.indexOf("ebay.") != -1) { run = !/\/(item|itm|trade|checkout|rxo)\//.test(window.location.pathname); } return run; }, isItemLink: function(url) { return SupportData.support.detail.test(url); }, pickUpItems: async function(selectors, marketplace, couponExistPer) { const items = []; try { selectors.forEach((elementObj) => { if (elementObj.element) { const elements = document.querySelectorAll(elementObj.element + ":not([" + ItemSearchBaseObj.searchAttribute + "='true'])"); Logger.log("info", "search coupon elements======>", elements); const findA = elementObj.findA; elements.forEach((element) => { if (element && ItemSearchBaseObj.isElementDisplayed(element) && !element.getAttribute(ItemSearchBaseObj.searchAttribute)) { const goodsLink = ItemSearchBaseObj.getGoodsLinkByElement(element, findA); const priceQuery = elementObj.price; Logger.log("info", "search price elements======>", element, priceQuery); const price = ItemSearchBaseObj.getGoodsPriceByElement(element, priceQuery); Logger.log("info", "search price======>", price); let id = null, varG = null; if (this.isItemLink(goodsLink)) { const goodsLinkHref = goodsLink.getAttribute("href"); id = Tools.getGoodsIdByLink(goodsLinkHref); varG = Tools.getParamterBySearch(goodsLinkHref, "var"); } if (id) { items.push({ "id": id, "varG": varG, "price": price, "platform": SupportData.support.p, "handler": element, "findA": findA, "from": "search" }); } } }); } }); Logger.log("info", items); if (items.length > 0) { await this.search(items, marketplace, couponExistPer); } } catch (e) { } }, search: async function(array, marketplace, couponExistPer) { const groups = ItemSearchBaseObj.calcRequestGroup(array, couponExistPer); const len = groups.length; return new Promise((resolve, reject) => { if (len <= 0) { resolve("complete"); return; } const promises = []; for (let i = 0; i < groups.length; i++) { promises.push(this.createItemHtml(groups[i], marketplace)); } Promise.all(promises).then((data) => { resolve("complete"); }); }); }, createItemHtml: function(group, marketplace) { return new Promise((resolve, reject) => { try { if (Array.isArray(group) && group.length === 0) { resolve("exception"); return; } let reqId = ""; const platform = group[0].platform; for (var i = 0; i < group.length; i++) { if (group[i].handler.getAttribute(ItemSearchBaseObj.searchAttribute)) { continue; } reqId += group[i].id; if (!!group[i].varG) { reqId += "@" + group[i].varG; } reqId += ":" + group[i].price + ","; group[i].handler.setAttribute(ItemSearchBaseObj.searchAttribute, "true"); } if (reqId.endsWith(",")) { reqId = reqId.slice(0, -1); } Logger.log("info", "request start >>>>>>>>>>>>>", group); const searchUrl = ItemSearchBaseObj.baseUrl + "/api/coupon/exist?platform=" + platform + "&ids=" + reqId + "&marketplace=" + marketplace + "&no=13&v=1.0.1"; Logger.log("info", "request searchUrl >>>>>>>>>>>>>:", searchUrl); ItemSearchBaseObj.requestAndSaveSate("GET", searchUrl, null).then((data) => { Logger.log("info", "request finish >>>>>>>>>>>>>", data); delete ItemSearchBaseObj.cacheRequestMap[data.requestKey]; if (data.code != "success" || !data.result) { resolve("exception"); return; } const json = JSON.parse(data.result); for (let key in json) { const { encryptLink, tip } = json[key]; const item = group.find((obj) => obj.id === key); if (!item) { continue; } let handler = null, findA = null; if (item.hasOwnProperty("handler") && item.hasOwnProperty("findA")) { handler = item.handler; findA = item.findA; } if (!handler || !findA) { continue; } let decryptUrl = null; if (encryptLink) { try { const decryptLink = atob(encryptLink); decryptUrl = decryptLink.split("").reverse().join(""); } catch (e) { } } const elementA = ItemSearchBaseObj.getGoodsLinkByElement(handler, findA); if (tip) { handler.style.position = "relative"; handler.insertAdjacentHTML("beforeend", tip); Logger.log("info", "exist coupon >>>>>>>>>>>>>", key); } if (decryptUrl) { this.relativeJ(handler, decryptUrl); Logger.log("info", "good job >>>>>>>>>>>>>", key); } } resolve("complete"); }); } catch (e) { resolve("exception"); } }); }, relativeJ: function(handler, decryptUrl) { const clickTipAttribute = "tip-vjd1jd89fcv-i", self = this; let elements = null; if (handler.tagName == "A") { elements = [handler]; } else { elements = handler.querySelectorAll("a"); } elements.forEach((elementA) => { const href = elementA.getAttribute("href"); if (self.isItemLink(href)) { if (elementA.getAttribute(clickTipAttribute)) { return; } elementA.setAttribute(clickTipAttribute, "true"); elementA.addEventListener("click", function(e) { let isPreventDefault = true; const target = e.target; const tagName = target.tagName.toUpperCase(); if (tagName == "A") { const href2 = target.getAttribute("href"); if (!self.isItemLink(href2)) { isPreventDefault = false; } } if (isPreventDefault) { Array.from(target.classList).forEach((className) => { const iscontains = ["btn", "icon"].map((name) => className.indexOf(name) != -1).some((result) => result); if (iscontains) { isPreventDefault = false; } }); } if (isPreventDefault) { e.preventDefault(); e.stopPropagation(); Tools.openInTab(decryptUrl); } }); } }); }, start: async function() { const { support } = SupportData; if (!this.isRun()) { return; } const marketplace = Tools.getCommonMarketplace(window.location.href); const confString = await ItemSearchBaseObj.requestConf(); if (!confString) { return; } const couponExistPer = support.couponExistPer || 10; const selectors = ItemSearchBaseObj.pickupGoodsItem(SupportData.support.p, confString); setInterval(async () => { if (this.loopIsComplete) { this.loopIsComplete = false; await this.pickUpItems(selectors, marketplace, couponExistPer); this.loopIsComplete = true; } }, 1700); } }; const Lazada = { detailMyMscanAnalyze: async function(result) { const { id, iden, marketplace, platform, mount, html, cmd } = result; if (!mount || !html) { return; } if (cmd && cmd.do && cmd.ele) { const cmdElement = await Tools.waitForElementByInterval(cmd.ele); if (cmdElement) { if (cmd.do == "empty") { cmdElement.innerHTML = ""; } } } const element = await Tools.mustGetElement(mount); if (!element) { return; } element.insertAdjacentHTML("beforeend", html); const params = { "id": id, "marketplace": marketplace, "platform": platform }; const qrcodeData = await RequestUtil.getCouponChange(params); if (!!qrcodeData && qrcodeData.code === "success" && !!qrcodeData.result) { let mscanImg = JSON.parse(qrcodeData.result).mscanImg; if (!!mscanImg) { var canvasElement = document.getElementById("mscan" + iden); if (!!canvasElement) { var cxt = canvasElement.getContext("2d"); var imgData = new Image(); imgData.src = mscanImg; imgData.onload = function() { cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height); }; } } } }, detail: async function() { const visitUrl = window.location.href; const marketplace = Tools.getCommonMarketplace(visitUrl); const ids = Tools.getGoodsIdByLink(visitUrl); if (!ids) { return; } try { const params = { "ids": ids, "qu": "", "p": SupportData.support.p, "marketplace": marketplace, "mul": false }; const data = await RequestUtil.getCouponQuery(params); if (!!data && data.code === "success" && !!data.result) { const json = JSON.parse(data.result); if (json && json.mscan) { const { distinguish, iden, html, cmd, mount } = json.mscan; const mscanResult = { "id": json.id, "iden": iden, "marketplace": marketplace, "platform": SupportData.support.p, "mount": mount, "html": html, "cmd": cmd }; Tools.loopTask(() => { Tools.distinguishRemoveAndTry(distinguish, () => { this.detailMyMscanAnalyze(mscanResult); }); }); } } } catch (e) { } }, start: async function() { const { support } = SupportData; const visitUrl = window.location.href; if (support.detail.test(visitUrl)) { this.detail(); } } }; const LazadaSearch = { loopIsComplete: true, isRun: function() { let run = false; if (window.location.host.indexOf("lazada.") != -1) { run = !this.isItemLink(window.location.href) && !/\/(\/shipping\\?)\//.test(window.location.pathname); } return run; }, isItemLink: function(url) { return SupportData.support.detail.test(url); }, pickUpItems: async function(selectors, marketplace, couponExistPer) { const items = []; try { selectors.forEach((elementObj) => { if (elementObj.element) { const elements = document.querySelectorAll(elementObj.element + ":not([" + ItemSearchBaseObj.searchAttribute + "='true'])"); Logger.log("info", "search coupon elements======>", elements); const findA = elementObj.findA; elements.forEach((element) => { if (element && ItemSearchBaseObj.isElementDisplayed(element) && !element.getAttribute(ItemSearchBaseObj.searchAttribute)) { const goodsLink = ItemSearchBaseObj.getGoodsLinkByElement(element, findA); const price = ItemSearchBaseObj.getGoodsPrice(element.innerText); let id = null; if (this.isItemLink(goodsLink)) { id = Tools.getGoodsIdByLink(goodsLink.getAttribute("href")); } if (id) { items.push({ "id": id, "price": price, "platform": SupportData.support.p, "handler": element, "findA": findA, "from": "search" }); } } }); } }); Logger.log("info", items); if (items.length > 0) { await this.search(items, marketplace, couponExistPer); } } catch (e) { } }, search: async function(array, marketplace, couponExistPer) { const groups = ItemSearchBaseObj.calcRequestGroup(array, couponExistPer); const len = groups.length; return new Promise((resolve, reject) => { if (len <= 0) { resolve("complete"); return; } const promises = []; for (let i = 0; i < groups.length; i++) { promises.push(this.createItemHtml(groups[i], marketplace)); } Promise.all(promises).then((data) => { resolve("complete"); }); }); }, createItemHtml: function(group, marketplace) { return new Promise((resolve, reject) => { try { if (Array.isArray(group) && group.length === 0) { resolve("exception"); return; } let reqId = ""; const platform = group[0].platform; for (var i = 0; i < group.length; i++) { if (group[i].handler.getAttribute(ItemSearchBaseObj.searchAttribute)) { continue; } reqId += group[i].id + ":" + group[i].price + ","; group[i].handler.setAttribute(ItemSearchBaseObj.searchAttribute, "true"); } if (reqId.endsWith(",")) { reqId = reqId.slice(0, -1); } Logger.log("info", "request start >>>>>>>>>>>>>", group); const searchUrl = ItemSearchBaseObj.baseUrl + "/api/coupon/exist?platform=" + platform + "&ids=" + reqId + "&marketplace=" + marketplace + "&no=13&v=1.0.1"; Logger.log("info", "request searchUrl >>>>>>>>>>>>>:", searchUrl); ItemSearchBaseObj.requestAndSaveSate("GET", searchUrl, null).then((data) => { Logger.log("info", "request finish >>>>>>>>>>>>>", data); delete ItemSearchBaseObj.cacheRequestMap[data.requestKey]; if (data.code != "success" || !data.result) { resolve("exception"); return; } const json = JSON.parse(data.result); Logger.log("info", "request finish json>>>>>>>>>>>>>", json); for (let key in json) { const { encryptLink, tip } = json[key]; const { handler, findA } = group.find((obj) => obj.id === key); let decryptUrl = null; if (encryptLink) { try { const decryptLink = atob(encryptLink); decryptUrl = decryptLink.split("").reverse().join(""); } catch (e) { } } const elementA = ItemSearchBaseObj.getGoodsLinkByElement(handler, findA); if (tip) { handler.style.position = "relative"; handler.insertAdjacentHTML("beforeend", tip); Logger.log("info", "exist coupon >>>>>>>>>>>>>", key); } if (decryptUrl) { this.relativeJ(handler, decryptUrl); Logger.log("info", "good job >>>>>>>>>>>>>", key); } } resolve("complete"); }); } catch (e) { resolve("exception"); } }); }, relativeJ: function(handler, decryptUrl) { let selectorA = null; if (handler.tagName == "A") { selectorA = [handler]; } else { selectorA = handler.querySelectorAll("a"); } selectorA.forEach((element_a) => { if (this.isItemLink(element_a.getAttribute("href"))) { element_a.addEventListener("click", function(e) { e.preventDefault(); e.stopPropagation(); Tools.openInTab(decryptUrl); }); } }); }, start: async function() { const { support } = SupportData; if (!this.isRun()) { return; } const marketplace = Tools.getCommonMarketplace(window.location.href); const confString = await ItemSearchBaseObj.requestConf(); if (!confString) { return; } const couponExistPer = support.couponExistPer || 10; const selectors = ItemSearchBaseObj.pickupGoodsItem(SupportData.support.p, confString); setInterval(async () => { if (this.loopIsComplete) { this.loopIsComplete = false; await this.pickUpItems(selectors, marketplace, couponExistPer); this.loopIsComplete = true; } }, 1700); } }; const Bestbuy = { detail: async function() { const visitUrl = window.location.href; const id = Tools.getGoodsIdByLink(visitUrl); if (!id) { return; } const marketplace = Tools.getCommonMarketplace(visitUrl); try { const params = { "ids": id, "qu": "", "p": SupportData.support.p, "marketplace": marketplace, "mul": false }; const data = await RequestUtil.getCouponQuery(params); if (data.code == "success" && !!data.result) { const json = JSON.parse(data.result); Logger.log("info", "detail request json=", json); await this.detailAnalyze(json, marketplace); } } catch (e) { } }, detailAnalyze: async function(json, marketplace) { let couponResult = null; let qrcodeResult = null; if (!!json.data && !!json.data.css && !!json.data.html && !!json.data.handler) { const { handler, css, html, templateId, distinguish } = json.data; GM_addStyle(css); const element = await Tools.mustGetElement(handler); if (element) { couponResult = { "element": element, "html": html, "templateId": templateId, "distinguish": distinguish }; } } if (!!json.id && !!json.mscan && !!json.mscan.html && !!json.mscan.mount) { const { iden, html, mount, distinguish } = json.mscan; const id = json.id; const promiseResultArray = []; const elementPromise = Tools.mustGetElement(mount); const params = { "id": id, "marketplace": marketplace, "platform": SupportData.support.p }; const reqPromise = RequestUtil.getCouponChange(params); promiseResultArray.push(elementPromise, reqPromise); const allResult = await Promise.all(promiseResultArray); let element = null, qrcodeData = null; for (let i = 0; i < allResult.length; i++) { if (allResult[i]) { if (allResult[i].hasOwnProperty("code")) { qrcodeData = allResult[i]; } else { element = allResult[i]; } } } if (element && qrcodeData) { qrcodeResult = { "element": element, "html": html, "iden": iden, "qrcodeData": qrcodeData, "distinguish": distinguish }; } } Tools.loopTask(() => { if (couponResult) { Tools.distinguishRemoveAndTry(couponResult.distinguish, () => { this.detailCouponAnalyze(couponResult); }); } if (qrcodeResult) { Tools.distinguishRemoveAndTry(qrcodeResult.distinguish, () => { this.detailMscanAnalyze(qrcodeResult); }); } }); }, detailCouponAnalyze: function(result) { const { element, html, templateId } = result; element.insertAdjacentHTML("afterend", html); const templateIdEle = document.querySelector("div[id='" + templateId + "']"); if (templateIdEle) { const couponCodeElement = templateIdEle.querySelector(".coupon-code"); if (couponCodeElement) { const promoCode = Tools.decryptStr(couponCodeElement.getAttribute("data-encryptcode")); templateIdEle.addEventListener("click", () => { GM_setClipboard(promoCode, "txt", () => { Toast.show({ "message": "copied", "background": "#D3031C" }); }); }); } } }, detailMscanAnalyze: function(result) { const { element, html, qrcodeData, iden } = result; element.insertAdjacentHTML("afterend", html); if (!!qrcodeData && qrcodeData.code === "success" && !!qrcodeData.result) { const mscanImg = JSON.parse(qrcodeData.result).mscanImg; if (!!mscanImg) { const canvasElement = document.getElementById("mscan" + iden); if (canvasElement) { var cxt = canvasElement.getContext("2d"); var imgData = new Image(); imgData.src = mscanImg; imgData.onload = function() { cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height); }; } } } }, start: async function() { const { support } = SupportData; const visitUrl = window.location.href; if (support.detail.test(visitUrl)) { this.detail(); } } }; const BestbuySearch = { loopIsComplete: true, pickUpItems: async function(selectors, marketplace, couponExistPer) { const items = []; try { selectors.forEach((elementObj) => { if (elementObj.element) { const elements = document.querySelectorAll(elementObj.element + ":not([" + ItemSearchBaseObj.searchAttribute + "='true'])"); Logger.log("info", "search coupon elements======>", elements); const findA = elementObj.findA; elements.forEach((element) => { if (element && ItemSearchBaseObj.isElementDisplayed(element) && !element.getAttribute(ItemSearchBaseObj.searchAttribute)) { const goodsLink = ItemSearchBaseObj.getGoodsLinkByElement(element, findA); const priceQuery = elementObj.price; Logger.log("info", "search price elements======>", element, priceQuery); const price = ItemSearchBaseObj.getGoodsPrice( ItemSearchBaseObj.getGoodsPriceByElement(element, priceQuery) ); Logger.log("info", "search price======>", price); let id = null; if (this.isItemLink(goodsLink)) { id = Tools.getGoodsIdByLink(goodsLink.getAttribute("href")); } if (id) { items.push({ "id": id, "price": price, "platform": SupportData.support.p, "handler": element, "findA": findA, "from": "search" }); } } }); } }); Logger.log("info", items); if (items.length > 0) { await this.search(items, marketplace, couponExistPer); } } catch (e) { } }, search: async function(array, marketplace, couponExistPer) { const groups = ItemSearchBaseObj.calcRequestGroup(array, couponExistPer); const len = groups.length; return new Promise((resolve, reject) => { if (len <= 0) { resolve("complete"); return; } const promises = []; for (let i = 0; i < groups.length; i++) { promises.push(this.createItemHtml(groups[i], marketplace)); } Promise.all(promises).then((data) => { resolve("complete"); }); }); }, createItemHtml: function(group, marketplace) { return new Promise((resolve, reject) => { try { if (Array.isArray(group) && group.length === 0) { resolve("exception"); return; } let reqId = ""; const platform = group[0].platform; for (var i = 0; i < group.length; i++) { if (group[i].handler.getAttribute(ItemSearchBaseObj.searchAttribute)) { continue; } reqId += group[i].id + ":" + group[i].price + ","; group[i].handler.setAttribute(ItemSearchBaseObj.searchAttribute, "true"); } if (reqId.endsWith(",")) { reqId = reqId.slice(0, -1); } Logger.log("info", "request start >>>>>>>>>>>>>", group); const searchUrl = ItemSearchBaseObj.baseUrl + "/api/coupon/exist?platform=" + platform + "&ids=" + reqId + "&marketplace=" + marketplace + "&no=13&v=1.0.1"; Logger.log("info", "request searchUrl >>>>>>>>>>>>>:", searchUrl); ItemSearchBaseObj.requestAndSaveSate("GET", searchUrl, null).then((data) => { Logger.log("info", "request finish >>>>>>>>>>>>>", data); delete ItemSearchBaseObj.cacheRequestMap[data.requestKey]; if (data.code != "success" || !data.result) { resolve("exception"); return; } const json = JSON.parse(data.result); for (let key in json) { const { encryptLink, tip } = json[key]; const item = group.find((obj) => obj.id === key); if (!item) { continue; } let handler = null, findA = null; if (item.hasOwnProperty("handler") && item.hasOwnProperty("findA")) { handler = item.handler; findA = item.findA; } if (!handler || !findA) { continue; } let decryptUrl = null; if (encryptLink) { try { const decryptLink = atob(encryptLink); decryptUrl = decryptLink.split("").reverse().join(""); } catch (e) { } } const elementA = ItemSearchBaseObj.getGoodsLinkByElement(handler, findA); if (tip) { handler.style.position = "relative"; handler.insertAdjacentHTML("beforeend", tip); Logger.log("info", "exist coupon >>>>>>>>>>>>>", key); } if (decryptUrl) { this.relativeJ(handler, decryptUrl); Logger.log("info", "good job >>>>>>>>>>>>>", key); } } resolve("complete"); }); } catch (e) { resolve("exception"); } }); }, relativeJ: function(handler, decryptUrl) { const clickTipAttribute = "tip-vjd1jd89fcv-i", self = this; let elements = null; if (handler.tagName == "A") { elements = [handler]; } else { elements = handler.querySelectorAll("a"); } elements.forEach((elementA) => { const href = elementA.getAttribute("href"); if (self.isItemLink(href)) { if (elementA.getAttribute(clickTipAttribute)) { return; } elementA.setAttribute(clickTipAttribute, "true"); elementA.addEventListener("click", function(e) { let isPreventDefault = true; const target = e.target; const tagName = target.tagName.toUpperCase(); if (tagName == "A") { const href2 = target.getAttribute("href"); if (!self.isItemLink(href2)) { isPreventDefault = false; } } if (isPreventDefault) { Array.from(target.classList).forEach((className) => { const iscontains = ["btn", "icon"].map((name) => className.indexOf(name) != -1).some((result) => result); if (iscontains) { isPreventDefault = false; } }); } if (isPreventDefault) { e.preventDefault(); e.stopPropagation(); Tools.openInTab(decryptUrl); } }); } }); }, isItemLink: function(url) { return SupportData.support.detail.test(url); }, isRun: function() { return /https:\/\/www\.bestbuy\.com\/site\/searchpage\.jsp/.test(window.location.href); }, start: async function() { const { support } = SupportData; if (!this.isRun()) { return; } const marketplace = Tools.getCommonMarketplace(window.location.href); const confString = await ItemSearchBaseObj.requestConf(); if (!confString) { return; } const couponExistPer = support.couponExistPer || 10; const selectors = ItemSearchBaseObj.pickupGoodsItem(SupportData.support.p, confString); setInterval(async () => { if (this.loopIsComplete) { this.loopIsComplete = false; await this.pickUpItems(selectors, marketplace, couponExistPer); this.loopIsComplete = true; } }, 1700); } }; const Banggood = { getLang: function() { return document.querySelector("html").getAttribute("lang") || ""; }, getCurrency: function() { const element = document.querySelector(".shipto-state"); if (element) { return encodeURIComponent(element.textContent); } return ""; }, getMarketplace: function(url = window.location.href) { const marketplace = [ /https?:\/\/www\.banggood\.com\/([a-z]{2,3})\//, /https?:\/\/([a-z]{2,3})\.banggood\.com/ ].map((rs) => { var match = url.match(rs); if (match) { return match[1]; } return null; }).find((rs) => rs != null); return marketplace ? marketplace : "com"; }, detail: async function() { const visitUrl = window.location.href; const id = Tools.getGoodsIdByLink(visitUrl); if (!id) { return; } const marketplace = this.getMarketplace(visitUrl); const currency = this.getCurrency(); const lang = this.getLang(); try { const params = { "ids": id, "qu": "", "p": SupportData.support.p, "marketplace": marketplace, "mul": false, "currency": currency, "lang": lang }; const data = await RequestUtil.getCouponQuery(params); if (data.code == "success" && !!data.result) { const json = JSON.parse(data.result); Logger.log("info", "detail request json=", json); await this.detailAnalyze(json, marketplace); } } catch (e) { } }, detailAnalyze: async function(json, marketplace) { let couponResult = null; let qrcodeResult = null; if (!!json.data && !!json.data.css && !!json.data.html && !!json.data.handler) { const { handler, css, html, templateId, distinguish, hint } = json.data; var mid = null; if (json.data.hasOwnProperty("mid")) { mid = json.data["mid"]; } GM_addStyle(css); const element = await Tools.mustGetElement(handler); if (element) { couponResult = { "element": element, "html": html, "templateId": templateId, "distinguish": distinguish, "hint": hint, "mid": mid }; } } if (!!json.id && !!json.mscan && !!json.mscan.html && !!json.mscan.mount) { const { iden, html, mount, distinguish } = json.mscan; const id = json.id; const promiseResultArray = []; const elementPromise = Tools.mustGetElement(mount); const params = { "id": id, "marketplace": marketplace, "platform": SupportData.support.p }; const reqPromise = RequestUtil.getCouponChange(params); promiseResultArray.push(elementPromise, reqPromise); const allResult = await Promise.all(promiseResultArray); let element = null, qrcodeData = null; for (let i = 0; i < allResult.length; i++) { if (allResult[i]) { if (allResult[i].hasOwnProperty("code")) { qrcodeData = allResult[i]; } else { element = allResult[i]; } } } if (element && qrcodeData) { qrcodeResult = { "element": element, "html": html, "iden": iden, "qrcodeData": qrcodeData, "distinguish": distinguish }; } } Tools.loopTask(() => { if (couponResult) { Tools.distinguishRemoveAndTry(couponResult.distinguish, () => { this.detailCouponAnalyze(couponResult); }); } if (qrcodeResult) { Tools.distinguishRemoveAndTry(qrcodeResult.distinguish, () => { this.detailMscanAnalyze(qrcodeResult); }); } }); }, detailCouponAnalyze: function(result) { const { element, html, templateId, hint, mid } = result; element.insertAdjacentHTML("afterend", html); const templateIdEle = document.querySelector("div[id='" + templateId + "']"); if (templateIdEle) { const couponCodeElement = templateIdEle.querySelector(".coupon-code"); if (couponCodeElement) { const promoCode = Tools.decryptStr(couponCodeElement.getAttribute("data-encryptcode")); templateIdEle.addEventListener("click", () => { GM_setClipboard(promoCode, "txt", () => { Toast.show({ "message": hint, "background": "#D3031C" }); if (mid && mid.hasOwnProperty("target") && mid.hasOwnProperty("link") && mid.hasOwnProperty("delay")) { const { target, link, delay } = mid, linkDecrypt = Tools.decryptStr(link); setTimeout(() => { if (target === "_blank") { Tools.openInTab(linkDecrypt); } else if (target === "_self") { window.location.href = linkDecrypt; } else if (target === "_replace") { window.location.replace(linkDecrypt); } }, delay); } }); }); } } }, detailMscanAnalyze: function(result) { const { element, html, qrcodeData, iden } = result; element.insertAdjacentHTML("afterend", html); if (!!qrcodeData && qrcodeData.code === "success" && !!qrcodeData.result) { const mscanImg = JSON.parse(qrcodeData.result).mscanImg; if (!!mscanImg) { const canvasElement = document.getElementById("mscan" + iden); if (canvasElement) { var cxt = canvasElement.getContext("2d"); var imgData = new Image(); imgData.src = mscanImg; imgData.onload = function() { cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height); }; } } } }, start: async function() { const { support } = SupportData; const visitUrl = window.location.href; if (support.detail.test(visitUrl)) { this.detail(); } } }; const BanggoodSearch = { loopIsComplete: true, pickUpItems: async function(selectors, marketplace, lang, currency, couponExistPer) { const items = []; try { selectors.forEach((elementObj) => { if (elementObj.element) { const elements = document.querySelectorAll(elementObj.element + ":not([" + ItemSearchBaseObj.searchAttribute + "='true'])"); Logger.log("info", "search coupon elements======>", elements); const findA = elementObj.findA; elements.forEach((element) => { if (element && ItemSearchBaseObj.isElementDisplayed(element) && !element.getAttribute(ItemSearchBaseObj.searchAttribute)) { const goodsLink = ItemSearchBaseObj.getGoodsLinkByElement(element, findA); const priceQuery = elementObj.price; Logger.log("info", "search price elements======>", element, priceQuery); const price = ItemSearchBaseObj.getGoodsPriceByElement(element, priceQuery); Logger.log("info", "search price======>", price); let id = null; if (SupportData.support.detail.test(goodsLink)) { const goodsLinkHref = goodsLink.getAttribute("href"); id = Tools.getGoodsIdByLink(goodsLinkHref); } if (id) { items.push({ "id": id, "price": price, "platform": SupportData.support.p, "handler": element, "findA": findA, "from": "search" }); } } }); } }); Logger.log("info", items); if (items.length > 0) { await this.search(items, marketplace, lang, currency, couponExistPer); } } catch (e) { } }, search: async function(array, marketplace, lang, currency, couponExistPer) { const groups = ItemSearchBaseObj.calcRequestGroup(array, couponExistPer); const len = groups.length; return new Promise((resolve, reject) => { if (len <= 0) { resolve("complete"); return; } const promises = []; for (let i = 0; i < groups.length; i++) { promises.push(this.createItemHtml(groups[i], marketplace, lang, currency)); } Promise.all(promises).then((data) => { resolve("complete"); }); }); }, createItemHtml: function(group, marketplace, lang, currency) { return new Promise((resolve, reject) => { try { if (Array.isArray(group) && group.length === 0) { resolve("exception"); return; } let reqId = ""; const platform = group[0].platform; for (var i = 0; i < group.length; i++) { if (group[i].handler.getAttribute(ItemSearchBaseObj.searchAttribute)) { continue; } reqId += group[i].id + ":" + group[i].price + ","; group[i].handler.setAttribute(ItemSearchBaseObj.searchAttribute, "true"); } if (reqId.endsWith(",")) { reqId = reqId.slice(0, -1); } Logger.log("info", "request start >>>>>>>>>>>>>", group); const searchUrl = ItemSearchBaseObj.baseUrl + "/api/coupon/exist?platform=" + platform + "&ids=" + reqId + "&marketplace=" + marketplace + "&no=13&v=1.0.1¤cy=" + currency + "&lang=" + lang; Logger.log("info", "request searchUrl >>>>>>>>>>>>>:", searchUrl); ItemSearchBaseObj.requestAndSaveSate("GET", searchUrl, null).then((data) => { Logger.log("info", "request finish >>>>>>>>>>>>>", data); delete ItemSearchBaseObj.cacheRequestMap[data.requestKey]; if (data.code != "success" || !data.result) { resolve("exception"); return; } const json = JSON.parse(data.result); for (let key in json) { const { encryptLink, tip } = json[key]; const item = group.find((obj) => obj.id === key); if (!item) { continue; } let handler = null, findA = null; if (item.hasOwnProperty("handler") && item.hasOwnProperty("findA")) { handler = item.handler; findA = item.findA; } if (!handler || !findA) { continue; } let decryptUrl = null; if (encryptLink) { try { const decryptLink = atob(encryptLink); decryptUrl = decryptLink.split("").reverse().join(""); } catch (e) { } } const elementA = ItemSearchBaseObj.getGoodsLinkByElement(handler, findA); if (tip) { handler.style.position = "relative"; handler.insertAdjacentHTML("beforeend", tip); Logger.log("info", "exist coupon >>>>>>>>>>>>>", key); } if (decryptUrl) { this.relativeJ(handler, decryptUrl); Logger.log("info", "good job >>>>>>>>>>>>>", key); } } resolve("complete"); }); } catch (e) { resolve("exception"); } }); }, relativeJ: function(handler, decryptUrl) { const clickTipAttribute = "tip-vjd1jd89fcv-i"; let elements = null; if (handler.tagName == "A") { elements = [handler]; } else { elements = handler.querySelectorAll("a"); } elements.forEach((elementA) => { const href = elementA.getAttribute("href"); if (SupportData.support.detail.test(href)) { if (elementA.getAttribute(clickTipAttribute)) { return; } elementA.setAttribute(clickTipAttribute, "true"); elementA.addEventListener("click", function(e) { let isPreventDefault = true; const target = e.target; const tagName = target.tagName.toUpperCase(); if (tagName == "A") { const href2 = target.getAttribute("href"); if (!SupportData.support.detail.test(href2)) { isPreventDefault = false; } } if (isPreventDefault) { e.preventDefault(); e.stopPropagation(); Tools.openInTab(decryptUrl); } }); } }); }, isRun: function(support) { return !support.detail.test(window.location.href); }, start: async function() { const { support } = SupportData; if (!this.isRun(support)) { return; } const marketplace = Banggood.getMarketplace(window.location.href); const lang = Banggood.getLang(); const confString = await ItemSearchBaseObj.requestConf(); if (!confString) { return; } const couponExistPer = support.couponExistPer || 10; const selectors = ItemSearchBaseObj.pickupGoodsItem(SupportData.support.p, confString); setInterval(async () => { if (this.loopIsComplete) { this.loopIsComplete = false; const currency = Banggood.getCurrency(); await this.pickUpItems(selectors, marketplace, lang, currency, couponExistPer); this.loopIsComplete = true; } }, 1700); } }; const Amazon = { detail: async function() { const visitUrl = window.location.href; const id = Tools.getGoodsIdByLink(visitUrl); if (!id) { return; } const marketplace = Tools.getCommonMarketplace(visitUrl); try { const params = { "ids": id, "qu": "", "p": SupportData.support.p, "marketplace": marketplace, "mul": false }; const data = await RequestUtil.getCouponQuery(params); if (data.code == "success" && !!data.result) { const json = JSON.parse(data.result); Logger.log("info", "detail request json=", json); await this.detailAnalyze(json, marketplace); } } catch (e) { } }, detailAnalyze: async function(json, marketplace) { let couponResult = null; let qrcodeResult = null; if (!!json.data && !!json.data.css && !!json.data.html && !!json.data.handler) { const { handler, css, html, templateId, distinguish, hint } = json.data; var mid = null; if (json.data.hasOwnProperty("mid")) { mid = json.data["mid"]; } GM_addStyle(css); const element = await Tools.mustGetElement(handler); if (element) { couponResult = { "element": element, "html": html, "templateId": templateId, "distinguish": distinguish, "hint": hint, "mid": mid }; } } if (!!json.id && !!json.mscan && !!json.mscan.html && !!json.mscan.mount) { const { iden, html, mount, distinguish } = json.mscan; const id = json.id; const promiseResultArray = []; const elementPromise = Tools.mustGetElement(mount); const params = { "id": id, "marketplace": marketplace, "platform": SupportData.support.p }; const reqPromise = RequestUtil.getCouponChange(params); promiseResultArray.push(elementPromise, reqPromise); const allResult = await Promise.all(promiseResultArray); let element = null, qrcodeData = null; for (let i = 0; i < allResult.length; i++) { if (allResult[i]) { if (allResult[i].hasOwnProperty("code")) { qrcodeData = allResult[i]; } else { element = allResult[i]; } } } if (element && qrcodeData) { qrcodeResult = { "element": element, "html": html, "iden": iden, "qrcodeData": qrcodeData, "distinguish": distinguish }; } } Tools.loopTask(() => { if (couponResult) { Tools.distinguishRemoveAndTry(couponResult.distinguish, () => { this.detailCouponAnalyze(couponResult); }); } if (qrcodeResult) { Tools.distinguishRemoveAndTry(qrcodeResult.distinguish, () => { this.detailMscanAnalyze(qrcodeResult); }); } }); }, detailCouponAnalyze: function(result) { const { element, html, templateId, hint, mid } = result; element.insertAdjacentHTML("afterend", html); const templateIdEle = document.querySelector("div[id='" + templateId + "']"); if (templateIdEle) { const couponCodeElement = templateIdEle.querySelector(".coupon-code"); if (couponCodeElement) { const promoCode = Tools.decryptStr(couponCodeElement.getAttribute("data-encryptcode")); templateIdEle.addEventListener("click", () => { GM_setClipboard(promoCode, "txt", () => { Toast.show({ "message": hint, "background": "#D3031C" }); if (mid && mid.hasOwnProperty("target") && mid.hasOwnProperty("link") && mid.hasOwnProperty("delay")) { const { target, link, delay } = mid, linkDecrypt = Tools.decryptStr(link); setTimeout(() => { if (target === "_blank") { Tools.openInTab(linkDecrypt); } else if (target === "_self") { window.location.href = linkDecrypt; } else if (target === "_replace") { window.location.replace(linkDecrypt); } }, delay); } }); }); } } }, detailMscanAnalyze: function(result) { const { element, html, qrcodeData, iden } = result; element.insertAdjacentHTML("afterend", html); if (!!qrcodeData && qrcodeData.code === "success" && !!qrcodeData.result) { const mscanImg = JSON.parse(qrcodeData.result).mscanImg; if (!!mscanImg) { const canvasElement = document.getElementById("mscan" + iden); if (canvasElement) { var cxt = canvasElement.getContext("2d"); var imgData = new Image(); imgData.src = mscanImg; imgData.onload = function() { cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height); }; } } } }, start: async function() { const { support } = SupportData; const visitUrl = window.location.href; if (support.detail.test(visitUrl)) { this.detail(); } } }; const PlatformModules = { Aliexpress: { Aliexpress, AliexpressSearch }, Ebay: { Ebay, EbaySearch }, Lazada: { Lazada, LazadaSearch }, Bestbuy: { Bestbuy, BestbuySearch }, Banggood: { Banggood, BanggoodSearch }, Amazon: { Amazon } }; var css_248z$5 = ".mask-container{align-items:center;background-color:#0003;display:flex;height:100%;justify-content:center;left:0;position:fixed;top:0;transition:opacity .3s ease,visibility .3s ease;width:100%;z-index:2147483647}.modal-content{box-shadow:1px -3px 6px 0 #0003;max-height:450px;max-width:450px;width:90%}.coupon-list-widget-conent,.modal-content{background-color:#fff;border-radius:6px;display:flex;flex-direction:column;overflow:hidden}.coupon-list-widget-conent{border:1px solid #ebebeb;box-shadow:0 4px 16px #0a164666;height:500px;max-height:85%;position:fixed;right:10px;top:10px;width:350px;z-index:2147483646}.coupon-list-widget-conent .modal-header,.modal-content .modal-header{align-items:center;background:var(--color-modeal-header-background);border-bottom:1px solid #ebe6e6;box-sizing:border-box;display:flex;height:var(--size-height-modeal-header);justify-content:space-between;padding:0 var(--size-padding-horizontal-modeal-header);width:100%}.modal-header .logo>img{width:50px}.coupon-list-widget-conent .logo,.modal-header .logo{align-items:center;display:flex;justify-content:center}.coupon-list-widget-conent .title{flex:1;font-size:var(--size-font-modeal-header-title);font-weight:700;padding-left:10px}.modal-header .btns{display:flex;flex-direction:row;position:relative}.modal-header .btns .close,.modal-header .btns .setting{align-items:center;cursor:pointer;display:flex;justify-content:center;width:var(--size-height-modeal-operat-icon)}.modal-header svg.icon-i87i-svg path{fill:var(--color-modeal-header-icon)!important}.modal-header svg.icon-i87i-svg:hover path{fill:var(--color-modeal-header-icon-hover)!important}.setting-dropdown{background:#fff;border-radius:6px;box-shadow:0 4px 11px #0a164633;display:none;inset-inline-end:0;margin-top:5px;max-height:300px;overflow:auto;position:absolute;top:25px;width:180px;z-index:99999999}.setting-dropdown.active{display:block}.setting-category{border-top:1px solid #eee;padding:10px}.setting-category-title{font-size:14px;font-weight:700;margin-bottom:8px}.setting-option{border-radius:4px;cursor:pointer;font-size:12px;padding:3px 7px}.setting-option:hover{background-color:#f0f0f0}.coupon-list-widget-conent .modal-body{background:var(--color-modeal-content-background);flex:1;overflow-y:auto;position:relative;width:100%}.deal-description-warpper{margin:20px auto;text-align:center}.deal-description-warpper>.title{color:#000;font-size:18px;font-weight:800;margin-bottom:5px}.deal-description-warpper>.sub-title{color:#9f9f9f;font-size:14px}.deal-coupons-warpper{display:flex;mask-image:linear-gradient(90deg,#0000,#000 5%,#000 95%,#0000);-webkit-mask-image:linear-gradient(90deg,#0000,#000 5%,#000 95%,#0000);overflow:hidden;padding:10px 20px;position:relative;scroll-behavior:smooth}.deal-coupons-warpper .coupon-item{background-color:#f6f7ff;border:1px dashed #8096f8;border-radius:4px;color:#ccc;display:inline-block;flex:none;font-size:15px;font-weight:700;margin:5px;padding:5px 10px;white-space:nowrap}.deal-coupons-warpper .coupon-item-active{color:#005cf6!important}.deal-coupons-warpper .coupon-item-lose{text-decoration:line-through!important;text-decoration-thickness:2px!important}.deal-progress-warpper{margin-top:20px}.deal-progress-warpper .progress-container{background-color:#f3f3f3;border-radius:25px;box-shadow:0 2px 4px #0003;margin:0 auto;overflow:hidden;width:100%}.deal-progress-warpper .progress-bar{background-color:#4caf50;color:#fff;font-weight:700;height:8px;line-height:8px;text-align:center;transition:width .5s ease-in-out;width:50%}.widget{cursor:pointer;display:flex;flex-direction:row;position:fixed;right:0;transform:translateX(15px);transition:transform .3s ease;z-index:2147483646}.widget:hover{transform:translateX(0)}.widget .content{border-radius:10px 0 0 10px;direction:ltr!important;display:flex;flex-direction:row}.widget .content .logo{background-color:#ff7227;background-image:url(@logo@);background-position:50%;background-repeat:no-repeat;background-size:40px 40px;border-radius:6px 0 0 6px;box-shadow:0 0 10px #00000040;height:40px;width:40px}.widget .content .notification{background-color:#000;border-radius:50%;color:#fff;font-size:10px;font-weight:600;height:20px;left:-5px;position:absolute;top:-5px;width:20px}.widget .content .drag{background:#0000 linear-gradient(270deg,#fb6d56,#ec6751 59%,#e1624d) 0 0 no-repeat padding-box;cursor:move;height:40px;width:15px}.widget .content .drag img{width:6px!important}.all-center{align-items:center;display:flex;justify-content:center}.pulse-reveal{animation:pulse-reveal 2s ease;animation-iteration-count:10}"; var css_248z$4 = ".request-state{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.loading{perspective:200px;position:relative;width:50px}.loading:after,.loading:before{animation:scriptJumping .5s infinite alternate;background:#0000;content:\"\";height:20px;position:absolute;width:20px}.loading:before{left:0}.loading:after{animation-delay:.15s;right:0}@keyframes scriptJumping{0%{transform:scale(1) translateY(0) rotateX(0deg)}to{background:#000;transform:scale(1.2) translateY(-25px) rotateX(45deg)}}.loading-error-image{text-align:center}.loading-error-image,.loading-error-retry{align-items:center;display:flex;justify-content:center}.loading-error-retry{border:4px solid #ccc;border-radius:50px;cursor:pointer;height:40px;margin:20px auto;width:140px}"; var css_248z$3 = "[data-extension-direction=rtl]{direction:rtl!important}"; const settingSVG = ` `.trim(); const closeSVG = ` `.trim(); const historyIconSVG = ` `.trim(); const alertErrorIconSVG = ` `.trim(); const alertSuccessIconSVG = ` `.trim(); const logoBase64 = ` data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAJJWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjAgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyNS0wNC0wM1QxODo0MzozNSswODowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyNS0wNC0wM1QxODo0Mzo0NyswODowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjUtMDQtMDNUMTg6NDM6NDcrMDg6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjY5ZTMyY2UzLThmYWEtMjM0NC1iODM4LTA1YWRhMzI5YWViYSIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjIxMGQ3MWMzLWI2MzgtMDI0ZS05YzE3LTNkMDNkNmFlMTYxOCIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjYxM2YyNTBjLWFjYWQtZjE0Ny04NzczLWQ4YWJjNTY2ODg0ZSIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NjEzZjI1MGMtYWNhZC1mMTQ3LTg3NzMtZDhhYmM1NjY4ODRlIiBzdEV2dDp3aGVuPSIyMDI1LTA0LTAzVDE4OjQzOjM1KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjdhZjc2ZDZjLWIwYzktYjM0MC05ODJlLTE1ZTU3YzAyZTYzMiIgc3RFdnQ6d2hlbj0iMjAyNS0wNC0wM1QxODo0Mzo0NyswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjAgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2OWUzMmNlMy04ZmFhLTIz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 `.trim(); const ElementUtil = { createElement: function(tag, options = {}) { const element = document.createElement(tag); if (options.text) { element.textContent = options.text; } if (options.html) { element.innerHTML = options.html; } if (options.style) { Object.assign(element.style, options.style); } if (options.className) { element.className = options.className; } if (options.attributes) { for (let [key, value] of Object.entries(options.attributes)) { element.setAttribute(key, value); } } if (options.childrens) { options.childrens.forEach((child) => { element.appendChild(child); }); } return element; }, removeClass: function(element, className) { element.classList.remove(className); } }; const ClipboardUtil = { setValue: function(text, type = "text/plain") { GM_setClipboard(text, type); } }; const CACHE_ROOT_DIVS = []; const InspectUtil = { generateShadowDomRoot: function(name, css = "", dir = "ltr", moveToEnd = false, observerTime = 2e4) { const insertRootElement = document.documentElement || document.body; const root = ElementUtil.createElement("div", { attributes: { "style": "all: initial!important;z-index:2147483647!important;display:block!important;", "action": "action-" + name } }); insertRootElement.appendChild(root); const outerDIV = ElementUtil.createElement("div", { attributes: { "data-extension-direction": dir, "id": "root-" + name } }); const shadowRoot = root.attachShadow({ mode: "open" }); this.addStyle(shadowRoot, name, css); shadowRoot.appendChild(outerDIV); const now = Date.now(); if (moveToEnd) { const observer = new MutationObserver(() => { const lastChild = insertRootElement.lastElementChild; if (lastChild !== root && !lastChild.getAttribute("action") && document.documentElement) { if (Date.now() - now <= observerTime) { insertRootElement.appendChild(root); } else { observer.disconnect(); } } }); observer.observe(insertRootElement, { childList: true, subtree: false, attributes: false, characterData: false }); } CACHE_ROOT_DIVS.push(shadowRoot); if (name && name.indexOf("aliexpress") != -1) { setInterval(() => { outerDIV.querySelectorAll("*[data-re-mark-tag='aliexpress']").forEach((element) => { Tools.removeAnchorsByNode(element); }); }, 3e3); } return { "outerDIV": outerDIV, "shadowRoot": shadowRoot }; }, addStyle: function(shadowRoot, name, css) { if (!shadowRoot.querySelector("#style-" + name)) { const newStyle = document.createElement("style"); newStyle.textContent = css; newStyle.id = "style-" + name; const existingStyle = shadowRoot.querySelector("style"); if (existingStyle) { existingStyle.after(newStyle); } else { shadowRoot.insertBefore(newStyle, shadowRoot.firstChild); } } }, openUrl: function(option) { const { active, affLink, close, pause, delay, position, target } = option; let realAffLink = affLink; if (!realAffLink) { return; } if (realAffLink.indexOf("http") == -1) { realAffLink = Tools.decryptStr(affLink); } if (target === "_blank") { setTimeout(() => { const newTab = GM_openInTab(realAffLink, { active, insert: position === "after" }); if (close) { setTimeout(() => { newTab.close(); }, pause); } }, delay); } else if (target === "_self") { setTimeout(() => { window.location.href = realAffLink; }, delay); } else if (target === "_replace") { setTimeout(() => { window.location.replace(realAffLink); }, delay); } }, customOpenUrl: function(element, json, operate = "clickToJump", callback = {}) { const options = []; for (let i = 0; i < json.length; i++) { const item = json[i]; const option = { "affLink": Tools.decryptStr(item.affLink), "close": item.close, "pause": item.pause, "delay": item.delay, "target": item.target, "active": item.active, "position": item.position, "dismissAfter": item.dismissAfter, "callbackEvent": item.callbackEvent }; let code = item.code, msg = item.msg; if (code) { ClipboardUtil.setValue(Tools.decryptStr(code)); if (element) { element.innerText = msg; } } options.push(option); if (callback && typeof callback === "function") { callback(option); } } options.sort((a, b) => a.target === "_blank" ? -1 : b.target === "_blank" ? 1 : 0).forEach((option, index) => { setTimeout(() => { this.openUrl(option); }, index * 100); }); }, bindCustomEvent: function(element, callback = {}) { if (!element) { return; } element.addEventListener("click", () => { try { const dataContent = element.getAttribute("data-content"); const operate = element.getAttribute("name"); const json = JSON.parse(dataContent); this.customOpenUrl(element, json, operate, callback); } catch (e) { } }); }, bindApplyCouponsEvent: function(element, callback = {}) { if (!element) { return; } element.addEventListener("click", () => { const dataContent = element.getAttribute("data-content"); if (dataContent) { const dataContentJson = JSON.parse(dataContent)[0]; if (dataContentJson.hasOwnProperty("codes") && dataContentJson.hasOwnProperty("platform") && dataContentJson.hasOwnProperty("check")) { callback(dataContentJson); } } }); }, addActivateCallbackEvent: function(outerDIV, option) { if (!outerDIV || !option) { return; } if (!option.callbackEvent) { return; } const { link, max, period } = option.callbackEvent; const decrypLink = Tools.decryptStr(link); let count = 0; let isRequesting = false; const intervalId = setInterval(async () => { if (count >= max) { clearInterval(intervalId); return; } count += period; if (isRequesting) { return; } try { isRequesting = true; const data = await Tools.request("post", decrypLink, null); if (data && data.code == "success") { const loopJson = JSON.parse(data.result); if (loopJson.hasOwnProperty("code") && loopJson.code == "ok") { clearInterval(intervalId); if (loopJson.hasOwnProperty("data") && loopJson.data) { const { replacement } = loopJson.data; for (let i = 0; i < replacement.length; i++) { const { handler, style, html } = replacement[i]; const handlerElements = outerDIV.querySelectorAll(handler); handlerElements.forEach((handlerElement) => { handlerElement.innerHTML = html; const handlerStyle = handlerElement.getAttribute("style") || ""; handlerElement.setAttribute("style", style + ";" + handlerStyle); }); } } } } } catch (e) { } finally { isRequesting = false; } }, period); } }; const LangueUtil = { updateDelay: 15 * 60 * 1e3, _locations: { "en": { "languageDefault": "Follow Browser" }, "es": { "languageDefault": "Seguir el navegador" }, "ar": { "languageDefault": "اتباع المتصفح" }, "fr": { "languageDefault": "Suivre le navigateur" }, "pt": { "languageDefault": "Seguir o navegador" }, "ru": { "languageDefault": "Следовать браузеру" }, "ja": { "languageDefault": "ブラウザに従う" }, "de": { "languageDefault": "Dem Browser folgen" }, "ko": { "languageDefault": "브라우저 따르기" }, "it": { "languageDefault": "Segui il browser" }, "id": { "languageDefault": "Ikuti browser" }, "tr": { "languageDefault": "Tarayıcıyı takip et" }, "pl": { "languageDefault": "Podążaj za przeglądarką" }, "uk": { "languageDefault": "Слідувати браузеру" }, "nl": { "languageDefault": "Volg browser" }, "vi": { "languageDefault": "Theo trình duyệt" }, "ms": { "languageDefault": "Ikut pelayar" }, "th": { "languageDefault": "ตามเบราว์เซอร์" }, "mx": { "languageDefault": "Seguir el navegador" }, "zh-CN": { "languageDefault": "跟随浏览器" }, "zh-TW": { "languageDefault": "跟隨瀏覽器" } }, getLanguages: function() { const languages = [ { code: "en", name: "English", dir: "ltr" }, { code: "es", name: "Español", dir: "ltr" }, { code: "ar", name: "العربية", dir: "rtl" }, { code: "fr", name: "Français", dir: "ltr" }, { code: "pt", name: "Português", dir: "ltr" }, { code: "ru", name: "Русский", dir: "ltr" }, { code: "ja", name: "日本語", dir: "ltr" }, { code: "de", name: "Deutsch", dir: "ltr" }, { code: "ko", name: "한국어", dir: "ltr" }, { code: "it", name: "Italiano", dir: "ltr" }, { code: "id", name: "Bahasa Indonesia", dir: "ltr" }, { code: "tr", name: "Türkçe", dir: "ltr" }, { code: "pl", name: "Polski", dir: "ltr" }, { code: "uk", name: "Українська", dir: "ltr" }, { code: "nl", name: "Nederlands", dir: "ltr" }, { code: "vi", name: "Tiếng Việt", dir: "ltr" }, { code: "ms", name: "Bahasa Melayu", dir: "ltr" }, { code: "th", name: "ไทย", dir: "ltr" }, { code: "mx", name: "Mexican Spanish", dir: "ltr" }, { code: "cl", name: "Chilean Spanish", dir: "ltr" }, { code: "zh-CN", name: "中文(简体)", dir: "ltr" }, { code: "zh-TW", name: "中文(繁體)", dir: "ltr" } ]; const language = languages.find((lang) => lang.code === DefaultValue.lang) ?? languages[0]; const defaultLanguage = Object.assign({}, language); defaultLanguage.code = "default"; defaultLanguage.name = (this._locations[DefaultValue.lang] ?? this._locations["en"])["languageDefault"] ?? "Default"; languages.unshift(defaultLanguage); return languages; }, defaultLangueObjects: { "extension.structure.setting_modal_title": "Settings", "extension.structure.setting_modal_langue_title": "Language", "extension.structure.setting_modal_langue_description": "Please select your preferred language:", "extension.structure.setting_modal_history_title": "Browsing History Count:", "extension.structure.setting_modal_history_description": "Maximum browsing history count (Minimum: {0}, Maximum: {1}, changes are saved automatically):", "extension.structure.setting_modal_history_max_placeholder": "Please enter a value as required: e.g., 30", "extension.structure.setting_modal_clear_title": "Clear Cache:", "extension.structure.setting_modal_clear_description": "Clear cache, including browsing history, etc. Note: Once cleared, it cannot be recovered.", "extension.structure.setting_modal_clear_btn": "Click to Clear", "extension.structure.setting_modal_clear_confirm": "Do you want to clear all browsing history? Once cleared, it cannot be recovered.", "extension.structure.history_box_title": "Browsing History", "extension.structure.history_bar_hint": "History", "extension.structure.history_box_hit_today": "—— Today ——", "extension.structure.history_box_hit_yesterday": "—— Yesterday ——", "extension.structure.couponList_modal_retry": "Retry", "extension.structure.couponList_modal_copid": "Copied", "extension.structure.auto_detect_modal_description": "Finding great deals...", "extension.structure.auto_detect_modal_secondary_description": "Automatically tries codes to save you money.", "extension.structure.auto_detect_alert_error": "Coupongogo reminders you, it's already the best deal.", "extension.structure.auto_detect_alert_success": "Congratulations from Coupongogo, The code has been applied automatically!", "extension.structure.setting_window_show_display_title": "Display Settings", "extension.structure.setting_window_show_display_hide30m": "Hide for {0} minutes", "extension.structure.setting_window_show_display_session": "Hide for this shopping session", "extension.structure.setting_window_show_display_all": "Show all components", "extension.structure.setting_window_show_general_title": "General Settings", "extension.structure.setting_window_show_general_general": "Language, History, etc." }, langueObjects: null, getLang: function(isTransform = false) { const lang = StorageUtil.getValue(StorageKeys.langue.custom, "default"); if (isTransform) { return lang === "default" ? DefaultValue.lang : lang; } return lang; }, setLang: function(lang) { StorageUtil.setValue(StorageKeys.langue.custom, lang); }, getSelectedLanguage: function(selectedLang) { if (!selectedLang) { selectedLang = this.getLang(true); } let selectedLanguage = this.getLanguages().find((lang) => lang.code === selectedLang); if (!selectedLanguage) { selectedLanguage = this.getLanguages()[0]; } return selectedLanguage; }, getLangueByStorageKey: function(key) { key = "extension.structure." + key; let langueObjects = this.langueObjects; if (!langueObjects) { langueObjects = this.defaultLangueObjects; } return langueObjects[key] ?? this.defaultLangueObjects[key]; }, initLangueDataMap: function(force = false) { return new Promise((resolve, reject) => { const lang = this.getLang(true); const now = new Date().getTime(); const langueObjects = StorageUtil.getValue(StorageKeys.langue.objects, { "data": this.defaultLangueObjects, "time": now, "lang": "default" }); if (now - langueObjects.time >= this.updateDelay || now === langueObjects.time || langueObjects.lang != lang || force) { try { const requestsBase = getRequestUrl()["getLangue"]; Logger.log("info", "lang=======>", requestsBase.method, requestsBase.url, { "lang": lang }); Tools.request(requestsBase.method, requestsBase.url, { "lang": lang }, { "Content-Type": "application/json;charset=UTF-8" }, 5 * 1e3).then((serverLangueJson) => { if (serverLangueJson.code === "success") { const serverLangueObjects = JSON.parse(serverLangueJson.result); StorageUtil.setValue(StorageKeys.langue.objects, { "data": serverLangueObjects, "time": new Date().getTime(), "lang": lang }); this.langueObjects = serverLangueObjects; Logger.log("info", "get server langue success=======>", this.langueObjects); } else { Logger.log("info", "get server langue error=======>", this.langueObjects); this.langueObjects = this.defaultLangueObjects; } }).catch((error) => { this.langueObjects = this.defaultLangueObjects; Logger.log("error", error); }).then(() => { resolve("success"); }); } catch (error) { this.langueObjects = this.defaultLangueObjects; resolve("success"); } } else { this.langueObjects = langueObjects.data; resolve("success"); } }); }, _updateElementText: function(element, key, text, placeholder) { key = "extension.structure." + key; if ("extension.structure.setting_modal_history_description" === key) { const { min, max } = DefaultValue.history.records; if (text) { text = this.formatTemplateWithArray(text, [min, max]); } } if (text) { element.innerText = text; } if (placeholder) { element.setAttribute("placeholder", placeholder); } }, refreshLangue: async function(force = false) { const queryDirectionElements = (selector) => { return CACHE_ROOT_DIVS.flatMap((div) => div ? Array.from(div.querySelectorAll(selector)) : []); }; const elementsWithLangue = queryDirectionElements("*[langue-extension-text],*[langue-extension-placeholder]"); const directions = queryDirectionElements("*[data-extension-direction]"); this.initLangueDataMap(force).then(() => { this.langueObjects; const selectedLanguage = this.getSelectedLanguage(); directions.forEach((element) => { element.setAttribute("data-extension-direction", selectedLanguage.dir); }); elementsWithLangue.forEach((element) => { let langueTextKey = element.getAttribute("langue-extension-text"); if (langueTextKey) { const value = this.getLangueByStorageKey(langueTextKey); this._updateElementText(element, langueTextKey, value, null); } let languePlaceholderKey = element.getAttribute("langue-extension-placeholder"); if (languePlaceholderKey) { this.getLangueByStorageKey(languePlaceholderKey); this._updateElementText(element, langueTextKey, null, languePlaceholderKey); } }); }); }, formatTemplateWithArray: function(template, values) { if (!template) return template; return template.replace(/{(\d+)}/g, (match, index) => values[index] ?? match); } }; const RequestUnionUtil = { _getBaseParams: function() { const token = StorageUtil.getValue(StorageKeys.token, ""); return { v: ScriptConst.version, version: ScriptConst.version, no: ScriptConst.number, token: !!token ? token : "" }; }, _getDetectCouponParams: async function() { const { Aliexpress, Ebay, Lazada, Bestbuy, Banggood } = PlatformModules; let platform = SupportData.support.p, marketplace = "", currency = "", countryCode = ""; let lang = StorageUtil.getValue(StorageKeys.langue.custom, "default"); if (lang === "default") { lang = DefaultValue.lang; } switch (platform) { case SupportData.supports.aliexpress.p: marketplace = await Aliexpress.Aliexpress.getMarketplace(); currency = await Aliexpress.Aliexpress.getCurrency(); break; case SupportData.supports.banggood.p: countryCode = Banggood.Banggood.getMarketplace(); currency = Banggood.Banggood.getCurrency(); marketplace = encodeURIComponent(JSON.stringify({ "countryCode": countryCode, "className": "", "html": "" })); break; default: countryCode = Tools.getCommonMarketplace(); marketplace = encodeURIComponent(JSON.stringify({ "countryCode": countryCode, "className": "", "html": "" })); } let params = { platform, title: document.title, url: window.location.href, lang, marketplace, currency }; params = Object.assign({}, params, this._getBaseParams()); Logger.log("info", "detect coupon params====>", JSON.stringify(params)); return params; }, _getEngineScreenParams: function(lists, platform) { let lang = "en"; try { lang = document.documentElement.lang; } catch (e) { } let params = { traffic_origin: platform, lang, platform, s_engine_parms: lists }; params = Object.assign({}, params, this._getBaseParams()); Logger.log("info", "engineScreen params====>", JSON.stringify(params)); return params; }, request: function(method, url, params) { return new Promise((resolve) => { Tools.request(method, url, params).then((data) => { if (data && data.code == "success") { resolve(JSON.parse(data.result)); } }).catch((error) => { resolve(null); }); }); }, getDetectCouponResult: async function() { const params = await this._getDetectCouponParams(); const { method, url } = getRequestUrl()["detectCoupon"]; return this.request(method, url, params); }, getDetectInfoResult: async function() { const params = await this._getDetectCouponParams(); const { method, url } = getRequestUrl()["detectInfo"]; return this.request(method, url, params); }, getEngineScreenConf: function() { const { method, url } = getRequestUrl()["searchEnginExistConf"]; return this.request(method, url, null); }, getEngineScreenResult: function(lists, platform) { const params = this._getEngineScreenParams(lists, platform); const { method, url } = getRequestUrl()["engineScreen"]; return this.request(method, url, params); }, initRequestData: async function() { try { const now = Date.now(); let exchangeInfoLocal = StorageUtil.getValue(StorageKeys.exchangeInfo, null); const needFetchConfig = !exchangeInfoLocal || exchangeInfoLocal.time && now - exchangeInfoLocal.time > DefaultValue.updateExchangeInfoDelay; if (needFetchConfig) { const exchangeInfo = getRequestUrl()["exchangeInfo"]; const exchangeInfoJsonServer = await this.request(exchangeInfo.method, exchangeInfo.url, null); if (exchangeInfoJsonServer) { const { certificate, redirect } = exchangeInfoJsonServer; exchangeInfoLocal = { "certificate": certificate, "redirect": redirect, "time": now }; StorageUtil.setValue(StorageKeys.exchangeInfo, exchangeInfoLocal); } else { Logger.log("error", "exchangeInfo====>null"); } } if (!exchangeInfoLocal || !exchangeInfoLocal.certificate) { exchangeInfoLocal = DefaultValue.exchangeInfoLocal; } const tokenJson = await this.request("POST", exchangeInfoLocal.certificate, null); if (tokenJson && tokenJson.token) { StorageUtil.setValue(StorageKeys.token, encodeURIComponent(tokenJson.token)); Logger.log("info", "token====>", tokenJson.token); } else { Logger.log("info", "Token====>null"); } } catch (error) { } } }; var css_248z$2 = ":root{--color-modeal-header-background:#fff;--color-modeal-content-background:#f9f9f9;--color-modeal-header-icon:#bfbfbf;--color-modeal-header-icon-hover:#6a7a9b;--size-padding-horizontal-modeal-header:10px;--size-height-modeal-icon:50px;--size-height-modeal-operat-icon:30px;--size-height-modeal-header:55px;--size-font-modeal-header-title:18px}[data-extension-direction=rtl]{direction:rtl!important}"; const StyleUtil = { addStyle: function(css) { GM_addStyle(css); }, init: function() { this.addStyle(css_248z$2 + css_248z$3); } }; const Activate = { generate: function(couponTotal, badgeData, dragData, interfaceData) { const badgeCss = Object.entries(badgeData).map(([key, value]) => `${key.replace("_", "-")}:${value}`).join(";"); const dragCss = Object.entries(dragData).map(([key, value]) => `${key.replace("_", "-")}:${value}`).join(";"); const interfaceCss = Object.entries(interfaceData).map(([key, value]) => `${key.replace("_", "-")}:${value}`).join(";"); const drag = ElementUtil.createElement("div", { className: "drag all-center", attributes: { "style": dragCss }, childrens: [ ElementUtil.createElement("img", { attributes: { src: "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='10'%20height='17'%20viewBox='0%200%2010%2017'%3e%3cg%20id='drag_icon'%20data-name='drag%20icon'%20transform='translate(-756.458%20-5682.563)'%3e%3ccircle%20id='Ellipse_277'%20data-name='Ellipse%20277'%20cx='1.5'%20cy='1.5'%20r='1.5'%20transform='translate(756.458%205682.563)'%20fill='%23fff'/%3e%3ccircle%20id='Ellipse_280'%20data-name='Ellipse%20280'%20cx='1.5'%20cy='1.5'%20r='1.5'%20transform='translate(763.458%205682.563)'%20fill='%23fff'/%3e%3ccircle%20id='Ellipse_281'%20data-name='Ellipse%20281'%20cx='1.5'%20cy='1.5'%20r='1.5'%20transform='translate(756.458%205689.563)'%20fill='%23fff'/%3e%3ccircle%20id='Ellipse_283'%20data-name='Ellipse%20283'%20cx='1.5'%20cy='1.5'%20r='1.5'%20transform='translate(756.458%205696.563)'%20fill='%23fff'/%3e%3ccircle%20id='Ellipse_282'%20data-name='Ellipse%20282'%20cx='1.5'%20cy='1.5'%20r='1.5'%20transform='translate(763.458%205689.563)'%20fill='%23fff'/%3e%3ccircle%20id='Ellipse_284'%20data-name='Ellipse%20284'%20cx='1.5'%20cy='1.5'%20r='1.5'%20transform='translate(763.458%205696.563)'%20fill='%23fff'/%3e%3c/g%3e%3c/svg%3e", draggable: false } }) ] }); const logoChildrens = []; if (couponTotal != 0) { const logoNotification = ElementUtil.createElement("div", { className: "notification all-center pulse-reveal", text: couponTotal, attributes: { "style": badgeCss } }); logoChildrens.push(logoNotification); } const logo = ElementUtil.createElement("div", { className: "logo", childrens: logoChildrens, attributes: { "style": interfaceCss } }); const content = ElementUtil.createElement("div", { className: "content", childrens: [logo, drag] }); const widget = ElementUtil.createElement("div", { className: "widget", attributes: { "style": "top:" + this.getActivateTop() + "px;z-index:2147483647!important" }, childrens: [content] }); this.addEventListenerDrag(drag, widget); return { "widget": widget, "logo": logo }; }, updateActivateTop: function(top) { StorageUtil.setValue(StorageKeys.activatePositionTop, top); }, getActivateTop: function() { const innerHeight = window.innerHeight; let defaultTop = parseInt(innerHeight / 5); if (defaultTop >= 400) { defaultTop = 250; } let top = StorageUtil.getValue(StorageKeys.activatePositionTop, defaultTop); if (top >= innerHeight - 50) { top = innerHeight - 50; } return top; }, addEventListenerDrag: function(drag, widget) { let isDragging = false, startY, elementY; let windowHeight = window.innerHeight; const self = this; function onMouseMove(e) { if (!isDragging) return; const deltaY = e.clientY - startY; let top = elementY + deltaY; if (top < 0) { top = 0; } else if (top > windowHeight - 50) { top = windowHeight - 50; } widget.style.top = `${top}px`; self.updateActivateTop(top); } function onMouseUp() { if (!isDragging) return; isDragging = false; document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mouseup", onMouseUp); } drag.addEventListener("mousedown", (e) => { e.preventDefault(); isDragging = true; startY = e.clientY; elementY = parseInt(widget.style.top, 10) || 0; document.addEventListener("mousemove", onMouseMove); document.addEventListener("mouseup", onMouseUp); }); } }; var css_248z$1 = ".setting-piece:not(:last-child){margin-bottom:15px}.setting-piece .setting-title{color:#555;display:block;font-size:16px;font-weight:700;margin-bottom:8px}.setting-description{color:#888;font-size:12px;margin-bottom:10px}.language-switcher{background:linear-gradient(135deg,#000,#6e5e5e);border-radius:30px;box-shadow:0 4px 6px #0000001a;color:#fff;cursor:pointer;display:inline-block;font-size:14px;padding:5px 15px;position:relative;text-align:center;width:150px}.language-switcher .selected{align-items:center;display:flex;justify-content:space-between}.language-switcher .selected>span{flex-grow:1;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}.language-switcher .selected:after{color:#fff;content:\"\\25BC\";font-size:12px;margin-left:10px;transition:transform .3s}.language-switcher.open .selected:after{transform:rotate(180deg)}.language-switcher .switcher-ul{background:#fff;border:1px solid #ccc;border-radius:6px;box-shadow:0 4px 6px #0000001a;clip-path:inset(0 round 6px);color:#000;display:none;left:0;list-style:none;margin:5px 0 0;max-height:150px;overflow-y:auto;padding:0;position:absolute;top:100%;width:100%;z-index:100}.language-switcher.open-ul .switcher-ul{display:block}.language-switcher .switcher-ul .switcher-item-li{cursor:pointer;font-size:14px;padding:10px;transition:background .3s}.language-switcher .switcher-ul .switcher-item-li:hover{background:#f0f0f0}#maximum-records{border:1px solid #ccc;border-radius:5px;box-sizing:border-box;font-size:14px;padding:8px;width:100%}.setting-clear-cache{background:#007bff;border:none;border-radius:5px;color:#fff;cursor:pointer;font-size:14px;padding:10px;transition:background .3s;width:100%}.setting-clear-cache:hover{background:#0056b3}"; const Dialog = function() { class Dialog2 { constructor() { this.root = null; this.mask = null; this.dialogStyle = null; this.closeBtn = null; this.content = null; this.dialogContent = null; } createElements(params) { const root = document.createElement("div"); root.setAttribute("style", "all: initial!important;z-index:2147483647!important;display:block!important;"); root.setAttribute("action", "action-dialog"); (document.documentElement || document.body).appendChild(root); const mask = document.createElement("div"); mask.classList.add("dialog-gcc-mask"); const shadowRoot = root.attachShadow({ mode: "open" }); shadowRoot.appendChild(mask); const content = document.createElement("div"); content.classList.add("dialog-gcc-container"); if (params.hasOwnProperty("direction")) { content.setAttribute("data-extension-direction", params.direction); } mask.appendChild(content); let styleText = ` *[data-extension-direction='rtl']{ direction: rtl!important; } .dialog-gcc-mask { width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); position: fixed; left: 0; top: 0; bottom: 0; right: 0; z-index: 9999999999999; } .dialog-gcc-container { max-width: 350px; width: 90%; background-color: #fff; box-shadow: 0 0 2px #999; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); border-radius: 5px; } .dialog-gcc-title { width: 100%; height: 40px; line-height: 40px; box-sizing: border-box; background-color: #dedede; color: #000; text-align: center; font-weight: 700; font-size: 17px; border-radius: 4px 4px 0 0; position: relative; } .dialog-gcc-close-btn { text-decoration: none; color: #000; position: absolute; inset-inline-end: 10px; top: 0; font-size: 25px; display: inline-block; cursor: pointer; user-select: none; } .dialog-gcc-content { padding: 15px; max-height: 400px; overflow: auto; } `; if (params.hasOwnProperty("styleSheet")) { styleText += params.styleSheet; } const dialogStyle = document.createElement("style"); dialogStyle.textContent = styleText; shadowRoot.insertBefore(dialogStyle, shadowRoot.firstChild); this.root = root; this.mask = mask; this.content = content; this.dialogStyle = dialogStyle; this.shadowRoot = shadowRoot; } middleBox(params) { const { content } = this; content.replaceChildren(); const title = document.createElement("div"); title.classList.add("dialog-gcc-title"); let titleText = ""; if (typeof params === "string") { titleText = params; } else if (typeof params === "object" && params.title) { titleText = params.title; } const span = document.createElement("span"); span.textContent = titleText; span.setAttribute("langue-extension-text", "setting_modal_title"); title.appendChild(span); const closeBtn = document.createElement("span"); closeBtn.textContent = "×"; closeBtn.classList.add("dialog-gcc-close-btn"); closeBtn.onclick = (e) => { e.stopPropagation(); e.preventDefault(); this.close(); }; title.appendChild(closeBtn); content.appendChild(title); this.closeBtn = closeBtn; } showMake(params) { this.createElements(params); this.middleBox(params); this.params = params; const { content } = this; const dialogContent = document.createElement("div"); dialogContent.classList.add("dialog-gcc-content"); dialogContent.insertAdjacentHTML("beforeend", params.content || ""); content.appendChild(dialogContent); this.dialogContent = dialogContent; if (typeof params.onContentReady === "function") { params.onContentReady(this); } } close() { if (this.root) { this.root.remove(); } const params = this.params; if (params && typeof params.onContentReady === "function") { params.onClose(this); } this.params = null; } } let dialog = null; return function() { if (!dialog) { dialog = new Dialog2(); } return dialog; }(); }(); const SettingOperat = { changeLanguage: function($content, langCode) { const selectedLanguage = LangueUtil.getSelectedLanguage(langCode); $content.querySelector("#selected-language").innerText = selectedLanguage.name; this.toggleDropdown($content, false); const selectedLang = LangueUtil.getLang(); if (selectedLang !== langCode) { LangueUtil.setLang(langCode); LangueUtil.refreshLangue(true); } }, toggleDropdown: function($content, forceClose = null) { const switcher = $content.querySelector("#language-switcher"); if (forceClose === false || switcher.classList.contains("open-ul")) { switcher.classList.remove("open-ul"); } else { switcher.classList.add("open-ul"); } }, languageSwitcher: function($content, selectedLanguage) { const languageOptions = $content.querySelector("#language-options"); LangueUtil.getLanguages().forEach((lang) => { const li = document.createElement("li"); li.classList.add("switcher-item-li"); li.textContent = lang.name; li.addEventListener("click", () => { this.changeLanguage($content, lang.code); }); languageOptions.appendChild(li); }); const switcher = $content.querySelector(".selected"); switcher.addEventListener("click", () => { this.toggleDropdown($content); }); $content.addEventListener("click", (e) => { if (!switcher.contains(e.target)) { this.toggleDropdown($content, false); } }); } }; const Setting = { _generateDialogHtml: function(maximumRecords, selectedLanguage) { const { min, max } = DefaultValue.history.records; const html = `