[🔥]!!网购小助手,不花冤枉钱:自动查询淘宝、天猫、天猫国际、京东、京东国际、唯品会等隐藏的大额优惠券,有无优惠券一目了然,持续维护更新,请放心使用!

网购小助手功能有:🔥1、浏览商品时脚本会自动查询商品是否有隐藏的优惠券,支持:京东、淘宝、天猫、天猫超市、天猫国际、京东国际、京东图书、京东大药房、阿里大药房、唯品会等;🔥2、商品二维码生成,手机可快捷访问该商品;🔥3、浏览记录标注,避免反复浏览相同商品(本地存储,可手动清空,快捷键shift+c清空);🔥4、PC网页优化,让使用更加舒适;代码全部采用低侵入提示,脚本长期维护更新~

// ==UserScript==
// @name              [🔥]!!网购小助手,不花冤枉钱:自动查询淘宝、天猫、天猫国际、京东、京东国际、唯品会等隐藏的大额优惠券,有无优惠券一目了然,持续维护更新,请放心使用!
// @name:zh           [🔥]!!网购小助手,不花冤枉钱:自动查询淘宝、天猫、天猫国际、京东、京东国际、唯品会等隐藏的大额优惠券,有无优惠券一目了然,持续维护更新,请放心使用!
// @name:zh-TW        [🔥]!!網購小助手,不花冤枉錢:自動查詢淘寶、天貓、天貓國際、京東、京東國際、唯品會等隱藏的大額優惠券,有無優惠券一目瞭然,持續維護更新,請放心使用!
// @description       网购小助手功能有:🔥1、浏览商品时脚本会自动查询商品是否有隐藏的优惠券,支持:京东、淘宝、天猫、天猫超市、天猫国际、京东国际、京东图书、京东大药房、阿里大药房、唯品会等;🔥2、商品二维码生成,手机可快捷访问该商品;🔥3、浏览记录标注,避免反复浏览相同商品(本地存储,可手动清空,快捷键shift+c清空);🔥4、PC网页优化,让使用更加舒适;代码全部采用低侵入提示,脚本长期维护更新~
// @description:zh    网购小助手功能有:🔥1、浏览商品时脚本会自动查询商品是否有隐藏的优惠券,支持:京东、淘宝、天猫、天猫超市、天猫国际、京东国际、京东图书、京东大药房、阿里大药房、唯品会等;🔥2、商品二维码生成,手机可快捷访问该商品;🔥3、浏览记录标注,避免反复浏览相同商品(本地存储,可手动清空,快捷键shift+c清空);🔥4、PC网页优化,让使用更加舒适;代码全部采用低侵入提示,脚本长期维护更新~
// @description:zh-TW 網購小助手功能有:🔥1、瀏覽商品時指令碼或直譯式程式會自動查詢商品是否有隱藏的優惠券,支援:京東、淘寶、天貓、天貓超市、天貓國際、京東國際、京東圖書、京東大藥房、阿里大藥房、唯品会等;🔥2、商品二維碼生成,手機可快捷訪問該商品;🔥3、瀏覽記錄標註,避免反覆瀏覽相同商品(本地存儲,可手動清空,快捷键shift+c清空);🔥4、PC網頁優化,讓使用更加舒適;代碼全部採用低侵入提示,指令碼或直譯式程式長期維護更新~
// @icon		      data:image/png;base64,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
// @namespace         coupon_honghaoer
// @version           2.2.3
// @author            洪皓儿
// @match             *://*.taobao.com/*
// @match             *://*.tmall.com/*
// @match             *://*.tmall.hk/*
// @match             *://*.liangxinyao.com/*
// @match             *://chaoshi.detail.tmall.com/*
// @match             *://pages.tmall.com/wow/an/cs/search**
// @match             *://*.jd.com/*
// @match             *://*.jd.hk/*
// @match             *://item.jkcsjd.com/*
// @match             *://*.yiyaojd.com/*
// @match             *://www.vipglobal.hk
// @match             *://*.vip.com/*
// @match             *://detail.vip.com/detail-*
// @match             *://www.vipglobal.hk/detail-*
// @match             *://category.vip.com/suggest.php**
// @match             *://list.vip.com/*.html
// @exclude           *://jianghu.taobao.com/*
// @exclude           *://login.taobao.com/*
// @exclude           *://uland.taobao.com/*
// @exclude           *://map.taobao.com/*
// @exclude           *://creator.guanghe.taobao.com/*
// @exclude           *://myseller.taobao.com/*
// @exclude           *://qn.taobao.com/*
// @exclude           *://jingfen.jd.com/*
// @exclude           *://passport.jd.com/*
// @exclude           *://jmw.jd.com/*
// @exclude           *://passport.shop.jd.com/*
// @exclude           *://passport.vip.com/*
// @exclude           *://huodong.taobao.com/wow/z/guang/gg_publish/*
// @require           https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.2.1/jquery.min.js
// @require           https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/keypress/2.1.5/keypress.min.js
// @grant             GM_openInTab
// @grant             GM.openInTab
// @grant             GM_getValue
// @grant             GM.getValue
// @grant             GM_setValue
// @grant             GM.setValue
// @grant             GM_addStyle
// @grant             GM_xmlhttpRequest
// @grant             GM.xmlHttpRequest
// @grant             GM_registerMenuCommand
// @license           AGPL License
// @antifeature  	  referral-link 【此提示为GreasyFork代码规范要求含有查券功能的脚本必须添加,请知悉!】
// @charset		      UTF-8
// @run-at            document-idle
// @original-script   https://greasyfork.org/zh-CN/scripts/469417
// @original-author   huahuacat
// @original-license  AGPL License
// ==/UserScript==
 
