401 lines
13 KiB
JavaScript
401 lines
13 KiB
JavaScript
/*
|
|
* @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)
|
|
}
|