// ==UserScript==
// @name 网购优惠查询小助手,淘宝、天猫、京东隐藏优惠券自动查询,搜索结果优惠券信息直接展示,无需进入详情页,快速对比同款优惠信息,持续维护中
// @name:zh 网购优惠查询小助手,淘宝、天猫、京东隐藏优惠券自动查询,搜索结果优惠券信息直接展示,无需进入详情页,快速对比同款优惠信息,持续维护中
// @name:zh-TW 網購優惠查詢小助手,淘寶、天貓、京东隱藏優惠券自動查詢,搜索結果優惠券信息直接展示,無需進入詳情頁,快速對比同款優惠信息,持續維護中
// @description 网购优惠查询小助手功能:1,淘宝、天猫商品详情页自动显示优惠券信息,包括隐藏优惠券的信息,点击领券按钮可快速领取优惠券。2.淘宝、天猫、京东搜索商品列表,每个商品自动显示优惠券面额,为你提供快速对比的效果!
// @description:zh 网购优惠查询小助手功能:1,淘宝、天猫商品详情页自动显示优惠券信息,包括隐藏优惠券的信息,点击领券按钮可快速领取优惠券。2.淘宝、天猫、京东搜索商品列表,每个商品自动显示优惠券面额,为你提供快速对比的效果!
// @description:zh-TW 網購優惠查詢小助手功能:1,淘寶、天貓商品詳情頁自動顯示優惠券信息,包括隱藏優惠券的信息,點擊領券按鈕可快速領取優惠券。2.淘寶、天貓、京東搜索商品列表,每個商品自動顯示優惠券面額,爲你提供快速對比的效果!
// @namespace coupon
// @version 1.78
// @author zhihu
// @license End-User License Agreement
// @match *://*.taobao.com/*
// @match *://*.tmall.com/*
// @match *://chaoshi.detail.tmall.com/*
// @match *://*.tmall.hk/*
// @match *://*.liangxinyao.com/*
// @match *://*.jd.com/*
// @match *://*.jd.hk/*
// @match *://*.yiyaojd.com/*
// @match *://*.vip.com/*
// @match *://*.vipglobal.hk/*
// @exclude *://login.taobao.com/*
// @exclude *://login.tmall.com/*
// @exclude *://uland.taobao.com/*
// @exclude *://pages.tmall.com/*
// @exclude *://wq.jd.com/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant GM_xmlhttpRequest
// @grant GM.xmlHttpRequest
// @grant GM_getValue
// @grant GM.getValue
// @grant GM_setValue
// @grant GM.setValue
// @antifeature referral-link 【此提示为GreasyFork代码规范要求含有查券功能的脚本必须添加,请知悉!】
// @connect api.zhihupe.com
// @grant unsafeWindow
// ==/UserScript==
(function() {
'use strict';
//全局对象
const window = unsafeWindow||window;
const API_DOMAIN = 'https://api.zhihupe.com';
//const API_DOMAIN = 'http://127.0.0.1:7001';
//---------------------------公共方法开始---------------------------
const Utils = {
//兼容 Tampermonkey | Violentmonkey | Greasymonkey 4.0+
getValue:function(name, value) {
if (typeof GM_getValue === "function") {
return GM_getValue(name, value);
} else {
return GM.getValue(name, value);
}
},
//兼容 Tampermonkey | Violentmonkey | Greasymonkey 4.0+
setValue:function(name, value) {
if (typeof GM_setValue === "function") {
GM_setValue(name, value);
} else {
GM.setValue(name, value);
}
},
/**
* 添加css
* @params {String||Array} css - css样式
*/
appendStyle(css){
let style = document.createElement('style');
if(css instanceof Array){
style.textContent = css.join('');
}else{
style.textContent = css
}
style.type = 'text/css';
let doc = document.head || document.documentElement;
doc.appendChild(style);
},
/**
* 添加js文件
* @params {String} url - js文件地址
*/
appendScript:function(type,content) {
let script = document.createElement('script');
if(type === 'url'){
script.src = content;
}else{
script.innerHTML = content;
}
var docu = document.body;
docu.appendChild(script);
},
getObjectValue(object,path,defValue){
let obj = object;
if(typeof path === 'string'){
const reg = /[^\[\].]+/g;
path = path.match(reg);
}
for(const key of path){
if(!obj) {
return defValue
}
obj = obj[key];
}
return obj === undefined ? defValue : obj;
},
getQueryParam(query,url = ''){
let search = ''
if(url&&url.indexOf('?' !== -1)){
search = url.split('?').slice(1).join();
}else{
search = window.location.search.replace('?','')
}
const queryArr = search.split('&');
let param = null;
queryArr.forEach(item => {
const paramArr = item.split('=');
if(paramArr[0] === query){
param = paramArr[1];
}
});
return param;
},
getUrlid(url) {
var id ="";
if (url.indexOf("?") != -1) {
url = url.split("?")[0]
}
if (url.indexOf("#") != -1) {
url = url.split("#")[0]
}
var text = url.split("/");
id = text[text.length - 1];
id = id.replace(".html", "");
return id
},
monitorElement(attr){
let attrArr = [];
if(attr instanceof Array&&attr.length > 0){
attrArr = [...attr];
}else{
attrArr.push(attr)
}
let element = null;
return new Promise((resolve, reject) => {
attrArr.forEach(ele =>{
let timer = null,count = 0;
element = document.querySelector(ele);
timer = setInterval(()=>{
if(element){
clearInterval(timer);
resolve(element);
}
if(count > 50){
clearInterval(timer);
reject('未找到元素节点');
}
element = document.querySelector(ele);
count ++
},200)
})
})
}
}
const initData = {
wenku:{
codeInputElement:"#code",
loginCode:"123456",
},
coupon:{
shopGuideGroupText:'捡漏导购Q群',
shopGuideGroup:'188872170',
hasCouponBtnText:'领券购买',
noCouponBtnText:'直接购买',
noCommissionBtnText:'搜索同款优惠',
buyUrl:'http://tool.wezhicms.com/coupon/getscan.php',
tbShortUrlApi:'https://api.shop.xuelg.com/?id={ID}&m=shangpin',
tbShortUrlApiReqQuery: 'shorturl',
blackElement:['.coupon-wrap','#toolbar-qrcode'],
taobao:{
detailCouponMountElement:['.SecurityPrice--securityPrice--25lJx-X','.Price--root--1CrVGjc'],
searchGoodsCardElement:['.Content--content--sgSCZ12 .Card--doubleCardWrapper--L2XFE73','.Content--content--sgSCZ12 .Card--doubleCardWrapperMall--uPmo5Bz','.J_TItems .item .photo a']
},
tmall:{
detailCouponMountElement:['.SecurityPrice--securityPrice--25lJx-X','.Price--root--1CrVGjc']
},
tmallcs:{
searchGoodsCardElement:['.feeds-list .feeds-item a']
},
jd:{
detailCouponMountElement:'#J-summary-top',
searchGoodsCardElement:['.J-goods-list .gl-i-wrap .p-img a','.jSearchListArea .jItem .jPic a']
}
}
}
class Coupon{
//优惠券查询地址
couponApiUrl = '';
//优惠券展示节点
initElement = null;
get isHasCoupon(){
return this.couponInfo?.couponAmount > 0;
}
constructor(platform){
this.platform = platform;
//优惠券信息
let couponInfo = {};
Object.defineProperty(this,'couponInfo',{
set(value){
couponInfo = value;
//更新优惠券信息
this.updateCouponHtml();
},
get(){
return couponInfo;
}
})
}
/*
获取优惠券信息
return {Promise}
*/
getCouponInfo(){
if(!this.goodsId) throw new TypeError('商品ID获取失败');
if(!this.couponApiUrl) throw new TypeError('优惠券查询链接不存在');
return new Promise((resolve, reject) => {
fetch(this.couponApiUrl,{
method:'GET',
mode:'cors',
}).then(r=>r.json()).then(response=>{
if(response.code === 1){
resolve(response.data)
}else{
reject(new TypeError(response.message))
}
}).catch(err=>{
reject(err)
})
});
}
getTbShortUrl(id){
const api = initData.coupon.tbShortUrlApi.replace('{ID}',id)
return new Promise((resolve, reject) => {
fetch(api,{
method:'GET',
mode:'cors',
}).then(r=>r.json()).then(response=>{
resolve(Utils.getObjectValue(response,initData.coupon.tbShortUrlApiReqQuery));
}).catch(err=>{
reject(err)
})
});
}
/*
*插入优惠券节点
* params {ElementObject} 定位元素对象
* params {String} position 插入位置
*/
async appendCouponElement(element,position = "afterend"){
//插入css
this.css&&Utils.appendStyle(this.css)
//插入Html
this.initElement = this.loadingElement||null;
if(this.initElement)element.insertAdjacentElement(position,this.initElement);
}
async updateCouponHtml(){
if(this.initElement){
this.initElement.innerHTML = this.couponHtml
//添加关闭二维码事件
const qr = document.querySelectorAll('.closeQr');
if(qr.length > 0){
console.log(qr)
Array.from(qr).forEach(e=>{e.onclick = ()=> e.parentNode.style.display = 'none'})
}
}
}
async updateCouponErrorHtml(){
if(this.initElement)this.initElement.innerHTML = this.couponHtml
}
}
class DetailCoupon extends Coupon{
css = `
.zhihu-coupon:hover .zhihu-scan{
display:block!important;
}
`
get mobileAppText(){
let text = '手机淘宝';
switch (this.platform) {
case 'tmall':
case 'taobao':
text = '手机淘宝'
break;
case 'jd':
text = '手机京东或微信'
break;
}
return text;
}
get couponHtml(){
let couponHtml = '<text style="font-size: 20px;">暂未发现优惠券</text>',
tipsText = initData.coupon.shopGuideGroupText + ':' + initData.coupon.shopGuideGroup,
btnText = initData.coupon.noCouponBtnText,
buyLink = `${initData.coupon.buyUrl}?link=${this.couponInfo.shortUrl}&platform=${encodeURIComponent(this.mobileAppText)}`,
qrcodebox = `<div style="position:fixed;bottom:50px;right:50px;width: 124px; z-index: 999999;">${this.qrcodeHtml}</div>`
if(this.isHasCoupon){
couponHtml = `
<text style="font-size: 20px;">优惠券:</text>
<text style="font-size: 18px; margin-right: 2px;">¥</text>${Math.round(this.couponInfo.couponAmount)}
`;
tipsText = `${this.couponInfo.couponStartTime} - ${this.couponInfo.couponEndTime}`;
btnText = initData.coupon.hasCouponBtnText;
}else if(this.noCommission){
couponHtml = '<text style="font-size: 20px;">暂未发现优惠券</text>';
buyLink = '';
btnText = initData.coupon.noCommissionBtnText;
qrcodebox = '';
}
return `
<div style="width: 279px; color: rgb(255, 255, 255); padding-left: 20px; box-sizing: border-box;">
<div style="font-size: 28px; line-height: 28px; font-weight: 900; white-space: nowrap;">
${couponHtml}
</div>
<div style="margin-top: 5px;">${tipsText}</div>
</div>
<div style="text-align: center; width: calc(100% - 279px); font-size: 20px; color: rgb(255, 255, 255); font-weight: bold; letter-spacing: 1px; cursor: pointer;">
<a target="_blank" href="${buyLink}" style="text-decoration: none; color: rgb(255, 255, 255);">${btnText}</a>
</div>
<div class="zhihu-scan" style="position: absolute; display: block; right: 426px; padding-right: 5px; top: -10px; width: 124px; z-index: 999999;">
${this.qrcodeHtml}
</div>
${qrcodebox}
`
}
get loadingElement(){
const div = document.createElement('div');
div.classList = 'zhihu-coupon';
div.style = 'background-image: url(https://gw.alicdn.com/tfs/TB16d.1ykPoK1RjSZKbXXX1IXXa-665-115.png); position: relative; font-family: HelveticaNeue-Bold, "Helvetica Neue"; width: 426px; height: 75px; background-size: 100%, 100%; background-repeat: no-repeat; margin: 10px 0px 10px 10px; display: flex; align-items: center;'
div.innerHTML = `
<div style="width: 279px; color: rgb(255, 255, 255); padding-left: 20px; box-sizing: border-box;">
<div style="font-size: 28px; line-height: 28px; font-weight: 900; white-space: nowrap;">
<text style="font-size: 20px;">正在搜索优惠券···</text>
</div>
</div>
`;
return div;
}
get qrcodeHtml(){
if(!this.couponInfo?.shortUrl) return '';
return `
<i class="closeQr" style="position: absolute;right: -2px;top: -2px;cursor: pointer;"><svg t="1712718308343" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1614" width="18" height="18"><path d="M512 960C264.97 960 64 759.03 64 512S264.97 64 512 64c247.04 0 448 200.97 448 448S759.04 960 512 960z m0-861.54C283.98 98.46 98.46 283.98 98.46 512S283.98 925.54 512 925.54 925.54 740.02 925.54 512 740.02 98.46 512 98.46z" fill="#666666" p-id="1615"></path><path d="M353.61 687.62c-4.41 0-8.82-1.68-12.18-5.05-6.73-6.73-6.73-17.63 0-24.37l316.78-316.78c6.73-6.73 17.63-6.73 24.37 0s6.73 17.63 0 24.37L365.79 682.57a17.14 17.14 0 0 1-12.18 5.05z" fill="#666666" p-id="1616"></path><path d="M670.39 687.62c-4.41 0-8.82-1.68-12.18-5.05L341.43 365.79c-6.73-6.73-6.73-17.63 0-24.37s17.63-6.73 24.37 0L682.58 658.2c6.73 6.73 6.73 17.63 0 24.37a17.18 17.18 0 0 1-12.19 5.05z" fill="#666666" p-id="1617"></path></svg></i>
<div style="text-align: center; padding: 12px 5px 8px; background: rgb(255, 255, 255); border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 12px;">
<div style="margin: 0px auto; width: 100px;">
<img src="http://v.zhihupe.com/enQrcode?url=${this.couponInfo.shortUrl}" style="width: 100px;">
</div>
<div style="margin-top: 4px;">${this.mobileAppText}扫一扫,享优惠</div>
</div>
`
}
constructor(platform){
super(platform);
this.addCouponElement();
}
async addCouponElement(){
try {
//获取商品ID和优惠券API链接
if(this.platform == 'taobao'||this.platform == 'tmall'){
this.goodsId = Utils.getQueryParam('id')||null;
const shortUrl = await this.getTbShortUrl(this.goodsId);
console.log(shortUrl)
this.couponApiUrl = API_DOMAIN + '/api/coupon/info?platform=taobao' + '&id=' + shortUrl
}else if(this.platform === 'jd'){
this.goodsId = Utils.getUrlid(window.location.href)||null;
this.couponApiUrl = API_DOMAIN + '/api/coupon/info?platform=jd' + '&id=' + this.goodsId;
}
//添加优惠券元素
const attr = initData.coupon[this.platform]['detailCouponMountElement'];
console.log(initData.coupon[this.platform])
const element = await Utils.monitorElement(attr);
this.appendCouponElement(element);
//获取商品优惠券
this.couponInfo = await this.getCouponInfo();
} catch (error) {
//添加无佣金状态
this.noCommission = true;
//更新无佣金html
this.updateCouponErrorHtml()
console.log(error)
}
}
}
class SearchCoupon extends Coupon{
get couponHtml(){
let html = `<span style="background: rgb(0 0 0 / 51%);border-radius: 999px;padding: 5px 10px;color: #fff;">暂无优惠</span>`
if(this.isHasCoupon){
html = `<span style="background: rgb(253 2 57);border-radius: 999px;padding: 5px 10px;color: #fff;">有券:减${this.couponInfo.couponAmount}元</span>`
}
return html
}
get loadingElement(){
const div = document.createElement('div');
div.style = 'position: absolute;top: 10px;right: 10px;z-index: 99999999;font-size: 12px;';
div.innerHTML = `
<span style="background: rgb(0 0 0 / 51%);border-radius: 999px;padding: 5px 10px;color: #fff;">正在搜索优惠</span>
`;
return div;
}
constructor(element,platform){
super(platform);
this.addCouponElement(element)
}
async addCouponElement(element){
try {
//获取商品ID和优惠券API链接
if(this.platform == 'taobao'||this.platform == 'tmallcs'){
const href = element.getAttribute('href');
this.goodsId = Utils.getQueryParam('id',href)||null;
const shortUrl = await this.getTbShortUrl(this.goodsId);
console.log(shortUrl)
this.couponApiUrl = API_DOMAIN + '/api/coupon/search?platform=taobao' + '&id=' + shortUrl
}else if(this.platform === 'jd'){
const href = element.getAttribute('href');
this.goodsId = Utils.getUrlid(href)||null;
this.couponApiUrl = API_DOMAIN + '/api/coupon/search?platform=jd' + '&id=' + this.goodsId;
}
element.style.position = 'relative';
//添加优惠券节点
this.appendCouponElement(element,'beforeend');
//获取商品优惠券
this.couponInfo = await this.getCouponInfo();
} catch (error) {
console.log(error)
//更新无佣金html
this.updateCouponErrorHtml()
console.log(error.message)
}
}
}
async function getInitData(){
const request = ()=>{
return new Promise((resolve, reject) => {
fetch(API_DOMAIN + '/api/coupon/init',{
method:'GET',
mode:'cors',
}).then(r=>r.json()).then(response=>{
if(response.code === 1){
resolve(response.data)
}else{
resolve(null)
}
}).catch(err=>{
resolve(null)
})
})
}
const _initData = await request();
_initData&&(initData.coupon = {..._initData});
}
async function detailCouponInit(platform = 'taobao'){
await getInitData();
new DetailCoupon(platform);
//移除节点
if(initData.coupon.blackElement instanceof Array && initData.coupon.blackElement.length > 0){
const blackElement = initData.coupon.blackElement;
blackElement.forEach(item => {
Utils.monitorElement(item).then(selector=>{
selector.remove()
})
})
}
}
async function searchCouponInit(platform = 'taobao'){
await getInitData();
if(!(initData.coupon?.[platform]?.searchGoodsCardElement instanceof Array)||initData.coupon?.[platform]?.searchGoodsCardElement.length === 0) return
//class数组
const clss = initData.coupon[platform].searchGoodsCardElement;
//监听商品卡片
setInterval(()=>{
//遍历class数组
for (let i = 0; i < clss.length; i++) {
const elements = document.querySelectorAll(clss[i]);
if(elements&&elements.length > 0){
Array.from(elements).forEach(element=>{
if(element.classList.contains('zhihu-coupon-added')) return;
//添加class标记
element.classList.add('zhihu-coupon-added');
new SearchCoupon(element,platform);
})
}
}
},1500)
}
async function zhihuWenkuInit(){
sessionStorage.setItem('zhihu_sign',true);
}
//网址匹配
const siteMap = [
{
match:['item.taobao.com/item.htm.*'],
platform:'taobao',
initFunc:detailCouponInit
},
{
match:['detail.tmall.com/item.htm.*','detail.tmall.hk/hk/item.htm.*'],
platform:'tmall',
initFunc:detailCouponInit
},
{
match:['item.jd.com/.*','npcitem.jd.hk/.*','item.yiyaojd.com/.*'],
platform:'jd',
initFunc:detailCouponInit
},
{
match:['s.taobao.com/search.*','suning.tmall.com/category.*'],
platform:'taobao',
initFunc:searchCouponInit
},
{
match:['pages.tmall.com/wow/an/cs/search.*'],
platform:'tmallcs',
initFunc:searchCouponInit
},
{
match:['search.jd.com/Search.*','list.jd.com/list.html.*','mall.jd.com/view_search.*'],
platform:'jd',
initFunc:searchCouponInit
},
{
match:['wenku.zhihupe.com/tool/index.*','wenku.zhihupe.com/#.*'],
initFunc:zhihuWenkuInit
}
]
//生成正则表达式
function createReg(arr){
return new RegExp(arr.join('|'))
}
//根据网址匹配
for (const site of siteMap) {
let reg = createReg(site.match)
let host = window.location.hostname + window.location.pathname
let result = reg.test(host)
if(result){
let platform = site.platform||'';
return site.initFunc(platform);
}
}
// Your code here...
})();;