diff --git a/ikuuu-auto-checkin.js b/ikuuu-auto-checkin.js index 9bf8694..612aa57 100644 --- a/ikuuu-auto-checkin.js +++ b/ikuuu-auto-checkin.js @@ -1,184 +1,144 @@ /* -填写注册的邮箱和密码,多账号使用;隔开 -export Ikuuu_EMAIL="xxx@.com;xxx@com" -export Ikuuu_PASSWD="A123;A123" -export Ikuuu_HOST="ikuuu.one" -由于 ikuuu 经常更换域名,添加 HOST 环境变量,默认为ikuuu.one。若域名更改,修改 HOST 的值为对应域名即可 + iKuuu 签到 + 流量查询 + 通知 + 青龙面板脚本 + + 环境变量: + - IKUuu_HOST: iKuuu 域名,默认 ikuuu.win + - IKUuu_ACCOUNTS: 账号 JSON 数组 + 示例: [{"name":"账号1","cookie":"xxx"},{"name":"账号2","cookie":"yyy"}] cron: 33 08 * * * const $ = new Env("ikuuu 机场签到"); */ -const { sendNotify } = require("./sendNotify"); -const fs = require('fs'); -const path = require('path'); -// 配置类 -class Config { - static get HOST() { - return process.env.Ikuuu_HOST || "ikuuu.one"; - } +// ============ 环境变量 ============ +const HOST = process.env.IKUuu_HOST || "ikuuu.win"; +const ACCOUNTS_JSON = process.env.IKUuu_ACCOUNTS || "[]"; - static get PROTOCOL_PREFIX() { - return "https://"; - } +const CHECKIN_URL = `https://${HOST}/user/checkin`; +const USER_URL = `https://${HOST}/user`; - static get LOGIN_URL() { - return `${Config.PROTOCOL_PREFIX}${Config.HOST}/auth/login`; - } - - static get CHECKIN_URL() { - return `${Config.PROTOCOL_PREFIX}${Config.HOST}/user/checkin`; +// ============ 工具函数 ============ +function decodeBase64(str) { + try { + const text = atob(str); + const bytes = new Uint8Array(text.length); + for (let i = 0; i < text.length; i++) { + bytes[i] = text.charCodeAt(i); } + return new TextDecoder().decode(bytes); + } catch (e) { + return decodeURIComponent(atob(str).split("").map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")); + } } -// 日志配置 -const logStream = fs.createWriteStream(path.join(__dirname, 'ikuuu.log'), { flags: 'a' }); - -function log(level, message) { - const timestamp = new Date().toISOString(); - const logMessage = `[${timestamp}] [${level}] ${message}\n`; - logStream.write(logMessage); - console.log(logMessage); +// ============ 签到 ============ +async function checkIn(account) { + try { + const response = await fetch(CHECKIN_URL, { + method: "POST", + headers: { + "Cookie": account.cookie, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); + + const data = await response.json(); + + let bonus = null; + if (data.msg) { + const match = data.msg.match(/(\d+\.?\d*)\s*([KMGT]?B)/i); + if (match) bonus = `${match[1]} ${match[2].toUpperCase()}`; + } + + if (data.ret === 1) { + console.log(`✅ ${account.name} 签到成功`); + if (bonus) console.log(` +${bonus}`); + return { success: true, bonus, msg: data.msg }; + } else { + console.log(`❌ ${account.name}: ${data.msg}`); + return { success: false, bonus: null, msg: data.msg }; + } + } catch (error) { + console.error(`[ERROR] ${account.name}: ${error.message}`); + return { success: false, bonus: null, msg: error.message }; + } } -// Cookie 工具类 -class CookieUtil { - static parseCookie(rawCookie) { - let cookieSets = rawCookie.split("path=/,"); - const cookies = {}; - - cookieSets.forEach((cookie) => { - const match = cookie.match(/^([^=]+)=(.*?);/); - if (match) { - const fieldName = match[1].trim(); - let fieldValue = match[2].trim(); - fieldValue = decodeURIComponent(fieldValue); - - if (!cookies[fieldName]) { - cookies[fieldName] = fieldValue; - } - } - }); - - return cookies; - } - - static generateCookieStr(cookieObject) { - return Object.entries(cookieObject) - .map(([key, value]) => `${key}=${encodeURIComponent(value)}`) - .join("; "); +// ============ 查询剩余流量 ============ +async function getTraffic(account) { + try { + const data = await fetch(USER_URL, { + headers: { Cookie: account.cookie } + }).then(r => r.text()); + + const originBodyMatch = data.match(/var originBody = "([^"]+)"/); + let rest = "N/A"; + + if (originBodyMatch && originBodyMatch[1]) { + const decodeData = decodeBase64(originBodyMatch[1]); + const match = decodeData.match(/

