/* * 原作者 @mcdasheng688 @General74110 * 酷我音乐签到 * 更新: 2026-04-19 * 说明: * - phone: 手机号 (用于Web登录) * - ocr: OCR密钥 (用于验证码识别) * - notify: 1=每次通知(默认), 0=仅23点汇总通知 * * 参数配置方式: 在脚本URL后添加 * 示例: .js?phone=138xxxx&ocr=Kxxx¬ify=0 * 示例: .js?phone=138xxx * 示例: .js?notify=0 可以不填写手机号和OCR密钥 [task_local] 15 7-23/1 * * * https://raw.githubusercontent.com/Yu9191/Rewrite/refs/heads/main/kuwotask.js, tag=酷我音乐签到, img-url=https://raw.githubusercontent.com/deezertidal/private/main/icons/kuwosvip.png, enabled=true [rewrite_local] ^https?:\/\/360\.com\/kuwo url script-analyze-echo-response https://raw.githubusercontent.com/Yu9191/Rewrite/refs/heads/main/kuwotask.js [mitm] hostname = *.kuwo.cn,360.com */ const $ = new Env("酷我音乐"); const ARGS = (() => { let args = { phone: "", ocr: "", notify: "1" }; let input = null; if (typeof $argument !== "undefined") { input = $argument; } else if (typeof $environment !== "undefined" && $environment.sourcePath) { input = $environment.sourcePath.split(/[?#]/)[1]; } if (!input) return args; if (typeof input === "object") { if (Array.isArray(input)) { args.phone = input[0]; args.ocr = input[1] || ""; args.notify = input[2] !== undefined ? input[2] : "1"; } else { args.phone = input.phone || input.sj || ""; args.ocr = input.ocr || ""; if (input.notify !== undefined) { args.notify = (input.notify === true || input.notify === "true" || input.notify === "1" || input.notify === 1) ? "1" : "0"; } } args.phone = String(args.phone || ""); args.ocr = String(args.ocr || ""); args.notify = String(args.notify || "1"); return args; } let str = String(input).trim().replace(/^\[|\]$/g, "").replace(/^"|"$/g, ""); if (str.includes("=") || str.includes("&")) { str.split(/&|,/).forEach(item => { let [k, v] = item.split("="); if (k && v) args[k.trim()] = decodeURIComponent(v.trim()); }); if (args.notify) { args.notify = (args.notify === "true" || args.notify === "1") ? "1" : "0"; } } else if (str.includes(",")) { let arr = str.split(","); args.phone = arr[0].trim(); args.ocr = (arr[1] || "").trim(); if (arr[2] !== undefined) { args.notify = (arr[2].trim() === "true" || arr[2].trim() === "1") ? "1" : "0"; } } else { args.phone = str; } return args; })(); // 敏感信息脱敏函数 function maskSensitiveInfo(str, type = 'phone') { if (!str) return ''; if (type === 'phone') { // 手机号脱敏:保留前3位和后4位 return str.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'); } else if (type === 'key') { // 密钥脱敏:只显示前4位和后4位 if (str.length <= 8) return '****'; return str.substring(0, 4) + '****' + str.substring(str.length - 4); } return str; } // 业务常量配置(必须在使用前定义) const BUSINESS_CONSTANTS = { MIN_SCORE_FOR_CONVERT: 150000, // 最低兑换积分阈值 SURPRISE_MAX_RUN_COUNT: 6, // 惊喜任务最大执行次数 VIDEO_TASK_COUNT: 5, // 视频任务执行次数 LOTTERY_VIDEO_COUNT: 3, // 视频抽奖次数 LAST_RUN_HOUR: 23, // 最后一次运行的小时数(用于汇总通知) SCORE_TO_YUAN_RATIO: 10000 // 积分转人民币比例 }; console.log(`手机号: ${maskSensitiveInfo(ARGS.phone, 'phone')}`); console.log(`OCR 密钥: ${maskSensitiveInfo(ARGS.ocr, 'key')}`); console.log(`每次通知: ${ARGS.notify === "1" ? "开启" : "关闭(仅汇总)"}`); // 判断是否为最后一次运行(用于汇总通知) const isLastRun = (() => { const now = new Date(); const hour = now.getHours(); const minute = now.getMinutes(); // 23:00-23:59 之间才算最后一次运行,避免边界问题 return hour === BUSINESS_CONSTANTS.LAST_RUN_HOUR && minute >= 0; })(); const STATS_KEY = "kuwo_daily_stats"; function getDailyStats() { const today = new Date().toISOString().slice(0, 10); let stats = {}; try { stats = JSON.parse($.getdata(STATS_KEY) || "{}"); } catch (e) { stats = {}; } if (stats.date !== today) { stats = { date: today, runCount: 0, totalGold: 0, accounts: {} }; } return stats; } function saveDailyStats(stats) { $.setdata(JSON.stringify(stats), STATS_KEY); } const CONFIG = { PATH: "/kuwo", WWW: "https://www.kuwo.cn", API: "https://wapi.kuwo.cn", PH: ARGS.phone || "", OCR: ARGS.ocr || "", NOTIFY: ARGS.notify || "1", KEY: "cookie_kuwo_v2" }; const kw_headers = { 'Origin': `https://h5app.kuwo.cn`, 'Host': `integralapi.kuwo.cn`, 'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 KWMusic/11.2.3.0 DeviceModel/iPhone13,2 NetType/WIFI kuwopage`, 'Referer': `https://h5app.kuwo.cn/`, 'Accept-Language': `zh-CN,zh-Hans;q=0.9` }; let notifyMsg = []; let surpriseState = new Map(); const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); (async () => { if (typeof $request !== "undefined") { const url = $request.url; if (url.indexOf(CONFIG.PATH) > -1) { if (url.indexOf("captcha") > -1) await h_cap(); else if (url.indexOf("ocr") > -1) await h_ocr(); else if (url.indexOf("sms") > -1) await h_sms(); else if (url.indexOf("login") > -1) await h_login(); else await render(); } else { $.done({}); } } else { await runCron(); $.done(); } })(); async function h_cap() { try { const ua = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }; const r1 = await $.http.get({ url: CONFIG.WWW, headers: ua }); let kv = "", kn = ""; const sc = r1.headers['set-cookie'] || r1.headers['Set-Cookie']; const arr = (Array.isArray(sc) ? sc : [sc]).filter(Boolean); for (let c of arr) { if (c && (c.includes('Hm_Iuvt') || c.includes('kw_token') || c.length > 20)) { let parts = c.split(';')[0].split('='); if (parts.length >= 2) { kn = parts[0]; kv = parts[1]; break; } } } if (!kv && arr.length > 0 && arr[0]) { let p = arr[0].split(';')[0].split('='); kn = p[0]; kv = p[1]; } if (!kv) return ret({ code: -1, msg: "Step1: Cookie获取失败" }); const r2 = await $.http.get({ url: `${CONFIG.WWW}/api/common/captcha/getcode?reqId=${uuid()}&httpsStatus=1`, headers: { 'Cookie': `${kn}=${kv}`, 'Secret': sec(kv, kn), 'Referer': CONFIG.WWW, ...ua } }); const j = JSON.parse(r2.body); ret({ code: j.code, msg: j.msg, data: { img: j.data?.img, token: j.data?.token, key: kn, val: kv } }); } catch (e) { ret({ code: -1, msg: `异常: ${e.message}` }); } } async function h_ocr() { try { const b = sbody($request); let img = b.image; if (img.includes(",")) img = img.split(",")[1]; const r = await $.http.post({ url: "https://api.ocr.space/parse/image", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `apikey=${CONFIG.OCR || 'helloworld'}&base64Image=data:image/jpeg;base64,${encodeURIComponent(img)}&language=eng&scale=true&OCREngine=2` }); const j = JSON.parse(r.body); if (j.ParsedResults?.[0]?.ParsedText) ret({ code: 200, text: j.ParsedResults[0].ParsedText.replace(/[\r\n\s]/g, "") }); else ret({ code: -1 }); } catch (e) { ret({ code: -1 }); } } async function h_sms() { try { const b = sbody($request); const r = await $.http.post({ url: `${CONFIG.WWW}/api/sms/mobileLoginCode?reqId=${uuid()}&httpsStatus=1`, headers: { 'Cookie': `${b.cookieKey}=${b.cookieVal}`, 'Secret': sec(b.cookieVal, b.cookieKey), 'Content-Type': 'application/json', 'Referer': CONFIG.WWW }, body: JSON.stringify({ verifyCode: b.code, verifyCodeToken: b.token, mobile: b.mobile }) }); ret(JSON.parse(r.body)); } catch (e) { ret({ code: -1, msg: "网络错误" }); } } async function h_login() { try { const b = sbody($request); const loginBody = { mobile: b.mobile, verifyCode: b.verifyCode, smsCode: b.smsCode, tm: b.tm }; const reqUrl = `${CONFIG.API}/api/www/login/loginByMobile?reqId=${uuid()}&httpsStatus=1`; $.log(`[h_login] 请求URL: ${reqUrl}`); $.log(`[h_login] 请求Body: ${JSON.stringify(loginBody)}`); const r = await $.http.post({ url: reqUrl, headers: { 'Cookie': `${b.cookieKey}=${b.cookieVal}`, 'Secret': sec(b.cookieVal, b.cookieKey), 'Content-Type': 'application/json', 'Referer': CONFIG.WWW, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }, body: JSON.stringify(loginBody) }); let respBody = r.body; $.log(`[h_login] 响应: ${typeof respBody === 'string' ? respBody.substring(0, 300) : JSON.stringify(respBody)}`); if (typeof respBody === 'string' && respBody.trim().startsWith('<')) { return ret({ code: -1, msg: "登录接口返回HTML,请检查网络或稍后重试", raw: respBody.substring(0, 200) }); } const j = JSON.parse(respBody); let logs = []; if (j.code === 200 && j.data && j.data.cookies) { const c = j.data.cookies; const u = { userid: c.userid, sid: c.sid || c.websid }; let old = $.getdata(CONFIG.KEY); let arr = []; let isNewUser = true; let isUpdated = false; try { let p = JSON.parse(old); if (Array.isArray(p)) arr = p; else if (p && typeof p === 'object') arr = [p]; } catch (e) { } // 检查是否是已存在的用户 const existingUser = arr.find(x => x && x.userid && String(x.userid) === String(u.userid)); if (existingUser) { isNewUser = false; // 检查sid是否变化 if (String(existingUser.sid) !== String(u.sid)) { isUpdated = true; $.log(`[h_login] 用户 ${u.userid} 的sid已更新: ${existingUser.sid} -> ${u.sid}`); } } // 移除旧的相同userid的记录 arr = arr.filter(x => x && x.userid && String(x.userid) !== String(u.userid)); arr.push(u); $.setdata(JSON.stringify(arr), CONFIG.KEY); // 构建通知消息 notifyMsg = []; let displayName = "新用户"; if (isNewUser) { notifyMsg.push("🎉 账号首次登录成功"); notifyMsg.push("✅ 数据已保存到持久化存储"); $.log(`[h_login] 新用户登录: userid=${u.userid}`); } else if (isUpdated) { notifyMsg.push("🔄 账号信息已更新"); notifyMsg.push("✅ 新的会话已保存"); displayName = "更新用户"; $.log(`[h_login] 用户信息已更新: userid=${u.userid}`); } else { notifyMsg.push("✅ 账号重新登录成功"); notifyMsg.push("ℹ️ 会话信息未变化"); displayName = "已有用户"; $.log(`[h_login] 用户重新登录: userid=${u.userid}`); } let tempStats = getDailyStats(); try { await executeTasks(`${u.userid}@${u.sid}`, displayName, tempStats); } catch (taskErr) { $.log(`[h_login] executeTasks 出错: ${taskErr.message}`); } saveDailyStats(tempStats); logs = notifyMsg; } $.log(`[h_login] 准备返回响应: code=${j.code}`); return ret({ code: j.code, msg: j.msg, logs: logs }); } catch (e) { $.log(`[h_login] 捕获异常: ${e.message}`); return ret({ code: -1, msg: e.message }); } } async function render() { const ph = CONFIG.PH.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'); // 检测用户使用的代理工具 let clientType = "未知"; let clientColor = "#8e8e93"; if ($.isQX) { clientType = "QuantumultX"; clientColor = "#0066cc"; } else if ($.isLoon) { clientType = "Loon"; clientColor = "#ff6b6b"; } else if ($.isSurge) { clientType = "Surge"; clientColor = "#00c4cc"; } const h = ` 酷我助手

酷我助手 v25${clientType}

配置: ${ph}

点击加载图片
等待 JS 初始化...
`; $.isQX ? $.done({ status: "HTTP/1.1 200 OK", headers: { "Content-Type": "text/html;charset=utf-8" }, body: h }) : $.done({ response: { status: 200, headers: { "Content-Type": "text/html;charset=utf-8" }, body: h } }); } async function runCron() { $.log("🔔 脚本开始运行..."); let rawData = $.getdata(CONFIG.KEY) || $.getdata("Kuwo_cookies"); if (!rawData) { if (CONFIG.NOTIFY === "1" || isLastRun) { $.msg("酷我音乐", "", "❌ 未检测到登录信息"); } return; } let accountArr = []; try { let p = JSON.parse(rawData); if (Array.isArray(p)) accountArr = p; else if (p && typeof p === 'object') accountArr = [p]; } catch (e) { accountArr = rawData.split(/[&]/).filter(x => x.includes('@')); } accountArr = accountArr.filter(x => { if (typeof x === 'string') return x.includes('@'); return x && x.userid; }); $.log(`📝 共检测到 ${accountArr.length} 个账号`); let dailyStats = getDailyStats(); dailyStats.runCount++; for (let i = 0; i < accountArr.length; i++) { let ID = accountArr[i]; if (typeof ID === 'object') ID = `${ID.userid}@${ID.sid || ID.websid}`; if (!ID.includes('@')) continue; if (!dailyStats.accounts[ID]) { dailyStats.accounts[ID] = { name: "", goldEarned: 0, taskCount: 0 }; } try { const nickname = await getNickname(ID); const displayName = nickname || `用户${i + 1}`; dailyStats.accounts[ID].name = displayName; notifyMsg = [`👤 账号: ${displayName}`]; $.log(`🚀 [${displayName}] 开始执行任务...`); if (nickname == null) { notifyMsg.push("⚠️ Cookie可能已失效,请检查"); } else { await executeTasks(ID, displayName, dailyStats); } if (CONFIG.NOTIFY === "1") { const message = notifyMsg.join("\n"); $.msg("酷我音乐", `任务报告`, message); } else { $.log(`📝 静默模式,跳过通知`); } } catch (err) { $.log(`❌ 账号 ${i + 1} 执行出错: ${err.message}`); if (CONFIG.NOTIFY === "1") { $.msg("酷我音乐", `账号 ${i + 1} 异常`, err.message); } } if (i < accountArr.length - 1) await sleep(3000); } saveDailyStats(dailyStats); if (isLastRun && CONFIG.NOTIFY === "0") { sendDailySummary(dailyStats); } } function sendDailySummary(stats) { let summary = [`📊 今日汇总 (${stats.date})`]; summary.push(`🔄 运行次数: ${stats.runCount}`); summary.push(`───────────`); let totalGold = 0; for (let id in stats.accounts) { const acc = stats.accounts[id]; summary.push(`👤 ${acc.name}`); summary.push(` 💰 获得: ${acc.goldEarned} 金币`); summary.push(` ✅ 任务: ${acc.taskCount} 次`); totalGold += acc.goldEarned; } summary.push(`───────────`); summary.push(`💎 总计获得: ${totalGold} 金币`); $.msg("酷我音乐", "📈 每日汇总", summary.join("\n")); } async function executeTasks(ID, displayName, dailyStats) { $.log(` - 获取资产...`); let taskSuccessCount = 0; // 局部变量,避免全局污染 let beforeScore = 0; await getAsset(ID); if ($.asset && $.asset.data) { beforeScore = $.asset.data.remainScore || 0; } await VipExtime(ID); try { if ($.asset && $.asset.data && $.asset.data.remainScore >= BUSINESS_CONSTANTS.MIN_SCORE_FOR_CONVERT) { const convertSuccess = await Convert(ID); if (convertSuccess) taskSuccessCount++; } } catch (e) { $.log(` - 兑换异常: ${e.message}`); } $.log(` - 强制执行任务...`); // 执行各项任务并统计成功数 if (await Clockin(ID)) taskSuccessCount++; taskSuccessCount += await box(ID); if (await BoxTask(ID)) taskSuccessCount++; if (await novel(ID)) taskSuccessCount++; if (await mobile(ID)) taskSuccessCount++; taskSuccessCount += await Listen(ID); taskSuccessCount += await Earning(ID); if (await collect(ID)) taskSuccessCount++; if (await loterry_free(ID)) taskSuccessCount++; if (await new_sign(ID)) taskSuccessCount++; if (await sign(ID)) taskSuccessCount++; for (let i = 0; i < BUSINESS_CONSTANTS.VIDEO_TASK_COUNT; i++) { if (await video(ID)) taskSuccessCount++; if (i % 2 == 0) await sleep(500); } for (let k = 0; k < BUSINESS_CONSTANTS.LOTTERY_VIDEO_COUNT; k++) { if (await loterry_video(ID)) taskSuccessCount++; } // 保存执行记录 try { let executedTasks = JSON.parse($.getval('executedTasks') || '{}'); const today = new Date().toISOString().slice(0, 10); if (!executedTasks[today]) executedTasks[today] = { morning: [], evening: [] }; if (!executedTasks[today].morning.includes(ID)) executedTasks[today].morning.push(ID); $.setval(JSON.stringify(executedTasks), 'executedTasks'); } catch (e) { $.log(` - 保存执行记录失败: ${e.message}`); } taskSuccessCount += await surprise(ID); await getAsset(ID, true); // 静默获取,不push到通知 let afterScore = 0; if ($.asset && $.asset.data) { afterScore = $.asset.data.remainScore || 0; } let earnedThisRun = Math.max(0, afterScore - beforeScore); if (dailyStats && dailyStats.accounts[ID]) { dailyStats.accounts[ID].goldEarned += earnedThisRun; dailyStats.accounts[ID].taskCount += taskSuccessCount; } // 精简通知:只显示关键信息 notifyMsg.push(`✅ 成功: ${taskSuccessCount}个任务`); notifyMsg.push(`💰 积分: ${afterScore} (¥${(afterScore / BUSINESS_CONSTANTS.SCORE_TO_YUAN_RATIO).toFixed(2)})`); notifyMsg.push(`📈 本次: +${earnedThisRun} 金币`); $.log(` > 成功任务: ${taskSuccessCount}, 本次获得: ${earnedThisRun} 金币`); } async function getNickname(ID) { let [uid] = ID.split('@'); try { let res = await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/music/userBase?loginUid=${uid}`, headers: kw_headers }); let body = res.body; if (typeof body === 'string') body = JSON.parse(body); return body.data.nickname; } catch (e) { return null; } } async function getAsset(ID, silent = false) { const [uid, sid] = ID.split('@'); await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/earningUserSignList?loginUid=${uid}&loginSid=${sid}`, headers: kw_headers }).then(resp => { try { const obj = JSON.parse(resp.body); $.asset = obj; if (obj.code == 200 && obj.success) { const score = obj.data.remainScore || 0; if (!silent) notifyMsg.push(`💰积分: ${score} (¥${(score / BUSINESS_CONSTANTS.SCORE_TO_YUAN_RATIO).toFixed(2)})`); $.log(` > 积分: ${score}`); } } catch (e) { $.log(` > 获取资产解析失败: ${e.message}`); } }).catch(err => { $.log(` > 获取资产请求失败: ${err.message}`); }); } async function VipExtime(ID) { const [uid, sid] = ID.split('@'); let h = JSON.parse(JSON.stringify(kw_headers)); h["Host"] = "vip1.kuwo.cn"; await $.http.get({ url: `http://vip1.kuwo.cn/vip/v2/user/vip?op=ui&uid=${uid}&sid=${sid}&signver=new`, headers: h }).then(resp => { try { const obj = JSON.parse(resp.body); if (obj.meta?.code !== 200) return; const vip = obj.data || {}; let t = Number(vip.vipLuxuryExpire || vip.vipmExpire || vip.vipExpire || 0); if (!t) { notifyMsg.push('🔴 未开通会员'); } else { if (t < 1e12) t *= 1000; const d = new Date(t); let str = `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`; notifyMsg.push(`🎟️ 会员到期: ${str}`); } } catch (e) { } }); } // 任务执行函数,返回是否成功 const doTask = async (ID, path, q, name) => { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/${path}?loginUid=${uid}&loginSid=${sid}&&${q}`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200 && o.success) { const d = o.data.description; if (d === "成功" || d === "今天已完成任务") { success = true; $.log(` > ${name}: ${d}`); } } } catch (e) { $.log(` > ${name} 解析失败: ${e.message}`); } }).catch(err => { $.log(` > ${name} 请求失败: ${err.message}`); }); return success; }; async function novel(ID) { return await doTask(ID, 'everydaymusic/doListen', 'from=novel&goldNum=18', '每日小说'); } async function mobile(ID) { return await doTask(ID, 'everydaymusic/doListen', 'from=mobile&goldNum=18', '每日听歌'); } async function collect(ID) { return await doTask(ID, 'everydaymusic/doListen', 'from=collect&goldNum=18', '每日收藏'); } async function video(ID) { return await doTask(ID, 'everydaymusic/doListen', 'from=videoadver&goldNum=58', '创意视频'); } async function sign(ID) { return await doTask(ID, 'everydaymusic/doListen', 'from=sign&extraGoldNum=110', '每日签到'); } async function new_sign(ID) { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/newUserSignList?loginUid=${uid}&loginSid=${sid}`, headers: kw_headers }).then(resp => { try { if (JSON.parse(resp.body).data.isSign) { success = true; $.log(` > 新签到: 已签`); } } catch (e) { $.log(` > 新签到解析失败: ${e.message}`); } }).catch(err => { $.log(` > 新签到请求失败: ${err.message}`); }); return success; } async function Clockin(ID) { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/newDoListen?loginUid=${uid}&loginSid=${sid}&from=clock&goldNum=59`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200) { success = true; notifyMsg.push(`⏰打卡: ${o.data.description}`); } } catch (e) { $.log(` > 打卡解析失败: ${e.message}`); } }).catch(err => { $.log(` > 打卡请求失败: ${err.message}`); }); return success; } async function Listen(ID) { const [uid, sid] = ID.split('@'); let list = []; let successCount = 0; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/newUserSignList?loginUid=${uid}&loginSid=${sid}`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200) { const t = o.data.dataList.find(x => x.taskType === "listen"); if (t && t.listenList) { list = t.listenList.filter(x => x.timetraStatus != "0").map(x => ({ gold: x.goldNum, time: x.time, unit: x.unit })); } } } catch (e) { $.log(` > 听歌列表解析失败: ${e.message}`); } }).catch(err => { $.log(` > 听歌列表请求失败: ${err.message}`); }); for (let t of list) { await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/newDoListen?loginUid=${uid}&loginSid=${sid}&from=listen&goldNum=${t.gold}&listenTime=${t.time}&unit=${t.unit}`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200) { successCount++; $.log(` > 听歌(${t.time}): ${o.data.description}`); } } catch (e) { $.log(` > 听歌(${t.time})解析失败: ${e.message}`); } }).catch(err => { $.log(` > 听歌(${t.time})请求失败: ${err.message}`); }); } return successCount; } async function Earning(ID) { const [uid, sid] = ID.split('@'); let successCount = 0; for (let id of [1, 2, 3]) { await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/newDoListen?loginUid=${uid}&loginSid=${sid}&from=coinAccumulationTask&taskId=${id}`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200 && o.data.obtain !== 0) { successCount++; $.log(` > 累计奖励(${id}): ${o.data.description}`); } } catch (e) { $.log(` > 累计奖励(${id})解析失败: ${e.message}`); } }).catch(err => { $.log(` > 累计奖励(${id})请求失败: ${err.message}`); }); } return successCount; } async function loterry_free(ID) { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/loterry/getLucky?loginUid=${uid}&loginSid=${sid}&type=free`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200) { success = true; $.log(` > 免费抽奖: ${o.data.loterryname || 'OK'}`); } } catch (e) { $.log(` > 免费抽奖解析失败: ${e.message}`); } }).catch(err => { $.log(` > 免费抽奖请求失败: ${err.message}`); }); return success; } async function loterry_video(ID) { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/loterry/getLucky?loginUid=${uid}&loginSid=${sid}&type=video`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200) { success = true; $.log(` > 视频抽奖: ${o.data.loterryname || 'OK'}`); } } catch (e) { $.log(` > 视频抽奖解析失败: ${e.message}`); } }).catch(err => { $.log(` > 视频抽奖请求失败: ${err.message}`); }); return success; } async function surprise(ID) { const [uid, sid] = ID.split('@'); let st = surpriseState.get(ID) || { runCount: 0 }; if (st.runCount >= BUSINESS_CONSTANTS.SURPRISE_MAX_RUN_COUNT) return 0; let successCount = 0; const gn = Math.random() < 0.3 ? 68 : 70; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/v1/earningSignIn/newDoListen?loginUid=${uid}&loginSid=${sid}&from=surprise&goldNum=${gn}&surpriseType=1`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200 && o.success) { successCount++; st.runCount++; surpriseState.set(ID, st); $.log(` > 惊喜任务: ${o.data.description}`); } } catch (e) { $.log(` > 惊喜任务解析失败: ${e.message}`); } }).catch(err => { $.log(` > 惊喜任务请求失败: ${err.message}`); }); return successCount; } async function box(ID) { const [uid, sid] = ID.split('@'); const times = ["00-08", "08-10", "10-12", "12-14", "14-16", "16-18", "18-20", "20-24"]; let successCount = 0; for (let t of times) { const rand = 30; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/new/boxRenew?loginUid=${uid}&loginSid=${sid}&action=new&time=${t}&goldNum=${rand}`, headers: kw_headers }).then(r => { try { if (JSON.parse(r.body).code === 200) { successCount++; $.log(` > 新宝箱(${t}): 成功`); } } catch (e) { $.log(` > 新宝箱(${t})解析失败: ${e.message}`); } }).catch(err => { $.log(` > 新宝箱(${t})请求失败: ${err.message}`); }); await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/new/boxRenew?loginUid=${uid}&loginSid=${sid}&action=old&time=${t}&goldNum=${rand}`, headers: kw_headers }).then(r => { try { if (JSON.parse(r.body).code === 200) { successCount++; $.log(` > 补宝箱(${t}): 成功`); } } catch (e) { $.log(` > 补宝箱(${t})解析失败: ${e.message}`); } }).catch(err => { $.log(` > 补宝箱(${t})请求失败: ${err.message}`); }); } return successCount; } async function BoxTask(ID) { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/new/newBoxList?loginUid=${uid}&loginSid=${sid}&from=sign&extraGoldNum=110`, headers: kw_headers }).then(async resp => { try { const d = JSON.parse(resp.body); if (d.code === 200 && d.data.goldNum > 0) { await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/new/newBoxFinish?loginUid=${uid}&loginSid=${sid}&action=new&goldNum=${d.data.goldNum}`, headers: kw_headers }).then(r => { const o = JSON.parse(r.body); if (o.code === 200) { success = true; $.log(` > 活动宝箱: 获得 ${d.data.goldNum}`); } }).catch(err => { $.log(` > 活动宝箱完成请求失败: ${err.message}`); }); } } catch (e) { $.log(` > 活动宝箱解析失败: ${e.message}`); } }).catch(err => { $.log(` > 活动宝箱列表请求失败: ${err.message}`); }); return success; } async function Convert(ID) { const [uid, sid] = ID.split('@'); let success = false; await $.http.get({ url: `https://integralapi.kuwo.cn/api/v1/online/sign/getExchangeAward?loginUid=${uid}&loginSid=${sid}"aId=13&exchangeType=vip`, headers: kw_headers }).then(resp => { try { const o = JSON.parse(resp.body); if (o.code === 200) { success = true; $.log(` > 兑换: ${o.data.description}`); } } catch (e) { $.log(` > 兑换解析失败: ${e.message}`); } }).catch(err => { $.log(` > 兑换请求失败: ${err.message}`); }); return success; } function sbody(r) { try { return typeof r.body == 'object' ? r.body : JSON.parse(r.body) } catch (e) { return {} } } function ret(d) { let h = { "Content-Type": "application/json; charset=utf-8", "Access-Control-Allow-Origin": "*" }; let b = JSON.stringify(d); $.log(`[ret] 返回数据: ${b.substring(0, 200)}`); if ($.isQX) { $done({ status: "HTTP/1.1 200 OK", headers: h, body: b }); } else { // Surge & Loon $done({ response: { status: 200, headers: h, body: b } }); } } // 生成UUID function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } // 加密函数(酷我API签名) function sec(t, e) { if (null == e || e.length <= 0) return null; let n = ""; for (let i = 0; i < e.length; i++) { n += e.charCodeAt(i).toString(); } const o = Math.floor(n.length / 5); const r = parseInt(n.charAt(o) + n.charAt(2 * o) + n.charAt(3 * o) + n.charAt(4 * o) + n.charAt(5 * o)); const c = Math.ceil(e.length / 2); const l = Math.pow(2, 31) - 1; if (r < 2) return null; const d = Math.round(1e9 * Math.random()) % 1e8; n += d; while (n.length > 10) { n = (parseInt(n.substring(0, 10)) + parseInt(n.substring(10, n.length))).toString(); } n = (r * n + c) % l; let f = ""; let h = ""; for (let i = 0; i < t.length; i++) { f = parseInt(t.charCodeAt(i) ^ Math.floor(n / l * 255)); h += f < 16 ? "0" + f.toString(16) : f.toString(16); } let dHex = d.toString(16); while (dHex.length < 8) { dHex = "0" + dHex; } return h += dHex; } function Env(name) { const isLoon = typeof $loon !== "undefined", isSurge = typeof $httpClient !== "undefined" && !isLoon, isQX = typeof $task !== "undefined"; const http = { get: o => send(o, 'GET'), post: o => send(o, 'POST') }; const send = (o, m) => new Promise((r, j) => { const opt = isQX ? o : { url: o.url, headers: o.headers, body: o.body }; if (isQX) { opt.method = m; $task.fetch(opt).then(res => { res.body = res.body; r(res) }).catch(j) } else { const c = m === 'POST' ? $httpClient.post : $httpClient.get; c(opt, (e, res, b) => { if (e) j(e); else { res.body = b; r(res) } }) } }); const setdata = (v, k) => { if (isQX) return $prefs.setValueForKey(v, k); return $persistentStore.write(v, k) }; const getdata = k => { if (isQX) return $prefs.valueForKey(k); return $persistentStore.read(k) }; const setval = setdata; const getval = getdata; const notify = (t, s, m) => { if (isSurge || isLoon) $notification.post(t, s, m); if (isQX) $notify(t, s, m) }; const msg = (t, s, m) => { if (isSurge || isLoon) $notification.post(t, s, m); if (isQX) $notify(t, s, m); console.log(`${t}\n${s}\n${m}`) }; const log = console.log; const done = v => { isQX ? $done(v) : $done(v) }; return { name, isLoon, isSurge, isQX, http, setdata, getdata, setval, getval, notify, msg, log, done }; }