(function() {
	'use strict';
	
	/**
	 * 代码版权说明:
	 * 原作者huahuacat,本脚本在原作者基础上优化了代码结构,添加了新功能
	 * 本脚本代码已获得原作者授权,并遵循AGPL License开源协议,请悉知!
	 */
	
	const recordBrowsingHistoryKey = "record_browsing_history_key";
	const browsedHtml= `
		<div style="position:absolute;white-space: nowrap; top:7px;padding:2px 5px;font-size:12px;background-color:rgba(0,0,0);color:#FFF;z-index:9999999999;border-radius:20px;right:10px;"><b>已浏览</b></div>
	`
	
	/**
	 * 公共的方法
	 */
	class CommonTools{
		request(method, url, param, isCrossOrigin=false){
			if(isCrossOrigin){
				return this.crossRequest(method, url, param);
			}else{
				return this.gmRequest(method, url, param);
			}
		}
		gmRequest(method, url, param){
			if(!param){
				param = {};
			}
			return new Promise(function(resolve, reject){
				GM_xmlhttpRequest({
					url: url,
					method: method,
					data:param,
					onload: function(response) {
						var status = response.status;
						if(status==200 || status=='200'){
							var responseText = response.responseText;
							resolve({"code":"success", "result":responseText});
						}else{
							reject({"code":"error", "result":null});
						}
					}
				});
			});
		}
		crossRequest(method, url, param) {
			if(!method){
				method = "get";
			}
			if(!url){
				return new Promise(function(resolve, reject){
					reject({"code":"error", "result":null});
				});
			}
			if(!param){
				param = {};
			}
			method = method.toUpperCase();
		    let config = {
		        method: method
		    };
		    if (method === 'POST') {
		        config.headers['Content-Type'] = 'application/json';
		        config.body = JSON.stringify(param);
		    }
			return new Promise(function(resolve, reject){
				fetch(url, config).then(response => response.text()).then(text => {
					resolve({"code":"success", "result":text});
				}).catch(error => {
					reject({"code":"error", "result":null});
				});
			});
		}
		randomNumber(){
			return Math.ceil(Math.random()*100000000);
		}
		getPlatform(url = window.location.href){
			let platform = "";
			if(url.indexOf("detail.tmall")!=-1 || url.indexOf("tmall.hk")!=-1 || url.indexOf("pages.tmall.com")!=-1){
				platform = "tmall";
			}else if(url.indexOf("taobao.com")!=-1 || url.indexOf("maiyao.liangxinyao.com")!=-1){
				platform = "taobao";
			}else if(url.indexOf("jd.com")!=-1 || url.indexOf("npcitem.jd.hk")!=-1 || url.indexOf("yiyaojd.com")!=-1 || url.indexOf("jkcsjd.com")!=-1){
				platform = "jd";
			}else if(url.indexOf("detail.vip.com")!=-1 || url.indexOf("www.vipglobal.hk")!=-1){
				platform = "vpinhui";
			}
			return platform;
		}
		getParamterQueryUrl(text, tag) { //查询GET请求url中的参数
			if(text.indexOf("?")!=-1){ //选取?后面的字符串,兼容window.location.search,前面的?不能去掉
				var textArray = text.split("?");
				text = "?"+textArray[textArray.length-1];
			}
			var t = new RegExp("(^|&)" + tag + "=([^&]*)(&|$)");
			var a = text.substr(1).match(t);
			if (a != null){
				return a[2];
			}
			return "";
		}
		getEndHtmlIdByUrl(url){
			if(url.indexOf("?")!=-1){
				url = url.split("?")[0]
			}
			if(url.indexOf("#")!=-1){
				url = url.split("#")[0]
			}
			var splitText = url.split("/");
			var idText = splitText[splitText.length-1];
			idText = idText.replace(".html","");
			return idText;
		}
		getElementAsync(selector, target=document.body, allowEmpty = true, delay=10, maxDelay=10 * 1000){
			return new Promise((resolve,reject) =>{
				if (selector.toUpperCase() === "BODY") {
					resolve(document.body);
					return;
				}
				if (selector.toUpperCase() === "HTML") {
					resolve(document.html);
					return;
				}
				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);
			});
		}
		GMgetValue(name, value=null) {
			let storageValue = value;
			if (typeof GM_getValue === "function") {
				storageValue = GM_getValue(name, value);
			} else if(typeof GM.setValue === "function"){
				storageValue = GM.getValue(name, value);
			}else{
				var arr = window.localStorage.getItem(name);
				if(arr != null){
					storageValue = arr
				}
			}
			return storageValue;
		}
		GMsetValue(name, value){
			if (typeof GM_setValue === "function") {
				GM_setValue(name, value);
			} else if(typeof GM.setValue === "function"){
				GM.setValue(name, value);
			}else{
				window.localStorage.setItem(name, value)
			}
		}
		decryptStr(str){
			let result = atob(str);
			return result.split('').reverse().join('');
		}
		encryptStr(str){
			let result = str.split('').reverse().join('');
			return btoa(result);
		}
		GMopenInTab(url, options={"active":true, "insert":true, "setParent":true}){
			if (typeof GM_openInTab === "function") {
				GM_openInTab(url, options);
			} else {
				GM.openInTab(url, options);
			}
		}
	}
	
	const dialog = (function(){
		class Dialog {
			constructor() {
				this.mask = document.createElement('div');
				this.dialogStyle = document.createElement('style');
				
				this.setStyle(this.mask, {
					"width": '100%',
					"height": '100%',
					"backgroundColor": 'rgba(0, 0, 0, .6)',
					"position": 'fixed',
					"left": "0px",
					"top": "0px",
					"bottom":"0px",
					"right":"0px",
					"z-index":"9999999999999"
				});
				
				this.content = document.createElement('div');
				this.setStyle(this.content, {
					"max-width": '450px',
					"width":"100%",
					"max-height": '600px',
					"backgroundColor": '#fff',
					"boxShadow": '0 0 2px #999',
					"position": 'absolute',
					"left": '50%',
					"top": '50%',
					"transform": 'translate(-50%,-50%)',
					"borderRadius": '5px'
				})
				this.mask.appendChild(this.content);
			}
			middleBox(param) {
				// 先清空中间小div的内容 - 防止调用多次,出现混乱
				this.content.innerHTML = '';
				
				let title = '默认标题内容';
				if({}.toString.call(param) === '[object String]') {
					title = param;
				} else if({}.toString.call(param) === '[object Object]') {
					title = param.title;
				}
	
				document.body.appendChild(this.mask);
				this.title = document.createElement('div');
				this.setStyle(this.title, {
					"width": '100%',
					"height": '40px',
					"lineHeight": '40px',
					"boxSizing": 'border-box',
					"background-color":"#dedede",
					"color": '#000',
					"text-align": 'center',
					"font-weight":"700",
					"font-size":"17px",
					"border-radius": "4px 4px 0px 0px"
				});
				
				this.title.innerText = title;
				this.content.appendChild(this.title);
	
				this.closeBtn = document.createElement('div');
				this.closeBtn.innerText = '×';
				
				this.setStyle(this.closeBtn, {
					"textDecoration": 'none',
					"color": '#000',
					"position": 'absolute',
					"right": '10px',
					"top": '0px',
					"fontSize": '25px',
					"display":"inline-block",
					"cursor":"pointer"
				})
				this.title.appendChild(this.closeBtn);
				
				const self = this;
				this.closeBtn.onclick = function(){
					self.close();
					if(param.onClose && (typeof param.onClose)==="function"){
						param.onClose();
					}
				}
			}
			showMake(param) {
				//添加公用样式表
				if(param.hasOwnProperty("styleSheet")){
					this.dialogStyle.textContent = param.styleSheet;
				}
				document.querySelector("head").appendChild(this.dialogStyle);
				
				this.middleBox(param);
				this.dialogContent = document.createElement('div');
				this.setStyle(this.dialogContent,{
					"padding":"15px",
					"max-height":"400px"
				});
				this.dialogContent.innerHTML = param.content;
				this.content.appendChild(this.dialogContent);
				param.onContentReady(this);
			}
			close() {
				document.body.removeChild(this.mask);
				document.querySelector("head").removeChild(this.dialogStyle);
			}
			setStyle(ele, styleObj) {
				for(let attr in styleObj){
					ele.style[attr] = styleObj[attr];
				}
			}
		}
		let dialog = null;
		return (function() {
			if(!dialog) {
				dialog = new Dialog()
			}
			return dialog;
		})()
	})();
	
	/**
	 * 优惠券相关功能
	 */
	class Coupon{
		platforms = ["detail.tmall.com", "item.taobao.com", "item.jd.com", "item.yiyaojd.com", "npcitem.jd.hk", 
			"detail.tmall.hk", "detail.vip.com", "item.jkcsjd.com"];
		constructor(commonTools){
			this.commonTools = commonTools;
			this.createQrcodeIsResult = true;
		}
		isRun(){
			for(var i=0; i<this.platforms.length;i++){
				if(window.location.host.indexOf(this.platforms[i])!=-1){
					return true;
				}
			}
			return false;
		}
		filterName(str){
			if(!str) return "";
			str = str.replace(/\t/g,"");
			str = str.replace(/\r/g,"");
			return encodeURIComponent(str)
		}
		async getGoodsData(platform){
			var goodsId = "";
			var goodsName = "";
			const href = window.location.href;
			if(platform=="taobao"){
				goodsId = this.commonTools.getParamterQueryUrl(window.location.search, "id");
				try{
					const titleObj = document.querySelector("[class^='ItemTitle--']");
					if(!!titleObj){
						goodsName = titleObj.textContent;
					}
				}catch(e){}
				
			}else if(platform=="tmall"){
				goodsId = this.commonTools.getParamterQueryUrl(window.location.search, "id");
				try{
					const titleObj = document.querySelector("[class^='ItemTitle--']");
					if(!!titleObj){
						goodsName = titleObj.textContent;
					}
				}catch(e){}
				
			}else if(platform=="jd"){
				goodsId = this.commonTools.getEndHtmlIdByUrl(href);
				try{
					const titleObj = document.querySelector("[class='sku-name']");
					if(!!titleObj){
						goodsName = titleObj.textContent;
					}
				}catch(e){}
			}else if(platform=="vpinhui"){
				goodsId = this.commonTools.getEndHtmlIdByUrl(href).replace("detail-","");
				const titleObj = document.querySelector("[class='pib-title-detail']");
				if(!!titleObj){
					goodsName = titleObj.textContent;
				}
			}
			const data = {"goodsId":goodsId, "goodsName":this.filterName(goodsName)};
			return data;
		}
		randomSpmValue(){
			$("meta[name='data-spm']").each(function(){
				var max = 5000;
				var min = 1000;
				var randomValue = Math.floor(Math.random() * (max - min + 1) ) + min;
				var randomLetter = String.fromCharCode(Math.floor( Math.random() * 26) + "a".charCodeAt(0));
				$(this).attr("content", randomValue+randomLetter);
			});
			$("meta[name='spm-id']").each(function(){
				var max = 5000;
				var min = 1000;
				var randomValue = Math.floor(Math.random() * (max - min + 1) ) + min;
				var randomLetter = String.fromCharCode(Math.floor( Math.random() * 26) + "a".charCodeAt(0));
				$(this).attr("content", randomValue+randomLetter);
			});
			$("body").find("*").each(function(){
				$(this).removeAttr("data-spm-anchor-id");
				$(this).removeAttr("data-spm");
			});
		}
		runAliDeceptionSpm(){
			const host = window.location.host;
			if(host.indexOf("aliyun.com")!=-1 || host.indexOf("taobao.com")!=-1 || host.indexOf("tmall.com")!=-1){
				this.randomSpmValue();
				setInterval(()=>{
					this.randomSpmValue();
				}, 2000);
			}
		}
		browsingHistoryMark(platform, goodsId){
			let histories = this.commonTools.GMgetValue(recordBrowsingHistoryKey,[]);
			let saveContent = platform+"_"+goodsId;
			if(!histories.includes(saveContent)){
				histories.unshift(saveContent);
				this.commonTools.GMsetValue(recordBrowsingHistoryKey,histories.slice(0,60));
			}
		}
		async browsingHistoryGoods(platform, goodsId){
			
		}
		async createHtml(platform, goodsId, goodsName){
			if(!platform || !goodsId){
				return "kong";
			}
			
			this.browsingHistoryMark(platform, goodsId); //把浏览记录给存在本地
			this.browsingHistoryGoods(platform, goodsId);  //把商品记录下来,包括title、价格和主图
			
			let addition = "";
			if(platform=="vpinhui"){
				const vip = goodsId.split("-");
				addition = vip[0];
				goodsId = vip[1];
			}
			const goodsCouponUrl = "https://api.shuoaini.xyz/api/coupon/query?no=888&version=1.0.2&platform="+platform+"&id="+goodsId+"&q="+goodsName+"&addition="+addition;
			try{
				const data = await this.commonTools.request("GET", goodsCouponUrl, null, true);
				if(data.code=="success" && !!data.result){
					const json = JSON.parse(data.result);
					
					await this.createCoupon(platform, json.data);
					await this.createQrcode(platform, json.mscan);
										
					//开启插入检测
					let heartms = 0;
					const HEART_DELAY = 1500, MAX_MS = 1000*30;  
					const createResultInterval = setInterval(async ()=>{
						if(this.createQrcodeIsResult){
							if(document.querySelector("*[name='exist-llkbccxs-9246-hi']") || heartms>=MAX_MS){
								clearInterval(createResultInterval);
							}else{
								await this.createCoupon(platform, json.data);
							}
						}
						heartms += HEART_DELAY;
					}, HEART_DELAY);
				}
			}catch(e){
				console.log("createCouponHtml:",e);
			}
		}
		async getHandlerElement(handler){
			const getElement = async (handler)=>{
				const promiseArray = [];
				const handlers = handler.split("@");
				for(let i=0; i<handlers.length; i++){
					const eleName = handlers[i];
					if(!eleName){
						continue;
					}
					if(eleName=="body"){
						promiseArray.push(
							new Promise((resolve,reject) =>{ resolve(document.body) }) 
						);
					}else if(eleName=="html"){
						promiseArray.push(
							new Promise((resolve,reject) =>{ resolve(document.html) }) 
						);
					}else{
						promiseArray.push(this.commonTools.getElementAsync(eleName, document.body, true, 10, 1500));
					}
				}
				const element = await Promise.race(promiseArray);
				return element ? element : null;
			}

			const element = await getElement(handler);
			return new Promise((resolve,reject) =>{
				resolve(element);
			});
		}
		async createCoupon(platform, result){
			try{
				this.createQrcodeIsResult = false;
				if(!result || result==="null" || !result.hasOwnProperty("css") || !result.hasOwnProperty("html") || !result.hasOwnProperty("handler")){
					return;
				}
				const  cssText = result.css, htmlText = result.html, handler = result.handler, templateId = result.templateId;
				if(!cssText || !htmlText || !handler){
					return;
				}
				GM_addStyle(cssText);

				// 添加HTML, 需要动态检测元素
				const handlerElement = await this.getHandlerElement(handler);
				if(handlerElement){
					const $handlerElement = $(handlerElement);
					if(platform=="taobao"){
						$handlerElement.parent().after(htmlText);
					}else if(platform=="tmall"){
						$handlerElement.parent().after(htmlText);
					}else if(platform=="jd"){
						$handlerElement.after(htmlText);
					}else if(platform=="vpinhui"){
						$handlerElement.after(htmlText);
					}
				}
				
				const $template = $("#"+templateId);
				if($template.length == 0){
					return;
				}
				
				const couponId = $template.data("id");
				const goodsPrivateUrl = "https://api.shuoaini.xyz/api/private/real?no=888&v=1.0.2&p="+platform+"&id=";
				
				if(!/\d/.test(couponId)){
					return;
				}
				
				setInterval(()=>{
					$template.find("*").each(function(){
						$(this).removeAttr("data-spm-anchor-id");
					});
				},400);
				
				const couponElementA = $template.find("a[name='cpShUrl']");				
				couponElementA.unbind("click").bind("click", ()=>{
					event.stopPropagation();
					event.preventDefault();
					this.commonTools.request("GET", goodsPrivateUrl+couponId, null, true).then((privateResultData)=>{
						if(privateResultData.code==="success" && !!privateResultData.result){
							let url = JSON.parse(privateResultData.result).url;
							if(!!url) GM_openInTab(url, {active:true});
						}
					});
				});
									
				//canvas画二维码
				var $canvasElement = $("#ca"+templateId);
				if($canvasElement.length == 0){
					return;
				}
				const qrcodeResultData = await this.commonTools.request("GET", goodsPrivateUrl+couponId, null, true);
				if(!!qrcodeResultData && qrcodeResultData.code==="success" && !!qrcodeResultData.result){
					let img = JSON.parse(qrcodeResultData.result).img;
					if(!!img){
						var canvasElement = document.getElementById("ca"+templateId);
						var cxt = canvasElement.getContext("2d");
						var imgData = new Image();
						imgData.src = img;
						imgData.onload=function(){
							cxt.drawImage(imgData, 0, 0, imgData.width, imgData.height);
						}
					}
				}
			}catch(e){
				console.log("~~~~~~~~~~~~~~~~~",e);
			}finally{
				this.createQrcodeIsResult = true;
			}
		}
		async createQrcode(platform, mscan){
			if(!mscan || mscan==="null" || !mscan.hasOwnProperty("mount") 
				|| !mscan.hasOwnProperty("html")|| !mscan.hasOwnProperty("qrcode")){
				return;
			}
			const {mount, html, qrcode, iden} = mscan;
			if(!!mount && !!html && !!qrcode && !!iden){
				$(mount).append(html);
				var canvasElement = document.getElementById("mscan"+iden);
				var width = canvasElement.getAttribute("width");
				var height = canvasElement.getAttribute("height");
				var cxt = canvasElement.getContext("2d");
				var imgData = new Image();
				imgData.src = qrcode;
				imgData.onload=function(){
					cxt.drawImage(imgData, 0, 0, width, height);
				}
			}
		}
		async start(){
			if(this.isRun()){
				this.runAliDeceptionSpm();
				const platform = this.commonTools.getPlatform();
				if(!platform) return;
				//如果sku太多就折叠,不然移动端体验太差了
				if(platform=="tmall" || platform=="taobao"){
					this.commonTools.getElementAsync("div[class^='skuWrapper--']", document.body, false, 10, 1500).then((skuItemWrapper)=>{
						if(skuItemWrapper != null){
							const { style } = skuItemWrapper;
							style.maxHeight = "400";
							style.overflow = "auto";
						}
					}).catch(()=>{});
				}else if(platform=="jd"){
					const skuItemWrapper = document.querySelector("#choose-attrs");
					if(skuItemWrapper){
						const { style } = skuItemWrapper;
						style.maxHeight = "400";
						style.overflow = "auto";
					}
				}
				const goodsData = await this.getGoodsData(platform);
				this.createHtml(platform, goodsData.goodsId, goodsData.goodsName);
			}
		}
	}
	
	class SearchPageObject{
		intervalIsRunComplete = true;  //定时任务一个循环是否完成
		
		constructor(commonTools){
			this.commonTools = commonTools;
			this.histories = commonTools.GMgetValue(recordBrowsingHistoryKey, []);
		}
		
		isRun(){
			return [
				/^https:\/\/www\.taobao\.com(\/|\/\?)?/i, /^https:\/\/s\.taobao\.com/i, /^https:\/\/shop(\d+)\.taobao\.com/i, /^https:\/\/www\.tmall\.com(\/|\/\?)?/i,
				/pages\.tmall\.com/i, /list\.tmall\.com/i, /list\.tmall\.hk/i, /tmall\.com\/category/i, /tmall\.com\/search/i,
				/tmall\.com\/shop/i, /tmall\.com\/\?q=/i, /maiyao\.liangxinyao\.com/i, /^https:\/\/www\.jd\.com(\/|\/\?)?/i, /search\.jd\.com/i,
				/search\.jd\.hk/i, /pro\.jd\.com\/mall/i, /jd\.com\/view_search/i, /category\.vip\.com/i, /list\.vip\.com/i
			].map((reg)=>(new RegExp(reg)).test(window.location.href)).some((res)=>res);
		}
		
		requestConf(){
			return new Promise((resolve, reject) => {
				this.commonTools.request("GET", "https://api.shuoaini.xyz/api/plugin/load/conf", null, true).then((data)=>{
					if(data.code=="success" && !!data.result){
						resolve(data.result);
					}else{
						resolve(null);
					}
				});
			});
		}
		
		pickupSearchElements(conf){
			const selectorElementList = new Array();
			const url = window.location.href;
			let confFilter = conf;
			try{
				confFilter = confFilter.replace(/\\\\/g,"\\");
			}catch(e){}
			const confJson = JSON.parse(confFilter);
			for(let key in confJson){
				if(!confJson.hasOwnProperty(key)){
					continue;
				}
				for(let i=0; i<confJson[key].length; i++){
					const itemJson = confJson[key][i];
					if(!itemJson.hasOwnProperty("elements") || !itemJson.hasOwnProperty("matches")){
						continue;
					}
					const {elements, matches} = itemJson;
					const isMatch = matches.map((reg)=>(new RegExp(reg, "i")).test(url)).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"]
							});
						}
					}
				}
			}
			return selectorElementList;
		}
		
		searchPage(selectorElementList){
			const items = [];
			selectorElementList.forEach((elementData)=>{
				if(elementData.element){
					$(elementData.element).each(function(){
						items.push({"element":$(this), "findA": elementData.findA, "page":elementData.page});
					});
				}
			});
			if(items.length>0){
				this.createAllElementHtml(items);
			}
		}
		
		/**
		 * @param {Object} items
		 * 为所有items创建提示
		 */
		createAllElementHtml(items){
			this.intervalIsRunComplete = false;
			const promises = [];
			items.forEach((item)=>{
				promises.push(this.createOneElementHtml(item));
			});
			Promise.all(promises).then((result)=>{
				this.intervalIsRunComplete = true;
			});
		}
		
		/**
		 * @param {Object} item
		 * 为每一个Item创建提示
		 */
		createOneElementHtml(item){
			const {element, page, findA} = item;
			const self = this;
			return new Promise(function(resolve, reject){
				if(element.attr("honghaoerbox")){  //当存在时,说明已经处理过了
					resolve(-1);
					return;
				}
				element.attr("honghaoerbox","true");
				element.css("position","relative");
				element.on("click",function(){
					$(this).append(browsedHtml);
				});
				
				var goodsDetailUrl = null;
				if(findA==="this"){ //说明本身就是A标签
					goodsDetailUrl = element.attr("href");
				}else if(/^child@/.test(findA)){
					const elementA = element.find(findA.replace(/^child@/,""));
					if(elementA){
						goodsDetailUrl = elementA.attr("href");
					}
				}
				if(!goodsDetailUrl){
					resolve(-2);
					return;
				}
				
				var analysisData = null;
				if(page.indexOf("jd_")!=-1){
					var jdId = self.commonTools.getEndHtmlIdByUrl(goodsDetailUrl);
					if(!!jdId) analysisData = {"id":jdId, "platform":"jd"};
				}else if(page.indexOf("vpinhui_")!=-1){
					var vipId = self.commonTools.getEndHtmlIdByUrl(goodsDetailUrl).replace("detail-","");;
					if(!!vipId){
						analysisData = {"id":vipId.split("-")[1], "platform":"vpinhui"};
					}
				}else{
					var platform = self.commonTools.getPlatform(goodsDetailUrl);
					var id = self.commonTools.getParamterQueryUrl(goodsDetailUrl, "id");
					if(platform && id){
						analysisData = {"id":id, "platform":platform};
					}
				}
				if(!analysisData){
					resolve(-3);
					return;
				}
				
				const mark = analysisData.platform + "_" + analysisData.id;
				if(self.histories.includes(mark)){
					element.append(browsedHtml);
				}
				
				const searchUrl = "https://api.shuoaini.xyz/api/ebusiness/q/c?p="+analysisData.platform+"&id="+analysisData.id;
				self.commonTools.request("GET", searchUrl, null, true).then((data)=>{
					if(data.code=="success" && !!data.result){
						const { tip, encryptLink } = JSON.parse(data.result);
						if(tip){
							element.append(tip);
						}
						if(encryptLink){
							let decryptUrl = null;
							try{
								const decryptLink = atob(encryptLink);
								decryptUrl = decryptLink.split('').reverse().join('');
							}catch(e){}
							if(decryptUrl){
								self.relativeJu(page, element, decryptUrl);
							}
						}
					}
					resolve(0);
				}).catch(()=>{
					resolve(-4);
				});
			});
		}
		
		relativeJu(page, element, decryptUrl){
			const self = this;
			try{
				if(page.indexOf("jd_")!=-1){
					element.find("a").each(function(){
						if($(this).attr("href").indexOf("item.jd.com")!=-1){
							$(this).removeAttr("onclick");
							$(this).unbind("click").bind("click", function(e){
								e.preventDefault();
								e.stopPropagation();
								self.commonTools.GMopenInTab(decryptUrl);
							});
						}
					});
				}
				else if(page.indexOf("taobao_")!=-1 || page.indexOf("tmall_")!=-1){
					element.unbind("click").bind("click",function(e){
						const target = $(e.target);
						const tagName = target.prop("tagName").toUpperCase();
						let isPreventDefault = false;
						if(tagName==="A"){ //只有点击A标签才去判断
							const href = target.attr("href");
							const isDetail = [/detail\.tmall\.com/, /item\.taobao\.com/]
								.map((reg)=> reg.test(href))
								.some((result) => result);
							if(isDetail){
								isPreventDefault = true;
							}
						}else{
							isPreventDefault = true;
						}
						if(isPreventDefault){
							e.preventDefault();
							e.stopPropagation();
							self.commonTools.GMopenInTab(decryptUrl);
						}	
					});
				}
				else if(page.indexOf("vpinhui_")!=-1){
					element.find("a").each(function(){
						if($(this).attr("href").indexOf("detail.vip.com/detail-")!=-1){
							$(this).unbind("click").bind("click", function(e){
								e.preventDefault();
								e.stopPropagation();
								self.commonTools.GMopenInTab(decryptUrl);
							});
						}
					});
				}
			}catch(e){console.log(e);}
		}
		
		start(){
			if(this.isRun()){
				this.requestConf().then((conf)=>{
					const selectorElementList = this.pickupSearchElements(conf);
					if(this.intervalIsRunComplete){
						this.searchPage(selectorElementList);
					}
					setInterval(()=>{
						if(this.intervalIsRunComplete){
							this.searchPage(selectorElementList);
						}
					}, 1500);
				});
			}
		}
		
	}

	const commonTools = new CommonTools();
	(new Coupon(commonTools)).start();
	(new SearchPageObject(commonTools)).start();
	
	GM_registerMenuCommand("清除浏览记录", ()=> {
		if(confirm('此弹窗来自脚本-[🔥]!!网购小助手,不花冤枉钱\n是否要移除所有的浏览记录?移除后将不可恢复...')){
			commonTools.GMsetValue(recordBrowsingHistoryKey,[]); //已浏览标识
		}
	});
})();