剩余流量<\/h4>[\s\S]*?([\d.]+)<\/span>\s*([A-Za-z]+)/); + if (match) rest = `${match[1]} ${match[2]}`; } + + console.log(`📊 ${account.name} 剩余流量: ${rest}`); + return rest; + } catch (error) { + console.log(`[ERROR] ${account.name} 流量查询: ${error.message}`); + return "Error"; + } } -// Ikuuu 客户端类 -class IkuuuClient { - constructor(email, password) { - this.email = email; - this.password = password; - } - - async login() { - log('INFO', `Logging in with email: ${this.email}...`); - - let formData = new FormData(); - formData.append("host", Config.HOST); - formData.append("email", this.email); - formData.append("passwd", this.password); - formData.append("code", ""); - formData.append("remember_me", "off"); - - try { - let response = await fetch(Config.LOGIN_URL, { - method: "POST", - body: formData, - }); - - let rawCookie = response.headers.get("set-cookie"); - let responseJson = await response.json(); - - if (responseJson) { - log('INFO', responseJson.msg); - } - - return CookieUtil.parseCookie(rawCookie); - } catch (error) { - log('ERROR', `Login failed for ${this.email}: ${error.message}`); - throw error; - } - } - - async checkIn(cookie) { - try { - let response = await fetch(Config.CHECKIN_URL, { - method: "POST", - headers: { - Cookie: CookieUtil.generateCookieStr(cookie), - }, - }); - - let responseJson = await response.json(); - if (responseJson) { - log('INFO', responseJson.msg); - } - } catch (error) { - log('ERROR', `Check-in failed for ${this.email}: ${error.message}`); - throw error; - } - } -} - -// 延迟函数,单位为毫秒 -function delay(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - +// ============ 主函数 ============ async function main() { - let emails = process.env.Ikuuu_EMAIL; - let passwords = process.env.Ikuuu_PASSWD; - - if (!emails || !passwords) { - log('ERROR', "ENV ERROR: Please set both Ikuuu_EMAIL and Ikuuu_PASSWD."); - process.exit(1); - } - - let emailList = emails.split(";"); - let passwdList = passwords.split(";"); - - if (emailList.length !== passwdList.length) { - log('ERROR', "Error: The number of emails does not match the number of passwords."); - process.exit(1); - } - - let notifications = []; - - for (let i = 0; i < emailList.length; i++) { - let email = emailList[i]; - let passwd = passwdList[i]; - let client = new IkuuuClient(email, passwd); - - try { - let cookie = await client.login(); - await client.checkIn(cookie); - notifications.push(`账号 ${email} 登录成功,签到完成`); - } catch (error) { - notifications.push(`账号 ${email} 操作失败: ${error.message}`); - } - - await delay(2000); // 延迟 2 秒 - } - - // 过滤掉 undefined 值 - const notificationMessage = notifications - .filter(msg => msg !== undefined) - .join("\n"); - - // 调试:打印通知数组 - console.log("通知数组内容:", notifications); - - sendNotify(`多个账号操作完成:\n${notificationMessage}`); + console.log("======== iKuuu 签到 + 流量查询 ========\n"); + console.log(`HOST: ${HOST}\n`); + + let accounts; + try { + accounts = JSON.parse(ACCOUNTS_JSON); + } catch (e) { + console.log("[ERROR] IKUuu_ACCOUNTS 格式错误,请检查 JSON 格式!"); + return; + } + + if (!accounts.length) { + console.log("[ERROR] 未配置账号! 请设置 IKUuu_ACCOUNTS 环境变量"); + return; + } + + console.log(`检测到 ${accounts.length} 个账号\n`); + + const results = []; + + for (const account of accounts) { + console.log(`\n--- ${account.name} ---`); + + const checkin = await checkIn(account); + const traffic = await getTraffic(account); + + results.push({ name: account.name, checkin, traffic }); + } + + console.log("\n======== 签到完成 ========"); + + // ============ 发送通知 ============ + const { sendNotify } = require("./sendNotify"); + + let msg = `iKuuu 签到 + 流量查询\n\n`; + + for (const r of results) { + const status = r.checkin.success ? "✅" : "❌"; + const bonus = r.checkin.bonus ? `\n 签到获得: ${r.checkin.bonus}` : ""; + msg += `${status} ${r.name}\n`; + msg += ` 签到: ${r.checkin.success ? "成功" : r.checkin.msg}${bonus}\n`; + msg += ` 剩余: ${r.traffic}\n\n`; + } + + await sendNotify("iKuuu 签到", msg); } main().catch(error => { - log('ERROR', `Main function failed: ${error.message}`); - process.exit(1); + console.error(`[ERROR] ${error.message}`); + process.exit(1); });