mirror of
https://github.com/KingJin-web/zy.git
synced 2026-11-05 23:26:43 +08:00
first commit
This commit is contained in:
1 parent
be740b0740
commit
effb805115
4 files changed
+1351
-94
No files matched your search
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* ------------------------------------------
|
||||
* @Description: 测试
|
||||
* const $ = new Env('快手极速')
|
||||
* cron: 0 30 8,10,12,16,18,20,22 * * ?
|
||||
* ------------------------------------------
|
||||
* #Notice:
|
||||
* APP CK的版本最少要是13.5以上,14版本以下
|
||||
* 变量名字:ksjsck 默认执行看广告版本 一次执行30次
|
||||
* 开宝箱ck#salt#socks://用户名:密码@IP:端口 不写代理就是默认本地网络 报错503和脚本没关系
|
||||
* socks:// 或者 socks5:// 哪个不报错写哪个
|
||||
* 变量名字 kstask='look,food,box'
|
||||
*
|
||||
* 自定义接口变量 ksjs_api 例如 http://192.168.2.1:8888
|
||||
* 自定义接口搭建教程 https://mp.weixin.qq.com/s/QCpnK8scCmG69lLm3xg9XA
|
||||
* 所需依赖
|
||||
* socks-proxy-agent@7.0.0
|
||||
* axios
|
||||
* request
|
||||
* smallfawn
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
|
||||
console.log("所需依赖:socks-proxy-agent@7.0.0\n" +
|
||||
"axios\n" +
|
||||
"request\n" +
|
||||
"smallfawn")
|
||||
|
||||
var _0xodK='jsjiami.com.v7';const _0x326197=_0x1d0e;(function(_0x37e714,_0x2fe52a,_0x2b73f5,_0x4759d8,_0x3a9c1e,_0x22db40,_0x2b0d7d){return _0x37e714=_0x37e714>>0x7,_0x22db40='hs',_0x2b0d7d='hs',function(_0x334770,_0x5d640a,_0x4b25d6,_0x30686e,_0x4536d5){const _0x1a29ae=_0x1d0e;_0x30686e='tfi',_0x22db40=_0x30686e+_0x22db40,_0x4536d5='up',_0x2b0d7d+=_0x4536d5,_0x22db40=_0x4b25d6(_0x22db40),_0x2b0d7d=_0x4b25d6(_0x2b0d7d),_0x4b25d6=0x0;const _0x5cc49d=_0x334770();while(!![]&&--_0x4759d8+_0x5d640a){try{_0x30686e=parseInt(_0x1a29ae(0x5e3,'dci2'))/0x1*(-parseInt(_0x1a29ae(0x85a,'*CJ$'))/0x2)+-parseInt(_0x1a29ae(0x50d,'X!PL'))/0x3+-parseInt(_0x1a29ae(0x2f7,'KQTN'))/0x4+parseInt(_0x1a29ae(0x601,'z9B7'))/0x5*(parseInt(_0x1a29ae(0x97e,'1ayM'))/0x6)+-parseInt(_0x1a29ae(0x752,'kFhi'))/0x7*(-parseInt(_0x1a29ae(0x9b6,'@@X$'))/0x8)+parseInt(_0x1a29ae(0x459,'dci2'))/0x9*(parseInt(_0x1a29ae(0x99c,'z9B7'))/0xa)+parseInt(_0x1a29ae(0x621,'kFhi'))/0xb;}catch(_0xcf82b){_0x30686e=_0x4b25d6;}finally{_0x4536d5=_0x5cc49d[_0x22db40]();if(_0x37e714<=_0x4759d8)_0x4b25d6?_0x3a9c1e?_0x30686e=_0x4536d5:_0x3a9c1e=_0x4536d5:_0x4b25d6=_0x4536d5;else{if(_0x4b25d6==_0x3a9c1e['replace'](/[pGtVLXuDRBJwIfFHNbW=]/g,'')){if(_0x30686e===_0x5d640a){_0x5cc49d['un'+_0x22db40](_0x4536d5);break;}_0x5cc49d[_0x2b0d7d](_0x4536d5);}}}}}(_0x2b73f5,_0x2fe52a,function(_0x5bd7b6,_0x55939d,_0x2764ba,_0x3ee079,_0x3b9ceb,_0x5e2c50,_0x3ba836){return _0x55939d='\x73\x70\x6c\x69\x74',_0x5bd7b6=arguments[0x0],_0x5bd7b6=_0x5bd7b6[_0x55939d](''),_0x2764ba='\x72\x65\x76\x65\x72\x73\x65',_0x5bd7b6=_0x5bd7b6[_0x2764ba]('\x76'),_0x3ee079='\x6a\x6f\x69\x6e',(0x1f76ad,_0x5bd7b6[_0x3ee079](''));});}(0x6000,0x515cf,_0x3cc3,0xc2),_0x3cc3)&&(_0xodK=0x11fe);const qs=require(_0x326197(0x3b8,'6M]i')),axios=require('axios'),querystring=require(_0x326197(0x3b8,'6M]i')),{SocksProxyAgent}=require('socks-proxy-agent'),KS_SIGN_API_URL=process['env'][_0x326197(0x7fa,'J$1x')]||_0x326197(0xb3a,'r)[!'),{getSig56,getSig68}=require('smallfawn');console[_0x326197(0x25d,'dci2')](_0x326197(0x935,'$(p3')+KS_SIGN_API_URL);function generateRandomInteractionMessage(){const _0x1a7c72=_0x326197,_0x2f83be={'KKMOh':_0x1a7c72(0x21e,'NPI2'),'BJpPP':'浏览广告内容','HmGJB':_0x1a7c72(0x697,'$(p3'),'acJLu':_0x1a7c72(0xa33,'@@X$'),'nSKnY':_0x1a7c72(0x65f,'rlxa')},_0x117999=[_0x2f83be[_0x1a7c72(0xaff,'nvT7')],'认真观看中...',_0x2f83be[_0x1a7c72(0xb8e,'QT@!')],_0x2f83be[_0x1a7c72(0x6c2,'@@X$')],'观看视频广告',_0x1a7c72(0x35f,'X!PL'),_0x2f83be['acJLu'],_0x2f83be[_0x1a7c72(0x495,'Mlbr')]];return _0x117999[Math[_0x1a7c72(0x54a,'$ZIy')](Math['random']()*_0x117999['length'])];}function getEnvNumber(_0x2b5fed,_0x335ada){const _0xe0bc96=_0x326197,_0x59dca8={'UFCVj':function(_0x1189a2,_0xfa1790,_0x20c9c3){return _0x1189a2(_0xfa1790,_0x20c9c3);},'CSUoW':function(_0x2c933f,_0x3bae48){return _0x2c933f(_0x3bae48);}},_0x2a1982=_0x59dca8['UFCVj'](parseInt,process[_0xe0bc96(0x9fc,'$(p3')][_0x2b5fed],0xa);return _0x59dca8['CSUoW'](isNaN,_0x2a1982)?_0x335ada:_0x2a1982;}const KSLOW_REWARD_THRESHOLD=getEnvNumber(_0x326197(0x8f9,'5lfq'),0x1),KSROUNDS=getEnvNumber(_0x326197(0x1ec,'jwKp'),0x5),KSCOIN_LIMIT=getEnvNumber(_0x326197(0x956,']HV]'),0x7a120),KSLOW_REWARD_LIMIT=getEnvNumber(_0x326197(0x1b9,'KM^0'),0x1),KSFOLLOW_COUNT=getEnvNumber('KSFOLLOW_COUNT',0x1),KSSEARCHFOLLOW_COUNT=getEnvNumber(_0x326197(0x561,'X!PL'),0x1),KSLOOK_COUNT=getEnvNumber(_0x326197(0xaf4,'ZSyu'),0x5),KSSEARCH_COUNT=getEnvNumber(_0x326197(0x8ac,'1Uu!'),0x5),KS_INVITE_CONFIG_URL=process[_0x326197(0x52e,'wS(Q')]['KS_INVITE_CONFIG_URL']||'https://gitee.com/smallfawn/Note/raw/main/KSConfig.json';let inviteAssistTasks=[],inviteBindTasks=[];function parseInviteTasksFromEnv(_0x3b8aa0){const _0x2d06b1=_0x326197,_0x5b9509={'epVCi':function(_0x3179ba,_0x846ade){return _0x3179ba===_0x846ade;},'FDWtM':_0x2d06b1(0x21c,'AcH3')},_0xb9e9d4=process['env'][_0x3b8aa0];if(!_0xb9e9d4)return null;try{const _0x39ae5e=JSON['parse'](_0xb9e9d4);if(Array[_0x2d06b1(0x3fa,'r)[!')](_0x39ae5e))return _0x39ae5e;if(_0x39ae5e&&_0x5b9509[_0x2d06b1(0x8a2,'nvT7')](typeof _0x39ae5e,_0x5b9509[_0x2d06b1(0x56f,'kFhi')]))return[_0x39ae5e];}catch(_0x2b177b){}return null;}function parseInviteCodeEntries(){const _0x1557b7=_0x326197,_0x1ca897={'MoihN':function(_0x5bbd41,_0x458fc0){return _0x5bbd41(_0x458fc0);}},_0xf3f724=process[_0x1557b7(0x99f,'Kl4l')]['ksuserinvite']||process['env']['KSUSERINVITE']||process['env'][_0x1557b7(0x893,'6M]i')]||process['env'][_0x1557b7(0x566,'$ZIy')];if(!_0xf3f724)return[];return _0x1ca897[_0x1557b7(0x3a4,'QT@!')](String,_0xf3f724)[_0x1557b7(0x33e,'oeN7')](/[,|&\n]/)[_0x1557b7(0x333,'Xx[1')](_0x3cdd94=>_0x3cdd94[_0x1557b7(0x58e,'jwKp')]())['filter'](Boolean)[_0x1557b7(0x57a,'NPI2')](_0x11d0dc=>({'inviteCode':_0x11d0dc}));}async function loadInviteConfig(){const _0xc64f80=_0x326197,_0x43ee14={'gZOcO':function(_0x3a648b,_0x52676a){return _0x3a648b+_0x52676a;},'NkokY':_0xc64f80(0x569,'1Uu!'),'aTJoS':_0xc64f80(0x76b,'rlxa'),'SpgKa':function(_0x1aef3b,_0x5d8f76){rLine truncated
|
||||
@@ -0,0 +1,853 @@
|
||||
const axios = require("axios");
|
||||
const axios = require("axios");
|
||||
console.log("自定义接口搭建教程 https://mp.weixin.qq.com/s/QCpnK8scCmG69lLm3xg9XA")
|
||||
console.log("最低2.1代理,4.5家庭住宅 http://www.gzsk5.com/#/register?invitation=hnking2&shareid=516")
|
||||
// ==============================================
|
||||
// 签名服务地址(可通过环境变量覆盖)
|
||||
// ==============================================
|
||||
const SIGN_API_KUAISHOU = process.env.kspt_api || "http://119.29.213.95:7779";
|
||||
const SIGN_API_NEBULA = process.env.ksjs_api || "http://119.29.213.95:7778";
|
||||
|
||||
const DEFAULT_TASKS_STR = process.env.KS_DEFAULT_TASKS || "live,lives";
|
||||
const TASKS_TO_RUN = DEFAULT_TASKS_STR.split(",").map(s => s.trim()).filter(Boolean);
|
||||
|
||||
const MAX_LIVES = parseInt(process.env.KS_MAX_LIVES) || 999999;
|
||||
const MAX_CONCURRENT_ACCOUNTS = parseInt(process.env.KS_MAX_CONCURRENT) || 66;
|
||||
|
||||
// 间隔 1-3 秒
|
||||
const MIN_DELAY_SEC = 1;
|
||||
const MAX_DELAY_SEC = 3;
|
||||
|
||||
function randomDelaySeconds() {
|
||||
return Math.floor(Math.random() * (MAX_DELAY_SEC - MIN_DELAY_SEC + 1) + MIN_DELAY_SEC);
|
||||
}
|
||||
function randomDelay() {
|
||||
const seconds = randomDelaySeconds();
|
||||
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
||||
}
|
||||
|
||||
// 繁忙/签名相关常量
|
||||
const MAX_BUSY_INITIAL = 2; // 初始任务繁忙2次后停止该任务
|
||||
const MAX_BUSY_APPEND = 3; // 追加任务繁忙3次后休息5分钟再继续
|
||||
const APPEND_BUSY_BREAK_MS = 5 * 60 * 1000; // 5分钟
|
||||
const MAX_SIGN_FAILURES = 3; // 签名失败3次后停止该账号
|
||||
|
||||
// ==================== 平台配置与双端识别 ====================
|
||||
const PLATFORM_CONFIG = {
|
||||
KUAISHOU: {
|
||||
name: "KS",
|
||||
host: "encourage.kuaishou.com",
|
||||
appId: "kuaishou",
|
||||
packageName: "com.smile.gifmaker",
|
||||
appName: "快手",
|
||||
displayName: "普通版",
|
||||
kpn: "KUAISHOU",
|
||||
adClientKey: "3c2cd3f3",
|
||||
reportClientKey: "3c2cd3f3"
|
||||
},
|
||||
NEBULA: {
|
||||
name: "JSB",
|
||||
host: "nebula.kuaishou.com",
|
||||
appId: "kuaishou_nebula",
|
||||
packageName: "com.kuaishou.nebula",
|
||||
appName: "快手极速版",
|
||||
displayName: "极速版",
|
||||
kpn: "NEBULA",
|
||||
adClientKey: "2ac2a76d",
|
||||
reportClientKey: "2ac2a76d"
|
||||
}
|
||||
};
|
||||
|
||||
function identifyPlatform(cookie) {
|
||||
const match = cookie.match(/kpn=([^;]+)/);
|
||||
const kpn = match ? match[1].toUpperCase() : "KUAISHOU";
|
||||
return kpn === "NEBULA" ? PLATFORM_CONFIG.NEBULA : PLATFORM_CONFIG.KUAISHOU;
|
||||
}
|
||||
|
||||
// ==================== 统一设备参数(基础模板) ====================
|
||||
const DEFAULT_DEVICE_PARAMS_UNIFIED = {
|
||||
earphoneMode: "1",
|
||||
mod: "OnePlus(PKX110)",
|
||||
appver: "14.3.30.11384",
|
||||
isp: "CMCC",
|
||||
language: "zh-cn",
|
||||
did_tag: "0",
|
||||
thermal: "10000",
|
||||
net: "5G",
|
||||
kcv: "1620",
|
||||
app: "0",
|
||||
kpf: "ANDROID_PHONE",
|
||||
bottom_navigation: "true",
|
||||
ver: "14.3",
|
||||
android_os: "0",
|
||||
oDid: "ANDROID_adb1e1653dd085be",
|
||||
boardPlatform: "sun",
|
||||
newOc: "ANDROID_OPPO__LXCPA_CPA_ZGYXZRGSKSKJ_249561%2C1",
|
||||
androidApiLevel: "36",
|
||||
slh: "0",
|
||||
country_code: "cn",
|
||||
nbh: "0",
|
||||
hotfix_ver: "",
|
||||
keyconfig_state: "2",
|
||||
cdid_tag: "2",
|
||||
sys: "ANDROID_16",
|
||||
max_memory: "256",
|
||||
oc: "ANDROID_OPPO__LXCPA_CPA_ZGYXZRGSKSKJ_249561%2C1",
|
||||
sh: "2640",
|
||||
deviceBit: "4",
|
||||
browseType: "3",
|
||||
ddpi: "476",
|
||||
socName: "Qualcomm%20Snapdragon%208750",
|
||||
is_background: "0",
|
||||
c: "ANDROID_OPPO__LXCPA_CPA_ZGYXZRGSKSKJ_249561%2C1",
|
||||
sw: "1216",
|
||||
ftt: "",
|
||||
abi: "arm64",
|
||||
userRecoBit: "0",
|
||||
device_abi: "arm64",
|
||||
icaver: "1",
|
||||
totalMemory: "15107",
|
||||
grant_browse_type: "AUTHORIZED",
|
||||
iuid: "",
|
||||
rdid: "ANDROID_7bc831446e31ac0a",
|
||||
sbh: "135",
|
||||
darkMode: "false"
|
||||
};
|
||||
|
||||
let deviceParamsUnified = { ...DEFAULT_DEVICE_PARAMS_UNIFIED };
|
||||
if (process.env.KS_DEVICE_PARAMS_UNIFIED) {
|
||||
try {
|
||||
const custom = JSON.parse(process.env.KS_DEVICE_PARAMS_UNIFIED);
|
||||
deviceParamsUnified = { ...deviceParamsUnified, ...custom };
|
||||
console.log("✅ 已加载自定义统一设备参数");
|
||||
} catch(e) { console.warn("⚠️ KS_DEVICE_PARAMS_UNIFIED 解析失败"); }
|
||||
}
|
||||
|
||||
// ==================== 任务配置(普通版与极速版区分) ====================
|
||||
const TASK_CONFIGS = {
|
||||
KUAISHOU: {
|
||||
live: { name: "直播广告", businessId: 101, posId: 5226, pageId: 100014023, subPageId: 100014024, requestSceneType: 1, taskType: 1 },
|
||||
lives: { name: "直播广告[追加]", businessId: 101, posId: 5226, pageId: 100014023, subPageId: 100014024, requestSceneType: 7, taskType: 2 }
|
||||
},
|
||||
NEBULA: {
|
||||
live: { name: "直播广告", businessId: 75, posId: 2318, pageId: 100012060, subPageId: 100012061, requestSceneType: 1, taskType: 1 },
|
||||
lives: { name: "直播广告[追加]", businessId: 75, posId: 2318, pageId: 100012060, subPageId: 100012061, requestSceneType: 7, taskType: 2 }
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.KS_TASK_CONFIG) {
|
||||
try {
|
||||
const customTasks = JSON.parse(process.env.KS_TASK_CONFIG);
|
||||
Object.assign(TASK_CONFIGS.KUAISHOU, customTasks.KUAISHOU || {});
|
||||
Object.assign(TASK_CONFIGS.NEBULA, customTasks.NEBULA || {});
|
||||
console.log("✅ 已加载自定义任务配置");
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function createLogger(remark, platformDisplayName) {
|
||||
const prefix = `[${remark}][${platformDisplayName}]`;
|
||||
return (msg) => console.log(`${prefix} ${msg}`);
|
||||
}
|
||||
|
||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
||||
function genRequestId() { return Math.floor(Math.random() * 100000000000000000).toString(); }
|
||||
function getCurrentTimestampMs() { return Date.now(); }
|
||||
function getColdLaunchTimeMs() { return Date.now() - 30 * 1000; }
|
||||
|
||||
function javaUrlEncode(str) {
|
||||
if (str === null || str === undefined) return "";
|
||||
let encoded = encodeURIComponent(str);
|
||||
return encoded.replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/~/g, '%7E').replace(/\*/g, '%2A');
|
||||
}
|
||||
|
||||
function buildSortedParams(obj) {
|
||||
const keys = Object.keys(obj).sort();
|
||||
const parts = [];
|
||||
for (let key of keys) {
|
||||
if (obj[key] !== undefined && obj[key] !== null && obj[key] !== "") {
|
||||
parts.push(`${javaUrlEncode(key)}=${javaUrlEncode(obj[key])}`);
|
||||
}
|
||||
}
|
||||
return parts.join('&');
|
||||
}
|
||||
|
||||
function getBase64NoWrap(obj) {
|
||||
return Buffer.from(JSON.stringify(obj)).toString('base64').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
async function getNsSign(reqInfo, kpnType, remark, logFn) {
|
||||
const SIGN_API_URL = kpnType === "NEBULA" ? SIGN_API_NEBULA : SIGN_API_KUAISHOU;
|
||||
try {
|
||||
const payload = { path: reqInfo.urlpath, data: reqInfo.reqdata, salt: reqInfo.salt };
|
||||
const resp = await axios.post(SIGN_API_URL + "/nssig", payload, { headers: { "Content-Type": "application/json" }, timeout: 15000 });
|
||||
if (resp.data && resp.data.data) {
|
||||
return { sig: resp.data.data.sig, nstokensig: resp.data.data.nstokensig, sig3: resp.data.data.nssig3, xfalcon: resp.data.data.nssig4 || resp.data.data.xfalcon || "" };
|
||||
}
|
||||
logFn(`❌ 签名服务无响应: ${resp.data?.message || '未知错误'}`);
|
||||
return null;
|
||||
} catch (e) {
|
||||
logFn(`❌ 签名服务异常: ${e.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 解析 liveInspireAwardInfo 实现翻倍 ====================
|
||||
function getExpectedCoins(feed) {
|
||||
try {
|
||||
let inspireInfo = null;
|
||||
const ad = feed.ad || feed.adInfo || {};
|
||||
if (feed.liveInspireAwardInfo) inspireInfo = feed.liveInspireAwardInfo;
|
||||
else if (ad.liveInspireAwardInfo) inspireInfo = ad.liveInspireAwardInfo;
|
||||
else if (feed.adExtInfo && feed.adExtInfo.liveInspireAwardInfo) inspireInfo = feed.adExtInfo.liveInspireAwardInfo;
|
||||
|
||||
if (inspireInfo && inspireInfo.enableLiveInspireAwardCoinMultiple === true) {
|
||||
const multipliedAmount = inspireInfo.liveInspireAwardCoinAmount;
|
||||
const multiple = inspireInfo.liveInspireAwardCoinMultiple;
|
||||
const baseCoin = inspireInfo.liveInspireAwardCoinCount;
|
||||
if (multipliedAmount && multipliedAmount > 0) {
|
||||
return { coins: multipliedAmount, multiple: multiple, baseCoin: baseCoin };
|
||||
}
|
||||
}
|
||||
|
||||
let extData = ad.extData || ad.adExtInfo || "{}";
|
||||
if (typeof extData === "string") extData = JSON.parse(extData);
|
||||
const awardCoin = extData.awardCoin || extData.coinAmount;
|
||||
if (awardCoin) {
|
||||
return { coins: parseInt(awardCoin) || 0, multiple: 1, baseCoin: parseInt(awardCoin) };
|
||||
}
|
||||
return { coins: 0, multiple: 1, baseCoin: 0 };
|
||||
} catch (e) {
|
||||
return { coins: 0, multiple: 1, baseCoin: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
function getMaterialTime(feed) {
|
||||
try {
|
||||
const ad = feed.ad || feed.adInfo || {};
|
||||
let extData = ad.extData || ad.adExtInfo || "{}";
|
||||
if (typeof extData === "string") extData = JSON.parse(extData);
|
||||
if (extData.materialTime) return parseInt(extData.materialTime);
|
||||
if (ad.materialTime) return parseInt(ad.materialTime);
|
||||
if (feed.materialTime) return parseInt(feed.materialTime);
|
||||
return 30;
|
||||
} catch (e) {
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
||||
class LiveAdTask {
|
||||
constructor(remark, cookie, salt) {
|
||||
this.remark = remark;
|
||||
this.cookie = cookie;
|
||||
this.salt = salt;
|
||||
|
||||
this.platform = identifyPlatform(cookie);
|
||||
this.kpn = this.platform.kpn;
|
||||
this.clientKey = this.platform.adClientKey;
|
||||
this.reportClientKey = this.platform.reportClientKey;
|
||||
|
||||
this.log = createLogger(remark, this.platform.displayName);
|
||||
|
||||
this.commonQuery = {};
|
||||
this.parseCookie();
|
||||
this.totalCoins = 0;
|
||||
this.adCreativeId = "";
|
||||
this.adId = "";
|
||||
this.llsid = "";
|
||||
this.feedId = "";
|
||||
this.appendCount = 0;
|
||||
this.h5ExtParams = Array.from({length: 96}, () => Math.floor(Math.random() * 256).toString(16).padStart(2, '0')).join('');
|
||||
|
||||
this.signFailCount = 0;
|
||||
}
|
||||
|
||||
parseCookie() {
|
||||
const extract = (key) => {
|
||||
const match = this.cookie.match(new RegExp(`(?:^|;\\s*)${key}=([^;]+)`));
|
||||
return match ? match[1] : '';
|
||||
};
|
||||
this.ud = extract("ud") || extract("userId") || "5488265105";
|
||||
this.did = extract("did") || "ANDROID_69242cf0063156fb";
|
||||
this.egid = extract("egid") || "DFPDE403E8A579BEFAFC60555A643E4BF281B64D188636A0157CBEE7B9D55016";
|
||||
this.api_st = extract("kuaishou.api_st");
|
||||
this.token = extract("token");
|
||||
|
||||
let cookieAppver = extract("appver");
|
||||
this.appver = cookieAppver && cookieAppver.trim() !== "" ? cookieAppver : deviceParamsUnified.appver;
|
||||
this.log(`📱 使用appver: ${this.appver} (来源: ${cookieAppver ? "cookie" : "默认"})`);
|
||||
|
||||
const nowMs = getCurrentTimestampMs();
|
||||
const did_gt = extract("did_gt") || (nowMs - 60000).toString();
|
||||
const coldLaunch = getColdLaunchTimeMs();
|
||||
|
||||
this.commonQuery = { ...deviceParamsUnified };
|
||||
this.commonQuery.appver = this.appver;
|
||||
this.commonQuery.ud = this.ud;
|
||||
this.commonQuery.did = this.did;
|
||||
this.commonQuery.egid = this.egid;
|
||||
this.commonQuery.kpn = this.kpn;
|
||||
this.commonQuery.did_gt = did_gt;
|
||||
this.commonQuery.cold_launch_time_ms = coldLaunch.toString();
|
||||
|
||||
const rdidFromCookie = extract("rdid");
|
||||
if (rdidFromCookie) this.commonQuery.rdid = rdidFromCookie;
|
||||
const oDidFromCookie = extract("oDid");
|
||||
if (oDidFromCookie) this.commonQuery.oDid = oDidFromCookie;
|
||||
}
|
||||
|
||||
getNeoParamsBase64(config) {
|
||||
const obj = {
|
||||
pageId: config.pageId, subPageId: config.subPageId, posId: 0, businessId: config.businessId,
|
||||
extParams: this.h5ExtParams,
|
||||
customData: { exitInfo: { toastDesc: null, toastImgUrl: null } },
|
||||
pendantType: 1, displayType: 1, singlePageId: 100011291, singleSubPageId: 100011292,
|
||||
channel: 0, countdownReport: true, themeType: 0, mixedAd: false, fullMixed: false,
|
||||
autoReport: true, fromTaskCenter: true, searchInspireSchemeInfo: null, amount: 0, slideNeoInfo: null
|
||||
};
|
||||
return getBase64NoWrap(obj);
|
||||
}
|
||||
|
||||
async doRequest(urlPath, formObj, pageCode, title, extraHeaders = {}) {
|
||||
const allParams = { ...this.commonQuery, ...formObj };
|
||||
const sortedData = buildSortedParams(allParams);
|
||||
const sign = await getNsSign({ urlpath: urlPath, reqdata: sortedData, salt: this.salt }, this.kpn, this.remark, this.log);
|
||||
if (!sign) {
|
||||
this.log("❌ 签名服务异常,本次请求签名失败");
|
||||
return { ok: false, signFailed: true };
|
||||
}
|
||||
const queryWithSign = buildSortedParams({
|
||||
...this.commonQuery, sig: sign.sig, __NS_sig3: sign.sig3, __NS_xfalcon: sign.xfalcon, __NStokensig: sign.nstokensig
|
||||
});
|
||||
const fullUrl = `https://api.e.kuaishou.com${urlPath}?${queryWithSign}`;
|
||||
const bodyStr = buildSortedParams(formObj);
|
||||
|
||||
try {
|
||||
const headers = {
|
||||
"Cookie": this.cookie, "User-Agent": "kwai-android aegon/4.41.0",
|
||||
"Content-Type": "application/x-www-form-urlencoded", "X-REQUESTID": genRequestId(),
|
||||
"page-code": pageCode, "X-Client-Info": "model=23013RK75C;os=Android;nqe-score=32;network=5G;signal-strength=1;",
|
||||
"Host": "api.e.kuaishou.com", "Connection": "keep-alive",
|
||||
...extraHeaders
|
||||
};
|
||||
const resp = await axios.post(fullUrl, bodyStr, { headers, timeout: 10000 });
|
||||
return { ok: true, data: resp.data, signFailed: false };
|
||||
} catch (e) {
|
||||
this.log(`❌ ${title} 异常: ${e.message}`);
|
||||
return { ok: false, signFailed: false };
|
||||
}
|
||||
}
|
||||
|
||||
handleSignFailure() {
|
||||
this.signFailCount++;
|
||||
this.log(`⚠️ 签名失败 (${this.signFailCount}/${MAX_SIGN_FAILURES})`);
|
||||
if (this.signFailCount >= MAX_SIGN_FAILURES) {
|
||||
this.log(`🚫 连续 ${MAX_SIGN_FAILURES} 次签名失败,停止该账号所有任务`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 强制翻页:固定请求 maxPages 次,忽略 pcursor 的 "no_more" 或空值
|
||||
async getAdTask(config, isAppend) {
|
||||
const maxRetries = 3;
|
||||
const maxPages = 8; // 强制翻页次数(固定请求8次)
|
||||
const urlPath = (this.kpn === "NEBULA") ? "/rest/nebula/fanstop/earnCoin" : "/rest/n/fanstop/earnCoin";
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
let pcursor = "";
|
||||
|
||||
for (let page = 1; page <= maxPages; page++) {
|
||||
const formObj = {
|
||||
awardType: "2", pcursor: pcursor, refreshTimes: "1", recoReportContext: "",
|
||||
neoParams: this.getNeoParamsBase64(config), requestSceneType: String(config.requestSceneType),
|
||||
videoModelCrowdTag: "", os: "android", cs: "false", client_key: this.clientKey,
|
||||
"kuaishou.api_st": this.api_st, uQaTag: "1%23%23DP%3Anull%23ecBl%3A00%23ecPp%3A--%23cmNt%3A11"
|
||||
};
|
||||
if (this.token) formObj.token = this.token;
|
||||
const { ok, data: res, signFailed } = await this.doRequest(urlPath, formObj, "LIVE_WATCH", `获取${config.name}流`);
|
||||
|
||||
if (signFailed) {
|
||||
if (this.handleSignFailure()) return null;
|
||||
else return null;
|
||||
}
|
||||
if (!ok || !res) return null;
|
||||
|
||||
// 尝试在返回结果中寻找有效广告
|
||||
if (res.result === 1 && res.feeds && res.feeds.length > 0) {
|
||||
let targetFeed = null, creativeId = null;
|
||||
for (let feed of res.feeds) {
|
||||
let cid = feed.creativeId || (feed.ad && feed.ad.creativeId) || (feed.adInfo && feed.adInfo.creativeId);
|
||||
if (cid) { targetFeed = feed; creativeId = cid; break; }
|
||||
}
|
||||
if (targetFeed) {
|
||||
const adObj = targetFeed.ad || targetFeed.adInfo || {};
|
||||
this.adId = adObj.adId || adObj.sourceId || adObj.id || "";
|
||||
this.adCreativeId = creativeId;
|
||||
this.llsid = targetFeed.llsid || "";
|
||||
if (!this.llsid && adObj) this.llsid = adObj.llsid || "";
|
||||
|
||||
let liveStreamId = null;
|
||||
let inspireTaskId = "";
|
||||
let adExtInfo = "";
|
||||
let jingleBellId = "";
|
||||
let neoParamsBase64 = "";
|
||||
let neoExtParams = "";
|
||||
|
||||
try {
|
||||
let extDataStr = "";
|
||||
if (adObj.extData) extDataStr = adObj.extData;
|
||||
else if (targetFeed.extData) extDataStr = targetFeed.extData;
|
||||
if (extDataStr) {
|
||||
const extData = JSON.parse(extDataStr);
|
||||
liveStreamId = extData.liveStreamId;
|
||||
inspireTaskId = extData.inspireTaskId || extData.taskId || "";
|
||||
jingleBellId = extData.jingleBellId || "";
|
||||
adExtInfo = extDataStr;
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
if (this.kpn === "NEBULA") {
|
||||
try {
|
||||
if (adObj.adExtInfo && typeof adObj.adExtInfo === 'string' && !adObj.adExtInfo.startsWith('{')) {
|
||||
adExtInfo = adObj.adExtInfo;
|
||||
} else if (targetFeed.adExtInfo && typeof targetFeed.adExtInfo === 'string' && !targetFeed.adExtInfo.startsWith('{')) {
|
||||
adExtInfo = targetFeed.adExtInfo;
|
||||
} else if (adObj.adDataV2 && adObj.adDataV2.inspireAdInfo && adObj.adDataV2.inspireAdInfo.adExtInfo) {
|
||||
adExtInfo = adObj.adDataV2.inspireAdInfo.adExtInfo;
|
||||
}
|
||||
if (adObj.adDataV2 && adObj.adDataV2.inspireAdInfo && adObj.adDataV2.inspireAdInfo.neoParams) {
|
||||
neoParamsBase64 = adObj.adDataV2.inspireAdInfo.neoParams;
|
||||
const neoParamsObj = JSON.parse(Buffer.from(neoParamsBase64, 'base64').toString('utf8'));
|
||||
neoExtParams = neoParamsObj.extParams || "";
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
this.feedId = liveStreamId ? String(liveStreamId) : (targetFeed.photoId || "未知feedId");
|
||||
const { coins: expectedCoins, multiple, baseCoin } = getExpectedCoins(targetFeed);
|
||||
const materialTime = getMaterialTime(targetFeed);
|
||||
|
||||
if (multiple > 1) {
|
||||
this.log(`✨ 触发翻倍奖励!基础 ${baseCoin} 金币 × ${multiple} 倍 = ${expectedCoins} 金币`);
|
||||
}
|
||||
// 找到广告立即返回,不继续翻页
|
||||
return {
|
||||
creativeId: this.adCreativeId,
|
||||
feedId: this.feedId,
|
||||
llsid: this.llsid,
|
||||
adExtInfo,
|
||||
materialTime,
|
||||
inspireTaskId,
|
||||
adId: this.adId,
|
||||
jingleBellId,
|
||||
expectedCoins,
|
||||
multiple,
|
||||
neoParamsBase64,
|
||||
neoExtParams
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 强制翻页:无论返回的 pcursor 是什么,都取返回值作为下一页的 pcursor(若无效则置空)
|
||||
const nextCursor = res?.pcursor;
|
||||
pcursor = (nextCursor && nextCursor !== "") ? nextCursor : "";
|
||||
// 翻页间隔(随机 1-3 秒)
|
||||
await randomDelay();
|
||||
}
|
||||
|
||||
// 强制翻页 maxPages 次后未找到广告,尝试外层重试
|
||||
if (attempt < maxRetries) {
|
||||
this.log(`⚠️ 第 ${attempt} 次刷新广告池失败(已强制翻页 ${maxPages} 次),${maxRetries - attempt} 秒后重试...`);
|
||||
await randomDelay();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async startTask(adTask, config) {
|
||||
const formObj = {
|
||||
pageId: "0", subPageId: "0", neoStatus: "1",
|
||||
neoParams: (this.kpn === "NEBULA" && adTask.neoParamsBase64) ? adTask.neoParamsBase64 : this.getNeoParamsBase64(config),
|
||||
h5NeoParams: this.getNeoParamsBase64(config),
|
||||
liveStreamId: adTask.feedId,
|
||||
feedId: adTask.feedId,
|
||||
llsid: adTask.llsid,
|
||||
creativeId: adTask.creativeId,
|
||||
taskType: String(config.taskType),
|
||||
videoModelCrowdTag: "",
|
||||
os: "android",
|
||||
cs: "false",
|
||||
client_key: this.clientKey,
|
||||
"kuaishou.api_st": this.api_st,
|
||||
uQaTag: "1%23%23DP%3Anull%23ecBl%3A00%23ecPp%3A--%23cmNt%3A11"
|
||||
};
|
||||
if (this.token) formObj.token = this.token;
|
||||
const { ok, data: res, signFailed } = await this.doRequest("/rest/r/neo/summary", formObj, "LIVE_WATCH", "初始化观看");
|
||||
if (signFailed) {
|
||||
if (this.handleSignFailure()) throw new Error("ACCOUNT_STOP");
|
||||
return false;
|
||||
}
|
||||
if (ok && res && res.result === 1) {
|
||||
if (this.kpn === "NEBULA" && res.data && (res.data.taskFinished || res.data.currentTaskFinished)) {
|
||||
this.log(`⚠️ 当天任务已完成,跳过上报`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async reportTask(adTask, watchDuration, config) {
|
||||
const nowMs = Date.now();
|
||||
const startTime = nowMs - watchDuration * 1000;
|
||||
const endTime = nowMs;
|
||||
const sessionId = `adNeo-${this.ud}-${config.subPageId}-${startTime}`;
|
||||
|
||||
if (this.kpn === "NEBULA") {
|
||||
const extInfoObj = {
|
||||
businessId: config.businessId,
|
||||
extParams: adTask.neoExtParams || "",
|
||||
pageId: config.pageId,
|
||||
subPageId: config.subPageId
|
||||
};
|
||||
const bizStrObj = {
|
||||
businessId: config.businessId,
|
||||
endTime: endTime,
|
||||
extParams: this.h5ExtParams,
|
||||
mediaScene: "live",
|
||||
neoInfos: [{
|
||||
creativeId: Number(this.adCreativeId),
|
||||
extInfo: getBase64NoWrap(extInfoObj),
|
||||
feedId: adTask.feedId,
|
||||
llsid: Number(adTask.llsid),
|
||||
adExtInfo: adTask.adExtInfo || "",
|
||||
materialTime: 0,
|
||||
watchAdTime: 30000,
|
||||
requestSceneType: config.requestSceneType,
|
||||
taskType: config.taskType,
|
||||
watchExpId: "",
|
||||
watchStage: 0
|
||||
}],
|
||||
pageId: config.pageId,
|
||||
posId: config.posId,
|
||||
reportType: 0,
|
||||
sessionId: sessionId,
|
||||
startTime: startTime,
|
||||
subPageId: config.subPageId
|
||||
};
|
||||
const formObj = {
|
||||
bizStr: JSON.stringify(bizStrObj),
|
||||
cs: "false",
|
||||
client_key: this.reportClientKey,
|
||||
videoModelCrowdTag: "",
|
||||
os: "android",
|
||||
"kuaishou.api_st": this.api_st,
|
||||
uQaTag: "1%23%23DP%3Anull%23ecBl%3A00%23ecPp%3A--%23cmNt%3A11"
|
||||
};
|
||||
if (this.token) formObj.token = this.token;
|
||||
const { ok, data: res, signFailed } = await this.doRequest("/rest/r/ad/task/report", formObj, "LIVE_WATCH", "上报任务");
|
||||
if (signFailed) {
|
||||
if (this.handleSignFailure()) throw new Error("ACCOUNT_STOP");
|
||||
return { success: false, amount: 0, busy: false, signFailed: true };
|
||||
}
|
||||
if (!ok) return { success: false, amount: 0, busy: false };
|
||||
if (res.result === 1) {
|
||||
const amount = res.data?.neoAmount || 0;
|
||||
return { success: true, amount, busy: false };
|
||||
} else {
|
||||
const msg = res.error_msg || "";
|
||||
const isBusy = (res.result === -1 && (msg.includes("忙") || msg.includes("frequency") || msg.includes("限流"))) ||
|
||||
msg.includes("内部系统繁忙") || msg.includes("系统繁忙") || res.result === 500;
|
||||
return { success: false, amount: 0, busy: isBusy };
|
||||
}
|
||||
} else {
|
||||
const extInfoObj = {
|
||||
businessId: config.businessId,
|
||||
extParams: "",
|
||||
pageId: config.pageId,
|
||||
subPageId: config.subPageId,
|
||||
posId: config.posId,
|
||||
adId: this.adId,
|
||||
creativeId: this.adCreativeId,
|
||||
feedId: adTask.feedId,
|
||||
inspireTaskId: String(adTask.inspireTaskId || ""),
|
||||
jingleBellId: adTask.jingleBellId || "",
|
||||
materialTime: adTask.materialTime,
|
||||
watchAdTime: adTask.materialTime
|
||||
};
|
||||
const bizStrObj = {
|
||||
businessId: config.businessId,
|
||||
endTime: endTime,
|
||||
extParams: "",
|
||||
mediaScene: "live",
|
||||
neoInfos: [{
|
||||
adId: this.adId,
|
||||
creativeId: this.adCreativeId,
|
||||
extInfo: getBase64NoWrap(extInfoObj),
|
||||
feedId: adTask.feedId,
|
||||
llsid: adTask.llsid,
|
||||
adExtInfo: adTask.adExtInfo || "",
|
||||
inflow: true,
|
||||
materialTime: adTask.materialTime,
|
||||
watchAdTime: adTask.materialTime,
|
||||
requestSceneType: config.requestSceneType,
|
||||
taskType: config.taskType,
|
||||
watchExpId: "",
|
||||
watchStage: 0,
|
||||
inspireTaskId: String(adTask.inspireTaskId || "")
|
||||
}],
|
||||
pageId: config.pageId,
|
||||
posId: config.posId,
|
||||
reportType: 0,
|
||||
sessionId: sessionId,
|
||||
startTime: startTime,
|
||||
subPageId: config.subPageId
|
||||
};
|
||||
const formObj = {
|
||||
bizStr: JSON.stringify(bizStrObj),
|
||||
cs: "false",
|
||||
client_key: this.reportClientKey,
|
||||
videoModelCrowdTag: "",
|
||||
os: "android",
|
||||
"kuaishou.api_st": this.api_st,
|
||||
uQaTag: "1%23%23DP%3Anull%23ecBl%3A00%23ecPp%3A--%23cmNt%3A11"
|
||||
};
|
||||
if (this.token) formObj.token = this.token;
|
||||
const { ok, data: res, signFailed } = await this.doRequest("/rest/r/ad/task/report", formObj, "LIVE_WATCH", "上报任务");
|
||||
if (signFailed) {
|
||||
if (this.handleSignFailure()) throw new Error("ACCOUNT_STOP");
|
||||
return { success: false, amount: 0, busy: false, signFailed: true };
|
||||
}
|
||||
if (!ok) return { success: false, amount: 0, busy: false };
|
||||
if (res.result === 1) {
|
||||
const amount = res.data?.neoAmount || 0;
|
||||
return { success: true, amount, busy: false };
|
||||
} else {
|
||||
const msg = res.error_msg || "";
|
||||
const isBusy = (res.result === -1 && (msg.includes("忙") || msg.includes("frequency") || msg.includes("限流"))) ||
|
||||
msg.includes("内部系统繁忙") || msg.includes("系统繁忙") || res.result === 500;
|
||||
if (isBusy) {
|
||||
this.log(`⚠️ 上报内部繁忙: ${msg || 'code '+res.result}`);
|
||||
} else {
|
||||
this.log(`❌ 上报失败: ${msg || '未知错误'} (${res.result})`);
|
||||
}
|
||||
return { success: false, amount: 0, busy: isBusy };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async runInitial(config) {
|
||||
try {
|
||||
let adTask = null;
|
||||
for (let refresh = 1; refresh <= 99; refresh++) {
|
||||
adTask = await this.getAdTask(config, false);
|
||||
if (adTask) {
|
||||
if (refresh > 1) {
|
||||
this.log(`✅ 第${refresh}次刷新广告池成功,获取到广告`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (refresh < 99) {
|
||||
const waitSec = randomDelaySeconds();
|
||||
this.log(`⚠️ 第${refresh}次刷新广告池失败,等待 ${waitSec} 秒后重试...`);
|
||||
await delay(waitSec * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!adTask) {
|
||||
this.log(`❌ 初始广告获取失败(已刷新99次广告池均失败),停止任务`);
|
||||
return false;
|
||||
}
|
||||
|
||||
let busyCount = 0;
|
||||
while (busyCount < MAX_BUSY_INITIAL) {
|
||||
const expected = adTask.expectedCoins;
|
||||
this.log(`初始 预计 ${expected} 金币`);
|
||||
|
||||
const baseWatch = adTask.materialTime;
|
||||
const watchSec = baseWatch + Math.random() * 2;
|
||||
this.log(`观看初始 ${watchSec.toFixed(1)} 秒...`);
|
||||
await delay(watchSec * 1000);
|
||||
|
||||
const initOk = await this.startTask(adTask, config);
|
||||
if (!initOk) {
|
||||
this.log(`❌ 初始化观看失败,停止任务`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const { success, amount, busy } = await this.reportTask(adTask, adTask.materialTime, config);
|
||||
if (success && amount > 0) {
|
||||
this.totalCoins += amount;
|
||||
this.log(`初始 ${amount} 金币 | 累计 ${this.totalCoins}`);
|
||||
return true;
|
||||
} else if (busy) {
|
||||
busyCount++;
|
||||
this.log(`⚠️ 初始上报繁忙 (${busyCount}/${MAX_BUSY_INITIAL})`);
|
||||
if (busyCount >= MAX_BUSY_INITIAL) {
|
||||
this.log(`❌ 连续 ${MAX_BUSY_INITIAL} 次内部繁忙,停止初始任务`);
|
||||
return false;
|
||||
}
|
||||
const intervalSec = randomDelaySeconds();
|
||||
this.log(`重试间隔 ${intervalSec.toFixed(1)} 秒...`);
|
||||
await delay(intervalSec * 1000);
|
||||
continue;
|
||||
} else {
|
||||
this.log(`❌ 初始上报失败(非繁忙),停止任务`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
if (error.message === "ACCOUNT_STOP") {
|
||||
this.log(`🚫 账号因连续签名失败已停止`);
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async runAppend(config) {
|
||||
this.appendCount = 0;
|
||||
let consecutiveFailures = 0;
|
||||
let busyCount = 0;
|
||||
const MAX_AD_FAILURES = 99;
|
||||
|
||||
try {
|
||||
for (let i = 1; i <= MAX_LIVES; i++) {
|
||||
const adTask = await this.getAdTask(config, true);
|
||||
if (!adTask) {
|
||||
consecutiveFailures++;
|
||||
this.log(`❌ 获取追加广告失败(刷新广告池第 ${consecutiveFailures}/${MAX_AD_FAILURES} 次失败)`);
|
||||
if (consecutiveFailures >= MAX_AD_FAILURES) {
|
||||
this.log(`❌ 连续 ${MAX_AD_FAILURES} 次刷新广告池失败,停止追加任务`);
|
||||
break;
|
||||
}
|
||||
const intervalSec = randomDelaySeconds();
|
||||
this.log(`追加间隔 ${intervalSec.toFixed(1)} 秒...`);
|
||||
await delay(intervalSec * 1000);
|
||||
continue;
|
||||
}
|
||||
consecutiveFailures = 0;
|
||||
|
||||
const expected = adTask.expectedCoins;
|
||||
this.log(`追加 预计 ${expected} 金币`);
|
||||
|
||||
const baseWatch = adTask.materialTime;
|
||||
const watchSec = baseWatch + Math.random() * 2;
|
||||
await delay(watchSec * 1000);
|
||||
|
||||
const initOk = await this.startTask(adTask, config);
|
||||
if (!initOk) {
|
||||
this.log(`❌ 初始化观看失败,本次追加无效,等待间隔后继续`);
|
||||
const intervalSec = randomDelaySeconds();
|
||||
this.log(`追加间隔 ${intervalSec.toFixed(1)} 秒...`);
|
||||
await delay(intervalSec * 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { success, amount, busy } = await this.reportTask(adTask, adTask.materialTime, config);
|
||||
if (busy) {
|
||||
busyCount++;
|
||||
this.log(`⚠️ 追加上报繁忙 (${busyCount}/${MAX_BUSY_APPEND})`);
|
||||
if (busyCount >= MAX_BUSY_APPEND) {
|
||||
this.log(`⏸️ 连续 ${MAX_BUSY_APPEND} 次繁忙,休息5分钟...`);
|
||||
await delay(APPEND_BUSY_BREAK_MS);
|
||||
busyCount = 0;
|
||||
this.log(`🔄 休息结束,继续追加任务`);
|
||||
}
|
||||
const intervalSec = randomDelaySeconds();
|
||||
this.log(`追加间隔 ${intervalSec.toFixed(1)} 秒...`);
|
||||
await delay(intervalSec * 1000);
|
||||
continue;
|
||||
}
|
||||
busyCount = 0;
|
||||
|
||||
if (success && amount > 0) {
|
||||
this.totalCoins += amount;
|
||||
this.appendCount++;
|
||||
this.log(`追加(${this.appendCount}) ${amount} 金币 | 累计 ${this.totalCoins}`);
|
||||
this.log(`追加计数 (第 ${this.appendCount}/${MAX_LIVES} 次)`); // 文案修改
|
||||
}
|
||||
|
||||
const intervalSec = randomDelaySeconds();
|
||||
this.log(`追加间隔 ${intervalSec.toFixed(1)} 秒...`);
|
||||
await delay(intervalSec * 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message === "ACCOUNT_STOP") {
|
||||
this.log(`🚫 账号因连续签名失败已停止`);
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async run() {
|
||||
this.log(`==== 开始执行 (${this.platform.displayName}) ====`);
|
||||
const platformKey = this.kpn === "NEBULA" ? "NEBULA" : "KUAISHOU";
|
||||
const configs = TASK_CONFIGS[platformKey];
|
||||
|
||||
for (let idx = 0; idx < TASKS_TO_RUN.length; idx++) {
|
||||
const taskKey = TASKS_TO_RUN[idx];
|
||||
const config = configs[taskKey];
|
||||
if (!config) continue;
|
||||
|
||||
if (taskKey === "live") {
|
||||
const success = await this.runInitial(config);
|
||||
if (!success) {
|
||||
this.log(`初始任务失败,跳过后续追加任务`);
|
||||
break;
|
||||
}
|
||||
if (idx < TASKS_TO_RUN.length - 1 && TASKS_TO_RUN[idx+1] === "lives") {
|
||||
const intervalSec = randomDelaySeconds();
|
||||
this.log(`追加间隔 ${intervalSec.toFixed(1)} 秒...`);
|
||||
await delay(intervalSec * 1000);
|
||||
}
|
||||
} else if (taskKey === "lives") {
|
||||
await this.runAppend(config);
|
||||
}
|
||||
}
|
||||
this.log(`==== 结束,累计获得 ${this.totalCoins} 金币 ====\n`);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 并发控制 ====================
|
||||
async function runWithConcurrency(tasks, concurrency) {
|
||||
const results = [];
|
||||
const executing = new Set();
|
||||
for (const task of tasks) {
|
||||
const p = Promise.resolve().then(() => task());
|
||||
results.push(p);
|
||||
executing.add(p);
|
||||
const clean = () => executing.delete(p);
|
||||
p.then(clean).catch(clean);
|
||||
if (executing.size >= concurrency) {
|
||||
await Promise.race(executing);
|
||||
}
|
||||
}
|
||||
return Promise.all(results);
|
||||
}
|
||||
|
||||
// ==================== 主入口 ====================
|
||||
(async () => {
|
||||
console.log(`🌸 快手广告脚本(双端自动识别 | 间隔1-3秒 | 签名失败3次停号 | 初始繁忙2次停任务 | 追加繁忙3次休息5分 | 强制翻页忽略no_more | 翻页日志静默)🌸\n`);
|
||||
const envKsck = process.env.ksck;
|
||||
if (!envKsck) { console.log("❌ 环境变量 ksck 未设置"); process.exit(1); }
|
||||
const rawAccounts = envKsck.split("&").filter(Boolean);
|
||||
const accounts = [];
|
||||
for (const line of rawAccounts) {
|
||||
const parts = line.trim().split("#");
|
||||
if (parts.length < 3) {
|
||||
console.log(`⚠️ 账号格式错误: ${line}`);
|
||||
continue;
|
||||
}
|
||||
accounts.push(new LiveAdTask(parts[0], parts[1], parts[2]));
|
||||
}
|
||||
if (accounts.length === 0) {
|
||||
console.log("❌ 没有有效的账号,退出");
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`📊 共加载 ${accounts.length} 个账号,并发数限制 ${MAX_CONCURRENT_ACCOUNTS}\n`);
|
||||
await runWithConcurrency(accounts.map(acc => () => acc.run()), MAX_CONCURRENT_ACCOUNTS);
|
||||
console.log("\n✅ 所有账号执行结束");
|
||||
})();
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* ============================================================
|
||||
* 脚本名称:快手极速版自动化脚本
|
||||
* 作者:[屿柚.]
|
||||
* 版本:v1.0.0
|
||||
* 日期:2026-05-06
|
||||
* ============================================================
|
||||
*
|
||||
* 【重要声明】
|
||||
* 本脚本为作者个人学习研究之作,未以任何开源协议发布,
|
||||
* 未经授权禁止复制、修改、分发或用于商业目的。
|
||||
*
|
||||
* 【使用须知】
|
||||
* 1. 本脚本仅供个人技术学习与交流,非官方工具,与快手及
|
||||
* 快手极速版(北京快手科技有限公司)无任何关联。
|
||||
* 2. 使用本脚本可能导致账号受限、收益清零、功能封禁等风险,
|
||||
* 一切后果由使用者自行承担,作者不承担任何责任。
|
||||
* 3. 请严格遵守《快手用户协议》《快手社区管理规定》及相关
|
||||
* 法律法规,禁止利用本脚本进行刷量、作弊、薅羊毛等违规
|
||||
* 操作。
|
||||
* 4. 脚本运行涉及账号Cookie/Token等敏感信息,请妥善保管,
|
||||
* 作者不收集、不存储、不泄露您的任何个人信息,信息泄露
|
||||
* 风险由使用者自行承担。
|
||||
* 5. 因快手平台规则调整、接口变更导致脚本失效,作者不承诺
|
||||
* 维护更新,保留随时停止分享的权利。
|
||||
*
|
||||
* 【使用即同意】
|
||||
* 运行本脚本即视为您已阅读、理解并同意上述全部条款。
|
||||
* 如不同意,请立即删除本脚本并停止使用。
|
||||
*
|
||||
* 【侵权处理】
|
||||
* 未经授权擅自转载、售卖、二次分发本脚本,作者保留追究
|
||||
* 法律责任的权利。
|
||||
*
|
||||
* ============================================================
|
||||
*/
|
||||
/*
|
||||
------------------------------------------
|
||||
@Description: 测试
|
||||
const $ = new Env('快手普通')
|
||||
cron: 1 1 1 1 1
|
||||
|
||||
------------------------------------------
|
||||
* ☆*:.。. Author: 屿柚. .。.:*☆
|
||||
* ☆*:.。. Contact: 2214400971 .。.:*☆
|
||||
* ☆*:.。. Completed: 2026-05-06 .。.:*☆
|
||||
* ☆*:.。. ┏━━━━━━━━━━━━━━━━━━━━━━━━━┓ .。.:*☆
|
||||
* ☆*:.。. ┃ ⚠️ 免 责 声 明 ⚠️ ┃ .。.:*☆
|
||||
* ☆*:.。. ┃ 本脚本完全免费! ┃ .。.:*☆
|
||||
* ☆*:.。. ┃ 如您是付费购买, ┃ .。.:*☆
|
||||
* ☆*:.。. ┃ 恭喜您被骗了!(╬゚д゚) ┃ .。.:*☆
|
||||
* ☆*:.。. ┗━━━━━━━━━━━━━━━━━━━━━━━━━┛ .。.:*☆
|
||||
*/
|
||||
|
||||
//变量名为Task 值为look,仅此一项任务
|
||||
//变量名为ck#salt 或 ck#salt#代理
|
||||
//代理已支持全格式
|
||||
//变量名为kspt_api 默认值为 http://frp-few.com:64437/ ****例如
|
||||
//其他变量我也不知道(눈_눈) 手动滑稽
|
||||
|
||||
process.env.yuyouAPI=process.env.kspt_api+"/"
|
||||
|
||||
const a0_0x5ca042=a0_0x40ce;(function(_0x4632e5,_0x15c67b){const _0x1c4240=a0_0x40ce,_0x507366=_0x4632e5();while(!![]){try{const _0x39ba0f=-parseInt(_0x1c4240(0x715))/0x1*(-parseInt(_0x1c4240(0x20e))/0x2)+-parseInt(_0x1c4240(0x6c2))/0x3+parseInt(_0x1c4240(0x33d))/0x4+parseInt(_0x1c4240(0x3ec))/0x5+-parseInt(_0x1c4240(0x3ed))/0x6+-parseInt(_0x1c4240(0x475))/0x7*(-parseInt(_0x1c4240(0x61b))/0x8)+-parseInt(_0x1c4240(0x470))/0x9*(parseInt(_0x1c4240(0x391))/0xa);if(_0x39ba0f===_0x15c67b)break;else _0x507366['push'](_0x507366['shift']());}catch(_0x3c7832){_0x507366['push'](_0x507366['shift']());}}}(a0_0x4054,0x9b72d));const a0_0x4c72cb=(function(){const _0x27b1ac=a0_0x40ce,_0x207716={'GUHsJ':function(_0x269a07,_0x55deb7){return _0x269a07===_0x55deb7;},'QSRDj':_0x27b1ac(0x678),'LbKSs':_0x27b1ac(0x4cf),'DbTVd':function(_0x1a2ec2,_0x349e50){return _0x1a2ec2(_0x349e50);}};let _0x36c171=!![];return function(_0x2b5057,_0x28af45){const _0x3faca6={'qLUHA':function(_0x4c3e0b,_0x11597c){const _0x501f0a=a0_0x40ce;return _0x207716[_0x501f0a(0x513)](_0x4c3e0b,_0x11597c);}},_0x17c1ea=_0x36c171?function(){const _0x2ed436=a0_0x40ce;if(_0x207716[_0x2ed436(0x610)](_0x207716[_0x2ed436(0x31e)],_0x207716[_0x2ed436(0x4bf)]))_0x3faca6[_0x2ed436(0x5dc)](_0x2c41d6,0x0);else{if(_0x28af45){const _0x1593e0=_0x28af45[_0x2ed436(0x761)](_0x2b5057,arguments);return _0x28af45=null,_0x1593e0;}}}:function(){};return _0x36c171=![],_0x17c1ea;};}()),a0_0x42c6ca=a0_0x4c72cb(this,function(){const _0x221564=a0_0x40ce,_0x5edac1={};_0x5edac1[_0x221564(0x5be)]=_0x221564(0x359)+_0x221564(0x4d6)+'+$';const _0xed7321=_0x5edac1;return a0_0x42c6ca[_0x221564(0x3dc)+_0x221564(0x49c)]()[_0x221564(0x44b)+'h'](_0xed7321[_0x221564(0x5be)])[_0x221564(0x3dc)+_0x221564(0x49c)]()[_0x221564(0x2c1)+_0x221564(0x49b)+'r'](a0_0x42c6ca)[_0x221564(0x44b)+'h'](_0xed7321[_0x221564(0x5be)]);});a0_0x42c6ca();const a0_0x493eac=(function(){const _0x559759=a0_0x40ce,_0x43249d={'PqheD':function(_0x39d235,_0x5165ed){return _0x39d235*_0x5165ed;},'sFmXJ':function(_0x1d279a,_0x4fb3fa){return _0x1d279a-_0x4fb3fa;},'ZvUeW':function(_0x27c3cc,_0x439089){return _0x27c3cc(_0x439089);},'GXYRu':function(_0x44eef3,_0x56e760){return _0x44eef3!==_0x56e760;},'rBBto':_0x559759(0x665)};let _0x4e0486=!![];return function(_0x3b9592,_0x570d31){const _0x1d5696=_0x559759,_0x4b112c={'NiasF':function(_0x3c8e30,_0x4877e1){const _0x113732=a0_0x40ce;return _0x43249d[_0x113732(0x6b3)](_0x3c8e30,_0x4877e1);},'IRezC':function(_0x3497bc,_0x5196d7){const _0xafc01=a0_0x40ce;return _0x43249d[_0xafc01(0x6d6)](_0x3497bc,_0x5196d7);},'HfWPB':function(_0x227e4c,_0xc7eb78){const _0x35d28d=a0_0x40ce;return _0x43249d[_0x35d28d(0x570)](_0x227e4c,_0xc7eb78);},'mODtb':function(_0x20dcca,_0x3ad9f5){const _0x1f8409=a0_0x40ce;return _0x43249d[_0x1f8409(0x5ad)](_0x20dcca,_0x3ad9f5);},'LyySH':_0x1d5696(0x703),'rpAHV':function(_0x1a16f9,_0x4b9bda){return _0x1a16f9!==_0x4b9bda;},'GQSiM':_0x43249d[_0x1d5696(0x260)]},_0x5bbe9b=_0x4e0486?function(){const _0x514a6d=_0x1d5696;if(_0x4b112c[_0x514a6d(0x59e)](_0x4b112c[_0x514a6d(0x30a)],_0x514a6d(0x703)))_0x279b77+=_0x30deec[_0x514a6d(0x6e9)+'t'](_0x22dac2[_0x514a6d(0x6bf)](_0x4b112c[_0x514a6d(0x411)](_0x12b803[_0x514a6d(0x6cc)+'m'](),_0x59d393[_0x514a6d(0x57b)+'h'])));else{if(_0x570d31){if(_0x4b112c[_0x514a6d(0x2d1)](_0x4b112c[_0x514a6d(0x6ae)],_0x4b112c[_0x514a6d(0x6ae)]))_0x6e4940=_0x9530f7[0x0],_0x41107e=_0xe03f0d[0x1],_0x24e5c9=_0x5e076e[_0x514a6d(0x3d1)](0x2,_0x4b112c[_0x514a6d(0x653)](_0xe4b797[_0x514a6d(0x57b)+'h'],0x1))[_0x514a6d(0x655)]('#'),_0x522e67=_0x4b112c[_0x514a6d(0x503)](_0x14044e,_0x129d01[_0x4b112c[_0x514a6d(0x653)](_0x3ab964[_0x514a6d(0x57b)+'h'],0x1)]);else{const _0x104393=_0x570d31[_0x514a6d(0x761)](_0x3b9592,arguments);return _0x570d31=null,_0x104393;}}}}:function(){};return _0x4e0486=![],_0x5bbe9b;};}());(function(){const _0x2331e1=a0_0x40ce,_0x60e784={'dUinw':function(_0x896daf,_0x1092e9){return _0x896daf(_0x1092e9);},'NhuHy':function(_0x4e91c8,_0x677407){return _0x4e91c8>=_0x677407;},'xsGLv':function(_0x37e4b6,_0x59399d){return _0x37e4b6+_0x59399d;},'XysCR':function(_0x3a2945,_0x56c8a4){return _0x3a2945===_0x56c8a4;},'XHSUq':_0x2331e1(0x42e),'bDjSZ':_0x2331e1(0x6fa),'eWZZe':_0x2331e1(0x723)+_0x2331e1(0x34b)+_0x2331e1(0x450)+')','xZIQd':function(_0x561c02,_0x14e57c){return _0x561c02(_0x14e57c);},'vOpPk':_0x2331e1(0x6c8),'Asfjy':function(_0x9ef2e9,_0x3db3cf){return _0x9ef2e9+_0x3db3cf;},'YQmba':_0x2331e1(0x33c),'qwOlB':_0x2331e1(0x5ac),'yragT':function(_0x267cd2,_0x5a9266){return _0x267cd2(_0x5a9266);},'jxZfV':function(_0x8d6a05){return _0x8d6a05();},'tIjBr':function(_0x29e4fd,_0x18715f,_0x25565b){return _0x29e4fd(_0x18715f,_0x25565b);}};_0x60e784[_0x2331e1(0x1e4)](a0_0x493eac,this,function(){const _0x4fbc79=_0x2331e1,_0x3a541f={'QOfSu':function(_0x12bfec,_0x566199){const _0x5c179b=a0_0x40ce;return _0x60e784[_0x5c179b(0x75b)](_0x12bfec,_0x566199);},'RZOCk':function(_0x4b8863,_0x564a7a){const _0x3a25d9=a0_0x40ce;return _0x60e784[_0x3a25d9(0x54b)](_0x4b8863,_0x564a7a);}Line truncated
|
||||
@@ -0,0 +1,498 @@
|
||||
|
||||
const axios = require("axios");
|
||||
console.log("自定义接口搭建教程 https://mp.weixin.qq.com/s/QCpnK8scCmG69lLm3xg9XA")
|
||||
console.log("最低2.1代理,4.5家庭住宅 http://www.gzsk5.com/#/register?invitation=hnking2&shareid=516")
|
||||
// ==============================================
|
||||
// 快手普通版 · 纯短剧广告专用脚本
|
||||
// 接口搭建教程
|
||||
// 环境变量:ck 格式:备注#cookie#salt&...
|
||||
// ==============================================
|
||||
|
||||
const COLOR = {
|
||||
RESET: "\x1b[0m",
|
||||
BRIGHT: "\x1b[1m",
|
||||
RED: "\x1b[31m",
|
||||
GREEN: "\x1b[32m",
|
||||
YELLOW: "\x1b[33m",
|
||||
BLUE: "\x1b[34m",
|
||||
MAGENTA: "\x1b[35m",
|
||||
CYAN: "\x1b[36m",
|
||||
GRAY: "\x1b[90m",
|
||||
BG_GREEN: "\x1b[42m",
|
||||
BG_YELLOW: "\x1b[43m",
|
||||
BG_RED: "\x1b[41m"
|
||||
};
|
||||
|
||||
function colorLog(type, msg) {
|
||||
const colorMap = {
|
||||
success: `${COLOR.GREEN}✅${COLOR.RESET}`,
|
||||
info: `${COLOR.BLUE}ℹ️${COLOR.RESET}`,
|
||||
warn: `${COLOR.YELLOW}⚠️${COLOR.RESET}`,
|
||||
error: `${COLOR.RED}❌${COLOR.RESET}`,
|
||||
stop: `${COLOR.BG_RED}🚫${COLOR.RESET}`,
|
||||
pause: `${COLOR.BG_YELLOW}⏸️${COLOR.RESET}`,
|
||||
refresh: `${COLOR.CYAN}🔄${COLOR.RESET}`,
|
||||
coin: `${COLOR.MAGENTA}💰${COLOR.RESET}`,
|
||||
double: `${COLOR.BRIGHT}✨${COLOR.RESET}`
|
||||
};
|
||||
return `${colorMap[type] || ""} ${msg}`;
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 签名配置
|
||||
// ==============================================
|
||||
const SIGN_API_KUAISHOU = process.env.kspt_api || "http://47.113.119.128:202";
|
||||
const SIGN_API_NEBULA = process.env.ksjs_api || "http://47.113.119.128:201";
|
||||
|
||||
// 强制只执行短剧
|
||||
const TASKS_TO_RUN = ["drama"];
|
||||
|
||||
const MAX_DRAMA = parseInt(process.env.KS_MAX_DRAMA) || 999999;
|
||||
const MAX_CONCURRENT_ACCOUNTS = parseInt(process.env.KS_MAX_CONCURRENT) || 10;
|
||||
|
||||
const MIN_DELAY_SEC = 1;
|
||||
const MAX_DELAY_SEC = 3;
|
||||
|
||||
function randomDelaySeconds() {
|
||||
return Math.floor(Math.random() * (MAX_DELAY_SEC - MIN_DELAY_SEC + 1) + MIN_DELAY_SEC);
|
||||
}
|
||||
function randomDelay() {
|
||||
return new Promise(resolve => setTimeout(resolve, randomDelaySeconds() * 1000));
|
||||
}
|
||||
|
||||
const MAX_BUSY_INITIAL = 2;
|
||||
const MAX_BUSY_APPEND = 3;
|
||||
const APPEND_BUSY_BREAK_MS = 5 * 60 * 1000;
|
||||
const MAX_SIGN_FAILURES = 3;
|
||||
|
||||
// ==============================================
|
||||
// 平台配置(普通版)
|
||||
// ==============================================
|
||||
const PLATFORM_CONFIG = {
|
||||
KUAISHOU: {
|
||||
name: "KS",
|
||||
host: "encourage.kuaishou.com",
|
||||
appId: "kuaishou",
|
||||
packageName: "com.smile.gifmaker",
|
||||
appName: "快手",
|
||||
displayName: "普通版",
|
||||
kpn: "KUAISHOU",
|
||||
adClientKey: "3c2cd3f3",
|
||||
reportClientKey: "3c2cd3f3"
|
||||
}
|
||||
};
|
||||
|
||||
function identifyPlatform(cookie) {
|
||||
return PLATFORM_CONFIG.KUAISHOU;
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 设备参数
|
||||
// ==============================================
|
||||
const DEFAULT_DEVICE_PARAMS_UNIFIED = {
|
||||
earphoneMode: "1",
|
||||
mod: "OnePlus(PKX110)",
|
||||
appver: "14.3.30.11384",
|
||||
isp: "CMCC",
|
||||
language: "zh-cn",
|
||||
did_tag: "0",
|
||||
thermal: "10000",
|
||||
net: "5G",
|
||||
kcv: "1620",
|
||||
app: "0",
|
||||
kpf: "ANDROID_PHONE",
|
||||
bottom_navigation: "true",
|
||||
ver: "14.3",
|
||||
android_os: "0",
|
||||
oDid: "ANDROID_adb1e1653dd085be",
|
||||
boardPlatform: "sun",
|
||||
newOc: "ANDROID_OPPO__LXCPA_CPA_ZGYXZRGSKSKJ_249561%2C1",
|
||||
androidApiLevel: "36",
|
||||
slh: "0",
|
||||
country_code: "cn",
|
||||
nbh: "0",
|
||||
hotfix_ver: "",
|
||||
keyconfig_state: "2",
|
||||
cdid_tag: "2",
|
||||
sys: "ANDROID_16",
|
||||
max_memory: "256",
|
||||
oc: "ANDROID_OPPO__LXCPA_CPA_ZGYXZRGSKSKJ_249561%2C1",
|
||||
sh: "2640",
|
||||
deviceBit: "4",
|
||||
browseType: "3",
|
||||
ddpi: "476",
|
||||
socName: "Qualcomm%20Snapdragon%208750",
|
||||
is_background: "0",
|
||||
c: "ANDROID_OPPO__LXCPA_CPA_ZGYXZRGSKSKJ_249561%2C1",
|
||||
sw: "1216",
|
||||
ftt: "",
|
||||
abi: "arm64",
|
||||
userRecoBit: "0",
|
||||
device_abi: "arm64",
|
||||
icaver: "1",
|
||||
totalMemory: "15107",
|
||||
grant_browse_type: "AUTHORIZED",
|
||||
iuid: "",
|
||||
rdid: "ANDROID_7bc831446e31ac0a",
|
||||
sbh: "135",
|
||||
darkMode: "false"
|
||||
};
|
||||
|
||||
let deviceParamsUnified = { ...DEFAULT_DEVICE_PARAMS_UNIFIED };
|
||||
if (process.env.KS_DEVICE_PARAMS_UNIFIED) {
|
||||
try {
|
||||
const custom = JSON.parse(process.env.KS_DEVICE_PARAMS_UNIFIED);
|
||||
deviceParamsUnified = { ...deviceParamsUnified, ...custom };
|
||||
console.log(colorLog("success", "已加载自定义设备参数"));
|
||||
} catch (e) {
|
||||
console.log(colorLog("warn", `设备参数解析失败: ${e.message}`));
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 短剧广告参数
|
||||
// ==============================================
|
||||
const TASK_CONFIGS = {
|
||||
KUAISHOU: {
|
||||
drama: {
|
||||
name: "短剧广告",
|
||||
businessId: 7057,
|
||||
posId: 216266,
|
||||
pageId: 100014021,
|
||||
subPageId: 100014022,
|
||||
requestSceneType: 7,
|
||||
taskType: 2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================================
|
||||
// 工具函数
|
||||
// ==============================================
|
||||
function createLogger(remark, platformDisplayName) {
|
||||
const prefix = `${COLOR.CYAN}[${new Date().toLocaleTimeString()}]${COLOR.RESET} ${COLOR.BRIGHT}[${remark}]${COLOR.RESET} ${COLOR.GRAY}[${platformDisplayName}]${COLOR.RESET}`;
|
||||
return {
|
||||
success: (msg) => console.log(`${prefix} ${colorLog("success", msg)}`),
|
||||
info: (msg) => console.log(`${prefix} ${colorLog("info", msg)}`),
|
||||
warn: (msg) => console.log(`${prefix} ${colorLog("warn", msg)}`),
|
||||
error: (msg) => console.log(`${prefix} ${colorLog("error", msg)}`),
|
||||
stop: (msg) => console.log(`${prefix} ${colorLog("stop", msg)}`),
|
||||
pause: (msg) => console.log(`${prefix} ${colorLog("pause", msg)}`),
|
||||
refresh: (msg) => console.log(`${prefix} ${colorLog("refresh", msg)}`),
|
||||
coin: (msg) => console.log(`${prefix} ${colorLog("coin", msg)}`),
|
||||
double: (msg) => console.log(`${prefix} ${colorLog("double", msg)}`),
|
||||
raw: (msg) => console.log(`${prefix} ${msg}`)
|
||||
};
|
||||
}
|
||||
|
||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
||||
function genRequestId() { return Math.floor(Math.random() * 100000000000000000).toString(); }
|
||||
function getCurrentTimestampMs() { return Date.now(); }
|
||||
function getColdLaunchTimeMs() { return Date.now() - 30 * 1000; }
|
||||
|
||||
function javaUrlEncode(str) {
|
||||
if (!str) return "";
|
||||
return encodeURIComponent(str)
|
||||
.replace(/!/g, '%21')
|
||||
.replace(/'/g, '%27')
|
||||
.replace(/\(/g, '%28')
|
||||
.replace(/\)/g, '%29')
|
||||
.replace(/~/g, '%7E')
|
||||
.replace(/\*/g, '%2A');
|
||||
}
|
||||
|
||||
function buildSortedParams(obj) {
|
||||
return Object.keys(obj).sort()
|
||||
.filter(k => obj[k] != null && obj[k] !== "")
|
||||
.map(k => `${javaUrlEncode(k)}=${javaUrlEncode(obj[k])}`)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
function getBase64NoWrap(obj) {
|
||||
return Buffer.from(JSON.stringify(obj)).toString('base64').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 签名
|
||||
// ==============================================
|
||||
async function getNsSign(reqInfo, kpnType, remark, logObj) {
|
||||
const SIGN_API_URL = SIGN_API_KUAISHOU;
|
||||
try {
|
||||
const payload = { path: reqInfo.urlpath, data: reqInfo.reqdata, salt: reqInfo.salt };
|
||||
const resp = await axios.post(SIGN_API_URL + "/nssig", payload, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 15000
|
||||
});
|
||||
if (resp.data?.data) {
|
||||
return {
|
||||
sig: resp.data.data.sig,
|
||||
nstokensig: resp.data.data.nstokensig,
|
||||
sig3: resp.data.data.nssig3,
|
||||
xfalcon: resp.data.data.nssig4 || ""
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
logObj.error(`签名失败: ${e.message}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 广告解析
|
||||
// ==============================================
|
||||
function getDramaAdInfo(feed) {
|
||||
try {
|
||||
const ad = feed.ad || feed.adInfo || feed;
|
||||
let extData = ad.extData || "{}";
|
||||
if (typeof extData === "string") extData = JSON.parse(extData);
|
||||
|
||||
const award = extData.awardCoin || extData.coinAmount || 0;
|
||||
const duration = extData.materialTime || ad.materialTime || 50;
|
||||
|
||||
return {
|
||||
coins: parseInt(award) || 0,
|
||||
duration
|
||||
};
|
||||
} catch (e) {
|
||||
return { coins: 0, duration: 50 };
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 短剧任务类
|
||||
// ==============================================
|
||||
class DramaAdTask {
|
||||
constructor(remark, cookie, salt) {
|
||||
this.remark = remark;
|
||||
this.cookie = cookie;
|
||||
this.salt = salt;
|
||||
|
||||
this.platform = PLATFORM_CONFIG.KUAISHOU;
|
||||
this.kpn = "KUAISHOU";
|
||||
this.clientKey = "3c2cd3f3";
|
||||
this.reportClientKey = "3c2cd3f3";
|
||||
|
||||
this.log = createLogger(remark, this.platform.displayName);
|
||||
this.commonQuery = {};
|
||||
this.parseCookie();
|
||||
|
||||
this.totalCoins = 0;
|
||||
this.cid = "";
|
||||
this.adId = "";
|
||||
this.llsid = "";
|
||||
this.feedId = "";
|
||||
this.signFailCount = 0;
|
||||
|
||||
this.h5ExtParams = Array.from({ length: 96 }, () =>
|
||||
Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
||||
).join("");
|
||||
}
|
||||
|
||||
parseCookie() {
|
||||
const extract = (k) => {
|
||||
const m = this.cookie.match(new RegExp(`(^|;\\s*)${k}=([^;]+)`));
|
||||
return m ? m[2] : "";
|
||||
};
|
||||
this.ud = extract("ud") || extract("userId");
|
||||
this.did = extract("did");
|
||||
this.egid = extract("egid");
|
||||
this.api_st = extract("kuaishou.api_st");
|
||||
this.token = extract("token");
|
||||
this.appver = extract("appver") || deviceParamsUnified.appver;
|
||||
|
||||
const now = Date.now();
|
||||
this.commonQuery = {
|
||||
...deviceParamsUnified,
|
||||
appver: this.appver,
|
||||
ud: this.ud,
|
||||
did: this.did,
|
||||
egid: this.egid,
|
||||
kpn: this.kpn,
|
||||
did_gt: extract("did_gt") || (now - 60000).toString(),
|
||||
cold_launch_time_ms: (now - 30000).toString()
|
||||
};
|
||||
}
|
||||
|
||||
async doRequest(urlPath, form) {
|
||||
const all = { ...this.commonQuery, ...form };
|
||||
const data = buildSortedParams(all);
|
||||
|
||||
const sign = await getNsSign(
|
||||
{ urlpath: urlPath, reqdata: data, salt: this.salt },
|
||||
this.kpn,
|
||||
this.remark,
|
||||
this.log
|
||||
);
|
||||
if (!sign) return { ok: false, signFailed: true };
|
||||
|
||||
const qs = buildSortedParams({
|
||||
...this.commonQuery,
|
||||
sig: sign.sig,
|
||||
__NS_sig3: sign.sig3,
|
||||
__NStokensig: sign.nstokensig
|
||||
});
|
||||
|
||||
const url = `https://api.e.kuaishou.com${urlPath}?${qs}`;
|
||||
const body = buildSortedParams(form);
|
||||
|
||||
try {
|
||||
const res = await axios.post(url, body, {
|
||||
headers: {
|
||||
Cookie: this.cookie,
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "kwai-android",
|
||||
Host: "api.e.kuaishou.com"
|
||||
},
|
||||
timeout: 10000
|
||||
});
|
||||
return { ok: true, data: res.data };
|
||||
} catch (e) {
|
||||
this.log.error(`请求失败: ${e.message}`);
|
||||
return { ok: false };
|
||||
}
|
||||
}
|
||||
|
||||
async getDramaAd(config) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const form = {
|
||||
client_key: this.clientKey,
|
||||
business_id: config.businessId,
|
||||
pageId: config.pageId,
|
||||
subPageId: config.subPageId,
|
||||
request_scene_type: config.requestSceneType,
|
||||
os: "android",
|
||||
cs: "false"
|
||||
};
|
||||
|
||||
const { ok, data, signFailed } = await this.doRequest("/rest/e/reward/mixed/ad", form);
|
||||
if (signFailed) {
|
||||
this.signFailCount++;
|
||||
if (this.signFailCount >= 3) { this.log.stop("签名失败超限"); return null; }
|
||||
continue;
|
||||
}
|
||||
if (!ok || data.result !== 1) continue;
|
||||
|
||||
const ad = data.ads?.[0] || data.adList?.[0] || data.feeds?.[0];
|
||||
if (!ad) continue;
|
||||
|
||||
this.cid = ad.cid || ad.creativeId || "";
|
||||
this.adId = ad.adId || ad.id || "";
|
||||
this.llsid = ad.llsid || "";
|
||||
this.feedId = ad.photoId || this.cid;
|
||||
|
||||
const { coins, duration } = getDramaAdInfo(ad);
|
||||
this.log.success(`获取短剧广告 | 预计 ${coins} 金币 | 时长 ${duration}s`);
|
||||
return { coins, duration };
|
||||
}
|
||||
this.log.warn("未获取到短剧广告");
|
||||
return null;
|
||||
}
|
||||
|
||||
async reportDrama(config, duration) {
|
||||
const now = Date.now();
|
||||
const watch = duration * 1000;
|
||||
|
||||
const biz = {
|
||||
businessId: config.businessId,
|
||||
pageId: config.pageId,
|
||||
subPageId: config.subPageId,
|
||||
posId: config.posId,
|
||||
startTime: now - watch,
|
||||
endTime: now,
|
||||
mediaScene: "video",
|
||||
sessionId: `drama_${now}`,
|
||||
reportType: 0,
|
||||
neoInfos: [
|
||||
{
|
||||
creativeId: this.cid,
|
||||
adId: this.adId,
|
||||
llsid: this.llsid,
|
||||
feedId: this.feedId,
|
||||
watchAdTime: watch,
|
||||
materialTime: watch,
|
||||
requestSceneType: config.requestSceneType,
|
||||
taskType: config.taskType,
|
||||
watchStage: 0
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const form = {
|
||||
bizStr: JSON.stringify(biz),
|
||||
client_key: this.reportClientKey,
|
||||
os: "android",
|
||||
cs: "false"
|
||||
};
|
||||
|
||||
const { ok, data } = await this.doRequest("/rest/r/ad/task/report", form);
|
||||
if (ok && data.result === 1) {
|
||||
const coin = data.data?.neoAmount || 0;
|
||||
this.totalCoins += coin;
|
||||
this.log.coin(`上报成功 +${coin} | 总计 ${this.totalCoins}`);
|
||||
return true;
|
||||
}
|
||||
this.log.error("上报失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
async run() {
|
||||
this.log.raw(`${COLOR.BG_GREEN}==== 开始短剧任务 ====${COLOR.RESET}`);
|
||||
const config = TASK_CONFIGS.KUAISHOU.drama;
|
||||
|
||||
for (let i = 1; i <= MAX_DRAMA; i++) {
|
||||
const ad = await this.getDramaAd(config);
|
||||
if (!ad) { await delay(5000); continue; }
|
||||
|
||||
this.log.info(`第 ${i} 轮 | 观看 ${ad.duration} 秒`);
|
||||
await delay(ad.duration * 1000 + Math.random() * 2000);
|
||||
|
||||
await this.reportDrama(config, ad.duration);
|
||||
await randomDelay();
|
||||
}
|
||||
|
||||
this.log.raw(`${COLOR.BG_GREEN}==== 任务结束 | 总计 ${this.totalCoins} 金币 ====${COLOR.RESET}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 账号读取:从环境变量 ck 读取
|
||||
// ==============================================
|
||||
function getAccounts() {
|
||||
const ck = process.env.ck || "";
|
||||
return ck.split("&").filter(Boolean).map(line => {
|
||||
const [remark, cookie, salt] = line.split("#");
|
||||
return { remark, cookie, salt };
|
||||
});
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// 启动入口
|
||||
// ==============================================
|
||||
async function run() {
|
||||
const accounts = getAccounts();
|
||||
if (accounts.length === 0) {
|
||||
console.log(colorLog("error", "请配置环境变量:ck"));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const set = new Set();
|
||||
for (const acc of accounts) {
|
||||
while (set.size >= MAX_CONCURRENT_ACCOUNTS) await Promise.race(set);
|
||||
const task = new DramaAdTask(acc.remark, acc.cookie, acc.salt).run().finally(() => set.delete(task));
|
||||
set.add(task);
|
||||
}
|
||||
await Promise.all(set);
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
// 当前脚本来自于 http://script.345yun.cn 脚本库下载!
|
||||
// 当前脚本来自于 http://2.345yun.cn 脚本库下载!
|
||||
// 当前脚本来自于 http://2.345yun.cc 脚本库下载!
|
||||
// 脚本库官方QQ群1群: 429274456
|
||||
// 脚本库官方QQ群2群: 1077801222
|
||||
// 脚本库官方QQ群3群: 433030897
|
||||
// 脚本库中的所有脚本文件均来自热心网友上传和互联网收集。
|
||||
// 脚本库仅提供文件上传和下载服务,不提供脚本文件的审核。
|
||||
// 您在使用脚本库下载的脚本时自行检查判断风险。
|
||||
// 所涉及到的 账号安全、数据泄露、设备故障、软件违规封禁、财产损失等问题及法律风险,与脚本库无关!均由开发者、上传者、使用者自行承担。
|
||||
Reference in new issue
Block a user