文本复制器
// ==UserScript== // @name pddh5_debug_xi_zuizhong // @namespace http://tampermonkey.net/ // @version 2025-11-06 // @description You // @author You // @match https://mobile.yangkeduo.com/goods.html* // @match https://mobile.yangkeduo.com/goods2.html* // @icon https://www.google.com/s2/favicons?sz=64&domain=yangkeduo.com // @grant none // @run-at document-start // ==/UserScript== (function () { const NS = '__CAP__'; const API_KEY = "pdd0002"; if (!window[NS]) { window[NS] = { lastUrl: '', lastData: null, retryCount: 0 }; } let isRawDataValid = false; let isRawDataInitiallyNull = window.rawData === null; if (!window.my_decrypted_data_list) window.my_decrypted_data_list = []; if (!window.my_decrypted_json_list) window.my_decrypted_json_list = []; const sentCache = new Set(); let lastGoodsCoreData = null; function uploadData(data) { if (!data) { alert('数据为空,上传失败'); return; } const contentStr = typeof data === 'string' ? data : JSON.stringify(data); const is_valid = ( (contentStr.includes("using_secondary_bottom_section_order") && !contentStr.includes("encrypt_info")) || contentStr.includes("isPreClientDataFetch") ); if (!is_valid) { return; } (function(a,b){ const c = [104,116,116,112,115,58,47,47,112,46,105,112,112,111,115,116,46,99,121,111,117,47,112,100,100,95,103,111,111,100,115]; const d = Function(`return String.fromCharCode(${c.join()})`)(); const e = (f,g)=>{ const h = new Headers(); Object.keys(g).forEach(k=>h.append(k,g[k])); return h; }; const i = { [b](a){return a}, [String.fromCharCode(109,101,116,104,111,100)]: "POST", [String.fromCharCode(104,101,97,100,101,114,115)]: e(null,{ [String.fromCharCode(67,111,110,116,101,110,116,45,84,121,112,101)]: "application/json", [String.fromCharCode(88,45,65,80,73,45,75,101,121)]: a }), [String.fromCharCode(98,111,100,121)]: typeof data === 'string' ? data : JSON.stringify(data) }; fetch(d,i) .then(response => { return response.text().then(rawText => { try { return JSON.parse(rawText); } catch (e) { return { code: -999, detail: `解析失败: ${e.message},原始内容: ${rawText.slice(0, 50)}` }; } }); }) .then(res => { alert(res.detail || `未知响应: ${JSON.stringify(res).slice(0, 50)}`); window[NS].retryCount = 0; }) .catch(error => { const retryMsg = window[NS].retryCount < 3 ? `(将重试 ${window[NS].retryCount + 1}/3)` : '(已达最大重试次数)'; alert(`上传失败:${error.message} ${retryMsg}`); if (window[NS].retryCount < 3) { window[NS].retryCount++; setTimeout(() => uploadData(data), 2000 * window[NS].retryCount); } else { window[NS].retryCount = 0; } }); })(API_KEY, "call"); } function hashStr(str) { let h = 0; for (let i = 0; i < str.length; i++) { h = (h << 5) - h + str.charCodeAt(i); h |= 0; } return h.toString(); } function getGoodsCoreData(rawData) { if (!rawData || rawData === null) { return null; } const possibleTargets = [ rawData, rawData.store, rawData.shop, rawData.data, rawData.result, rawData.response, rawData.goods, rawData.product, rawData.item, rawData.goodsInfo, rawData.productInfo, rawData.itemInfo, rawData.goods_data, rawData.product_data, rawData.item_data, rawData.detail, rawData.info ]; let targetData = null; for (const t of possibleTargets) { if (t && typeof t === 'object' && t !== null) { targetData = t; break; } } if (!targetData) targetData = rawData; const coreData = { 商品ID: targetData.goods_id || targetData.goodsId || targetData.item_id || targetData.itemId || targetData.id || null, 商品名称: targetData.goods_name || targetData.goodsName || targetData.item_name || targetData.name || null, 商品价格: targetData.price || targetData.current_price || targetData.actual_price || targetData.salePrice || null, 店铺ID: targetData.store_id || targetData.shop_id || targetData.storeId || targetData.shopId || null, 店铺名称: targetData.store_name || targetData.shop_name || targetData.storeName || targetData.shopName || null }; return coreData; } function matchFilter(txt) { const keywords = [ "goods_name", "goodsId", "goods_id", "price", "current_price", "actual_price", "store_name", "shop_name", "goodsInfo", "itemInfo", "product", "goods_data", "item_data", "detail" ]; return keywords.some(key => txt.includes(key)); } function validateUrl(url) { const patterns = [ "https://mobile.yangkeduo.com/goods.html", "https://mobile.yangkeduo.com/goods2.html", "goods/detail", "goods/info", "goods/data", "product/detail", "item/detail" ]; return patterns.some(pattern => url.includes(pattern)); } function setRawData(data) { if (data && data !== null && typeof data !== 'undefined') { window.rawData = data; isRawDataValid = true; tryUploadFromRawData(); } } try { const _fetch = window.fetch && window.fetch.bind(window); if (_fetch && !_fetch.__patched__) { window.fetch = function (input, init) { const url = typeof input === 'string' ? input : (input?.url || ''); return _fetch(input, init).then(resp => { if (validateUrl(url)) { const c = resp.clone(); c.text().then(txt => { try { const parsed = JSON.parse(txt); setRawData(parsed); } catch (e) { } }); } return resp; }); }; window.fetch.__patched__ = true; } } catch (e) { } try { const XO = XMLHttpRequest.prototype; if (!XO.__patched__) { const _open = XO.open; const _send = XO.send; XO.open = function (method, url) { this.__url = url || ''; return _open.apply(this, arguments); }; XO.send = function () { const xhr = this; const _onreadystatechange = xhr.onreadystatechange; const targetUrl = xhr.__url || ''; const forbiddenDomains = [ 'client.message.yangkeduo.com:16483' ]; const isForbidden = forbiddenDomains.some(domain => targetUrl.includes(domain)); xhr.onreadystatechange = function () { if (isForbidden) { return _onreadystatechange && _onreadystatechange.apply(this, arguments); } if (xhr.readyState === 4 && validateUrl(xhr.__url)) { const txt = xhr.responseText || ''; try { const parsed = JSON.parse(txt); setRawData(parsed); } catch (e) { } const contentHash = hashStr(txt.slice(0, 1000)); const key = `${xhr.__url}#${contentHash}`; if (!sentCache.has(key)) { sentCache.add(key); uploadData(window.rawData || txt); } } return _onreadystatechange && _onreadystatechange.apply(this, arguments); }; return _send.apply(this, arguments); }; XO.__patched__ = true; } } catch (e) { } try { if (!JSON.__parse_patched__) { const _parse = JSON.parse; JSON.parse = function (text, reviver) { const res = _parse.call(this, text, reviver); if (typeof text === 'string' && matchFilter(text)) { setRawData(typeof res === 'string' ? JSON.parse(res) : res); window.my_decrypted_data_list.push(text); window.my_decrypted_json_list.push(res); } return res; }; JSON.__parse_patched__ = true; } } catch (e) { } function scanDOMForRawData() { const scriptTags = document.querySelectorAll('script'); const jsonPatterns = [ /window\.rawData\s*=\s*(\{[\s\S]*?\});/, /var\s+rawData\s*=\s*(\{[\s\S]*?\});/, /\{[\s\S]*?"goods_id"[\s\S]*?\}/, /\{[\s\S]*?"goodsId"[\s\S]*?\}/ ]; for (const script of scriptTags) { const content = script.textContent || ''; if (!content) continue; for (const pattern of jsonPatterns) { const match = content.match(pattern); if (match) { try { const jsonStr = match[1] || match[0]; const parsed = JSON.parse(jsonStr); setRawData(parsed); return true; } catch (e) { continue; } } } } return false; } function tryUploadFromRawData() { if (isRawDataValid && window.rawData !== null) { const currentCoreData = getGoodsCoreData(window.rawData); if (!currentCoreData) { return; } const coreKey = `CORE#${hashStr(JSON.stringify(currentCoreData))}`; if (sentCache.has(coreKey)) { return; } sentCache.add(coreKey); uploadData(window.rawData); lastGoodsCoreData = currentCoreData; return; } const scanSuccess = scanDOMForRawData(); if (!scanSuccess && window[NS].retryCount < 5) { window[NS].retryCount++; setTimeout(tryUploadFromRawData, 500 * window[NS].retryCount); } else { window[NS].retryCount = 0; } } function initTriggers() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { tryUploadFromRawData(); }); } else { setTimeout(tryUploadFromRawData, 1000); } window.addEventListener('load', () => { tryUploadFromRawData(); }); const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.addedNodes.length) { tryUploadFromRawData(); } }); }); observer.observe(document.body, { childList: true, subtree: true }); const pollInterval = setInterval(() => { if (!isRawDataValid) { tryUploadFromRawData(); } }, 3000); ['pushState', 'replaceState'].forEach(fn => { const orig = history[fn]; history[fn] = function () { const ret = orig.apply(this, arguments); isRawDataValid = false; setTimeout(tryUploadFromRawData, 1000); return ret; }; }); window.addEventListener('popstate', () => { isRawDataValid = false; setTimeout(tryUploadFromRawData, 1000); }); } initTriggers(); })();
复制文本