/* * @name 青龙 XYYYAPP 变量自动上传 * @version v1.0.0 * @description 自动提取 3rdSession 并上传到青龙面板 XYYYAPP 变量 * @author Antigravity * * [rewrite_local] * ^https:\/\/gzpengru\.weimbo\.com\/api\/index\.php url script-request-header xyyx_qx.js * * [mitm] * hostname = gzpengru.weimbo.com * * ⚠️ 使用说明: * 1. 请并在下方配置青龙面板信息 QL_URL, QL_CLIENT_ID, QL_CLIENT_SECRET * 2. 将脚本添加到 Rewrite * 3. 触发请求即可自动上传 */ const $ = new Env("XYYYAPP自动上传"); // ---------------------- 用户配置区域 ---------------------- // 请在下方填写您的青龙面板信息 const QL_URL = "http://chickliu.store:5732"; // 例如 http://192.168.1.1:5700 const QL_CLIENT_ID = "M2HkEY-8RRWq"; // 应用ID const QL_CLIENT_SECRET = "-LHulEYdGa2TR7_th6oX4Zxb"; // 应用密钥 // --------------------------------------------------------- const TARGET_URL_KEY = "gzpengru.weimbo.com/api/index.php"; (async () => { try { if (typeof $request === "undefined") { $.msg($.name, "脚本运行环境错误", "请在 Quantumult X Rewrite 中使用 script-request-header"); return; } if ($request.url.indexOf(TARGET_URL_KEY) === -1) { return; } $.log(`[${$.name}] 开始捕获...`); // 1. 提取信息 const headers = $request.headers; // 查找 3rdSession,处理大小写可能不一致的情况 let session = null; for (const key in headers) { if (key.toLowerCase() === '3rdsession') { session = headers[key]; break; } } if (!session) { $.log(`[${$.name}] 未找到 3rdSession 头`); return; } $.log(`获取到 3rdSession: ${session}`); // 2. 登录青龙 const token = await qlLogin(); if (!token) return; // 3. 获取现有变量 const envs = await qlGetEnvs(token); let targetEnvId = null; let targetEnvValue = "[]"; const existingEnv = envs.find(e => e.name === "XYYYAPP"); if (existingEnv) { targetEnvId = existingEnv.id; targetEnvValue = existingEnv.value || "[]"; } // 4. 处理数据逻辑 let dataList = []; try { dataList = JSON.parse(targetEnvValue); if (!Array.isArray(dataList)) dataList = []; } catch (e) { $.log("原有变量格式不是JSON,重置为空数组"); dataList = []; } // 检查是否存在 const existingIndex = dataList.findIndex(item => item.cookie === session); let successMsg = ""; let needUpdate = false; if (existingIndex !== -1) { $.log(`检测到 Session 已存在: ${session}`); $.msg($.name, "无需更新", "Session 已存在且一致"); return; } else { // 新增 $.log(`检测到新 Session,添加数据`); dataList.push({ "cookie": session }); successMsg = `Session 添加成功`; needUpdate = true; } if (!needUpdate) return; const newEnvValue = JSON.stringify(dataList); // 5. 上传/更新变量 if (targetEnvId) { await qlUpdateEnv(token, targetEnvId, "XYYYAPP", newEnvValue, successMsg); } else { await qlAddEnv(token, [{ name: "XYYYAPP", value: newEnvValue }], successMsg); } } catch (e) { $.logErr(e); $.msg($.name, "运行时错误", e.message); } finally { $.done(); } })(); // ---------------------- 辅助函数 ---------------------- // 青龙 API: 登录 async function qlLogin() { const options = { url: `${QL_URL}/open/auth/token?client_id=${QL_CLIENT_ID}&client_secret=${QL_CLIENT_SECRET}`, timeout: 10000 }; return new Promise((resolve) => { $.get(options, (err, resp, data) => { try { if (err) throw new Error(JSON.stringify(err)); const body = JSON.parse(data); if (body.code === 200) { resolve(body.data.token); } else { $.msg($.name, "青龙登录失败", body.message); resolve(null); } } catch (e) { $.msg($.name, "青龙登录异常", "请检查 URL 和 Client ID/Secret 设置"); $.logErr(e); resolve(null); } }); }); } // 青龙 API: 获取变量 async function qlGetEnvs(token) { const options = { url: `${QL_URL}/open/envs?searchValue=XYYYAPP`, headers: { "Authorization": `Bearer ${token}` }, timeout: 10000 }; return new Promise((resolve) => { $.get(options, (err, resp, data) => { try { if (err) throw new Error(JSON.stringify(err)); const body = JSON.parse(data); if (body.code === 200) { resolve(body.data); } else { resolve([]); } } catch (e) { $.logErr(e); resolve([]); } }); }); } // 青龙 API: 更新变量 async function qlUpdateEnv(token, id, name, value, msg) { const options = { url: `${QL_URL}/open/envs`, method: "PUT", headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify({ id: id, name: name, value: value }), timeout: 10000 }; return new Promise((resolve) => { $.put(options, (err, resp, data) => { try { if (err) throw new Error(JSON.stringify(err)); const body = JSON.parse(data); if (body.code === 200) { $.msg($.name, "操作成功", msg || "变量已更新"); } else { $.msg($.name, "更新失败", body.message); } } catch (e) { $.logErr(e); $.msg($.name, "更新异常", e.message); } resolve(); }); }); } // 青龙 API: 新增变量 async function qlAddEnv(token, envsArray, msg) { const options = { url: `${QL_URL}/open/envs`, method: "POST", headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify(envsArray), timeout: 10000 }; return new Promise((resolve) => { $.post(options, (err, resp, data) => { try { if (err) throw new Error(JSON.stringify(err)); const body = JSON.parse(data); if (body.code === 200) { $.msg($.name, "操作成功", msg || "XYYYAPP 变量已创建"); } else { $.msg($.name, "上传失败", body.message); } } catch (e) { $.logErr(e); $.msg($.name, "上传异常", e.message); } resolve(); }); }); } // ---------------------- Env Class ---------------------- function Env(name, env) { "undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0); return new class { constructor(name, env) { this.name = name; this.notifyStr = ''; this.startTime = (new Date).getTime(); Object.assign(this, env); this.log("", `🔔${this.name}, 开始!`); } isNode() { return "undefined" != typeof module && !!module.exports } isQuanX() { return "undefined" != typeof $task } isSurge() { return "undefined" != typeof $httpClient && "undefined" == typeof $loon } isLoon() { return "undefined" != typeof $loon } get(options, callback) { if (this.isQuanX()) { if (typeof options == "string") options = { url: options } options["method"] = "GET" $task.fetch(options).then(response => { callback(null, response, response.body) }, reason => callback(reason.error, null, null)) } if (this.isSurge() || this.isLoon()) { $httpClient.get(options, (error, response, body) => { callback(error, response, body) }) } if (this.isNode()) { this.got = this.got ? this.got : require("got"); const { url, ...otherOptions } = options; this.got.get(url, otherOptions).then(response => { const { statusCode, headers, body } = response; callback(null, { status: statusCode, statusCode, headers, body }, body) }, error => { const { message, response } = error; callback(message, response, response && response.body) }) } } post(options, callback) { if (this.isQuanX()) { if (typeof options == "string") options = { url: options } options["method"] = "POST" $task.fetch(options).then(response => { callback(null, response, response.body) }, reason => callback(reason.error, null, null)) } if (this.isSurge() || this.isLoon()) { $httpClient.post(options, (error, response, body) => { callback(error, response, body) }) } if (this.isNode()) { this.got = this.got ? this.got : require("got"); const { url, ...otherOptions } = options; this.got.post(url, otherOptions).then(response => { const { statusCode, headers, body } = response; callback(null, { status: statusCode, statusCode, headers, body }, body) }, error => { const { message, response } = error; callback(message, response, response && response.body) }) } } put(options, callback) { if (this.isQuanX()) { if (typeof options == "string") options = { url: options } options["method"] = "PUT" $task.fetch(options).then(response => { callback(null, response, response.body) }, reason => callback(reason.error, null, null)) } if (this.isSurge() || this.isLoon()) { options.method = 'PUT'; $httpClient.put(options, (error, response, body) => { callback(error, response, body) }) } if (this.isNode()) { this.got = this.got ? this.got : require("got"); const { url, ...otherOptions } = options; this.got.put(url, otherOptions).then(response => { const { statusCode, headers, body } = response; callback(null, { status: statusCode, statusCode, headers, body }, body) }, error => { const { message, response } = error; callback(message, response, response && response.body) }) } } msg(title = name, subtitle = '', body = '') { const opts = (val) => { if (this.isLoon()) return { openUrl: val } if (this.isQuanX()) return { 'open-url': val } if (this.isSurge()) return { url: val } return {} } if (this.isSurge() || this.isLoon()) { $notification.post(title, subtitle, body) } if (this.isQuanX()) { $notify(title, subtitle, body) } this.log('==============📣系统通知📣==============') this.log(title) if (subtitle) this.log(subtitle) if (body) this.log(body) } log(...logs) { if (logs.length > 0) { this.logs = [...(this.logs || []), ...logs] } console.log(logs.join(this.logSeparator || "\n")) } logErr(err, msg) { const isSurge = this.isSurge() const isQuanX = this.isQuanX() const isLoon = this.isLoon() if (!isSurge && !isQuanX && !isLoon) { this.log('', `❗️${this.name}, 错误!`, err.stack) } else { this.log('', `❗️${this.name}, 错误!`, err) } } wait(time) { return new Promise(resolve => setTimeout(resolve, time)) } done(val = {}) { const endTime = (new Date).getTime() const costTime = (endTime - this.startTime) / 1000 this.log('', `🔔${this.name}, 结束! 🕛 ${costTime} 秒`) this.log() if (this.isSurge() || this.isQuanX() || this.isLoon()) { $done(val) } } }(name, env) }