Initial commit: new history

This commit is contained in:
king
2025-06-30 21:59:46 +08:00
commit cd32a8c7e5
1945 changed files with 111356 additions and 0 deletions

265
Scripts/qinglong/api.js Normal file
View File

@ -0,0 +1,265 @@
'use strict';
const got = require('got');
require('dotenv').config();
const {readFile} = require('fs/promises');
const fs = require('fs');
let fileExists = fs.existsSync('/ql/data/config/auth.json');
let authFile = "";
if (fileExists)
authFile = "/ql/data/config/auth.json"
else
authFile = "/ql/config/auth.json"
const api = got.extend({
prefixUrl: 'http://127.0.0.1:5600',
retry: {limit: 0},
});
async function getToken() {
const authConfig = JSON.parse(await readFile(authFile));
return authConfig.token;
}
module.exports.getEnvsByNameBackUp = async (searchValue) => {
const token = await getToken();
const body = await api({
url: 'api/envs',
searchParams: {
searchValue: searchValue,
t: Date.now(),
},
headers: {
'Accept': 'application/json',
'authorization': `Bearer ${token}`,
'host': '127.0.0.1',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
},
}).json();
return body.data;
};
module.exports.getEnvsByName = async (searchValue) => {
const token = await getToken();
const url = `http://127.0.0.1:5600/api/envs?searchValue=${searchValue}&t=` + Date.now();
const headers = {
"Accept": "application/json",
"authorization": `Bearer ${token}`,
"Content-Type": "application/json;charset=UTF-8",
"host": "127.0.0.1",
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
const request = {
method: "get",
headers: headers
}
console.log("url=" + url);
console.log("request=" + JSON.stringify(request));
fetch(url, request)
.then(response => {
console.log(response.status + "\n\n" + response.statusText);
return response.text();
})
.then(body => {
console.log(body);
})
.catch(error => {
console.log(error);
});
};
module.exports.getEnvsCount = async () => {
const data = await this.getEnvsByName();
return data.length;
};
module.exports.addEnv = async (cookie, remarks) => {
const token = await getToken();
return await api({
method: 'post',
url: 'api/envs',
params: {t: Date.now()},
json: [{
name: 'JD_COOKIE',
value: cookie,
remarks,
}],
headers: {
Accept: 'application/json',
authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}).json();
};
module.exports.updateEnv = async (value, eid, remarks) => {
const token = await getToken();
const body = await api({
method: 'put',
url: 'api/envs',
params: {t: Date.now()},
json: {
name: 'JD_COOKIE',
value: value,
_id: eid,
remarks,
},
headers: {
Accept: 'application/json',
authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}).json();
return body;
};
module.exports.updateEnvByIdBackUp = async (name, value, eid, remarks) => {
const token = await getToken();
return await api({
method: 'put',
url: 'api/envs',
params: {t: Date.now()},
json: {
name: name,
value: value,
id: eid,
remarks,
},
headers: {
Accept: 'application/json',
authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}).json();
};
// id是必传字段否则青龙会报错
module.exports.updateEnvById = async (id, name, value, remarks) => {
const token = await getToken();
const url = "http://127.0.0.1:5600/api/envs?t=" + Date.now();
const headers = {
"Accept": "application/json",
"authorization": `Bearer ${token}`,
"Content-Type": "application/json;charset=UTF-8",
"host": "127.0.0.1",
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
const body = {
"id": id,
"name": name,
"value": value,
"remarks": remarks
};
const request = {
method: "put",
headers: headers,
body: JSON.stringify(body)
}
console.log("request=" + JSON.stringify(request));
fetch(url, request)
.then(response => {
console.log(response.status + "\n\n" + response.statusText);
return response.text();
})
.then(body => {
console.log(body);
})
.catch(error => {
console.log(error);
});
};
module.exports.DisableCk = async (eid) => {
const token = await getToken();
const body = await api({
method: 'put',
url: 'api/envs/disable',
params: {t: Date.now()},
body: JSON.stringify([eid]),
headers: {
Accept: 'application/json',
authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}).json();
return body;
};
module.exports.EnableCk = async (eid) => {
const token = await getToken();
const body = await api({
method: 'put',
url: 'api/envs/enable',
params: {t: Date.now()},
body: JSON.stringify([eid]),
headers: {
Accept: 'application/json',
authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}).json();
return body;
};
module.exports.getStatus = async (eid) => {
const envs = await this.getEnvsByName();
var tempid = 0;
for (let i = 0; i < envs.length; i++) {
tempid = 0;
if (envs[i]._id) {
tempid = envs[i]._id;
}
if (envs[i].id) {
tempid = envs[i].id;
}
if (tempid == eid) {
return envs[i].status;
}
}
return 99;
};
module.exports.getEnvById = async (eid) => {
const envs = await this.getEnvsByName();
var tempid = 0;
for (let i = 0; i < envs.length; i++) {
tempid = 0;
if (envs[i]._id) {
tempid = envs[i]._id;
}
if (envs[i].id) {
tempid = envs[i].id;
}
if (tempid == eid) {
return envs[i].value;
}
}
return "";
};
module.exports.getEnvByPtPin = async (Ptpin) => {
const envs = await this.getEnvsByName();
for (let i = 0; i < envs.length; i++) {
var tempptpin = decodeURIComponent(envs[i].value.match(/pt_pin=([^; ]+)(?=;?)/) && envs[i].value.match(/pt_pin=([^; ]+)(?=;?)/)[1]);
if (tempptpin == Ptpin) {
return envs[i];
}
}
return "";
};
module.exports.delEnv = async (eid) => {
const token = await getToken();
const body = await api({
method: 'delete',
url: 'api/envs',
params: {t: Date.now()},
body: JSON.stringify([eid]),
headers: {
Accept: 'application/json',
authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}).json();
return body;
};

141
Scripts/qinglong/ql_api.js Normal file
View File

@ -0,0 +1,141 @@
$.ql = {
type: 'api',
headers: {
'Content-Type': `application/json;charset=UTF-8`,
Authorization: '',
},
disabled(ids) {
if (!this.headers.Authorization) return;
const opt = {
url: `${$.ql_url}/${this.type}/envs/disable`,
headers: this.headers,
body: JSON.stringify(ids),
};
return $.http.put(opt).then((response) => JSON.parse(response.body));
},
enabled(ids) {
if (!this.headers.Authorization) return;
const opt = {
url: `${$.ql_url}/${this.type}/envs/enable`,
headers: this.headers,
body: JSON.stringify(ids),
};
return $.http.put(opt).then((response) => JSON.parse(response.body));
},
delete(ids) {
if (!this.headers.Authorization) return;
const opt = {
url: `${$.ql_url}/${this.type}/envs`,
headers: this.headers,
body: JSON.stringify(ids),
};
return $.http.delete(opt).then((response) => JSON.parse(response.body));
},
add(records) {
if (!this.headers.Authorization) return;
const opt = {
url: `${$.ql_url}/${this.type}/envs`,
headers: this.headers,
body: JSON.stringify(records),
};
return $.http.post(opt).then((response) => JSON.parse(response.body));
},
edit(records) {
if (!this.headers.Authorization) return;
const opt = {
url: `${$.ql_url}/${this.type}/envs`,
headers: this.headers,
body: JSON.stringify(records),
};
return $.http.put(opt).then((response) => JSON.parse(response.body));
},
select(searchValue) {
if (!this.headers.Authorization) return;
const opt = {
url: `${$.ql_url}/${this.type}/envs?searchValue=${searchValue}`,
headers: this.headers,
};
return $.http.get(opt).then((response) => JSON.parse(response.body));
},
initial: () => {
$.ql_url = $.ql_config.ip;
if ($.ql_url && !$.ql_url.match(/^(http|https)/))
$.ql_url = `http://${$.ql_url}`;
$.application = {
client_id: $.ql_config.client_id,
client_secret: $.ql_config.client_secret,
};
$.ql_account = {
username: $.ql_config.username,
password: $.ql_config.password,
};
},
};
try {
$.ql_config = JSON.parse($.read('#ql'));
} catch (e) {
$.ql_config = {};
}
$.ql.initial();
$.log(`地址:${$.ql_url}`);
function noReady() {
$.ql = false;
$.log('请配置好相关信息');
}
if ($.ql_config.is_pwd === 'true') {
if ($.ql_account.username && $.ql_account.password) {
$.ql.login = async () => {
const options = {
url: `${$.ql_url}/api/user/login`,
body: JSON.stringify($.ql_account),
headers: {
'Content-Type': `application/json;charset=UTF-8`,
},
};
let response = await $.http.post(options);
response = JSON.parse(response.body);
if (response.code === 200) {
$.ql.type = 'api';
$.ql.headers.Authorization = `Bearer ${response.data.token}`;
$.log(`登陆成功:${response.data.lastaddr}`);
$.log(`ip:${response.data.lastip}`);
} else {
$.log(response);
$.log(`登陆失败:${response.message}`);
}
};
} else {
noReady();
}
} else {
if ($.application.client_id && $.application.client_secret) {
$.ql.login = async () => {
const options = {
url: `${$.ql_url}/open/auth/token?client_id=${$.application.client_id}&client_secret=${$.application.client_secret}`,
headers: {
'Content-Type': `application/json;charset=UTF-8`,
},
};
let response = await $.http.get(options);
response = JSON.parse(response.body);
if (response.code === 200) {
$.ql.type = 'open';
$.ql.headers.Authorization = `Bearer ${response.data.token}`;
$.log(`登陆成功`);
} else {
$.log(response);
$.log(`登陆失败:${response.message}`);
}
};
} else {
noReady();
}
}

413
Scripts/qinglong/ql_sync.js Normal file
View File

@ -0,0 +1,413 @@
/**
* 作者fmz200修改自dompling的ql_cookie_sync.js
* 作用定时同步BoxJS中的数据到青龙环境变量每日自动同步
* 配置40 0 * * * https://raw.githubusercontent.com/fmz200/wool_scripts/main/Scripts/qinglong/ql_sync.js
* 定时QX导入订阅 https://raw.githubusercontent.com/fmz200/wool_scripts/main/boxjs/fmz200_gallery.json
* 使用详见BoxJS页面 https://raw.githubusercontent.com/fmz200/wool_scripts/main/boxjs/fmz200.boxjs.json
* 更新2023-06-04 13:30
*/
const $ = new API('ql', true);
const title = '🐉 同步通知';
const sync_keys = $.read('#ql_sync_keys').replace(/\s/g, '').split(',') || [];
if (sync_keys.length === 0) {
$.notify(title, '', `未填写需要同步的keys请在BoxJS填写正确`);
$.done();
}
let remark = {};
!(async () => {
// 只登陆一次
const ql_script = (await getScriptUrl()) || '';
eval(ql_script);
await $.ql.login();
// 开始同步数据
for await (const key of sync_keys) {
await autoSync(key);
}
const keyText = sync_keys.map((item) => item).join(`\n`);
if ($.read('ql_sync_notify') !== 'true') {
$.notify(title, '', `已同步以下keys的数据\n${keyText}`);
}
$.done();
})();
async function autoSync(key_remark) {
$.log(`--------------------`);
try {
// key可能包含两部分key@remark
let key;
let remark;
if (key_remark.includes('@')) {
[key, remark] = key_remark.split('@');
} else {
key = key_remark;
remark = 'BoxJS同步的数据'; // 如果没有备注,可以设置为 null 或其他默认值
}
const values = await $.ql.select(key); // 同一个key可能有多个值暂时只做一个的同步
await $.ql.delete(values.data.map((item) => item.id));
$.log(`已清空${key}的数据`);
const addData = [];
const key_value = $.read(`#${key}`);
$.log(`已读取${key}的数据`);
addData.push({name: key, value: key_value, remarks: remark});
if (addData.length) await $.ql.add(addData);
$.log(`已同步${key}的数据`);
} catch (e) {
$.log(`同步${key_remark}的数据时发生错误:` + JSON.stringify(e));
}
$.log(`--------------------`);
}
async function getScriptUrl() {
const response = await $.http.get({
url: 'https://raw.githubusercontent.com/fmz200/wool_scripts/main/Scripts/qinglong/ql_api.js',
});
return response.body;
}
function getURL(api, key = 'api') {
return `${baseURL}/${key}/${api}`;
}
function login() {
const opt = {
headers,
url: getURL('login'),
body: JSON.stringify(account),
};
return $.http.post(opt).then((response) => JSON.parse(response.body));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function ENV() {
const isQX = typeof $task !== 'undefined';
const isLoon = typeof $loon !== 'undefined';
const isSurge = typeof $httpClient !== 'undefined' && !isLoon;
const isJSBox = typeof require == 'function' && typeof $jsbox != 'undefined';
const isNode = typeof require == 'function' && !isJSBox;
const isRequest = typeof $request !== 'undefined';
const isScriptable = typeof importModule !== 'undefined';
return {isQX, isLoon, isSurge, isNode, isJSBox, isRequest, isScriptable};
}
function HTTP(defaultOptions = {baseURL: ''}) {
const {isQX, isLoon, isSurge, isScriptable, isNode} = ENV();
const methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH'];
const URL_REGEX =
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
function send(method, options) {
options = typeof options === 'string' ? {url: options} : options;
const baseURL = defaultOptions.baseURL;
if (baseURL && !URL_REGEX.test(options.url || '')) {
options.url = baseURL ? baseURL + options.url : options.url;
}
options = {...defaultOptions, ...options};
const timeout = options.timeout;
const events = {
...{
onRequest: () => {
},
onResponse: (resp) => resp,
onTimeout: () => {
},
},
...options.events,
};
events.onRequest(method, options);
let worker;
if (isQX) {
worker = $task.fetch({method, ...options});
} else if (isLoon || isSurge || isNode) {
worker = new Promise((resolve, reject) => {
const request = isNode ? require('request') : $httpClient;
request[method.toLowerCase()](options, (err, response, body) => {
if (err) reject(err);
else
resolve({
statusCode: response.status || response.statusCode,
headers: response.headers,
body,
});
});
});
} else if (isScriptable) {
const request = new Request(options.url);
request.method = method;
request.headers = options.headers;
request.body = options.body;
worker = new Promise((resolve, reject) => {
request
.loadString()
.then((body) => {
resolve({
statusCode: request.response.statusCode,
headers: request.response.headers,
body,
});
})
.catch((err) => reject(err));
});
}
let timeoutid;
const timer = timeout
? new Promise((_, reject) => {
timeoutid = setTimeout(() => {
events.onTimeout();
return reject(
`${method} URL: ${options.url} exceeds the timeout ${timeout} ms`
);
}, timeout);
})
: null;
return (
timer
? Promise.race([timer, worker]).then((res) => {
clearTimeout(timeoutid);
return res;
})
: worker
).then((resp) => events.onResponse(resp));
}
const http = {};
methods.forEach(
(method) =>
(http[method.toLowerCase()] = (options) => send(method, options))
);
return http;
}
function API(name = 'untitled', debug = false) {
const {isQX, isLoon, isSurge, isNode, isJSBox, isScriptable} = ENV();
return new (class {
constructor(name, debug) {
this.name = name;
this.debug = debug;
this.http = HTTP();
this.env = ENV();
this.node = (() => {
if (isNode) {
const fs = require('fs');
return {
fs,
};
} else {
return null;
}
})();
this.initCache();
const delay = (t, v) =>
new Promise(function (resolve) {
setTimeout(resolve.bind(null, v), t);
});
Promise.prototype.delay = function (t) {
return this.then(function (v) {
return delay(t, v);
});
};
}
// persistance
// initialize cache
initCache() {
if (isQX) this.cache = JSON.parse($prefs.valueForKey(this.name) || '{}');
if (isLoon || isSurge)
this.cache = JSON.parse($persistentStore.read(this.name) || '{}');
if (isNode) {
// create a json for root cache
let fpath = 'root.json';
if (!this.node.fs.existsSync(fpath)) {
this.node.fs.writeFileSync(
fpath,
JSON.stringify({}),
{flag: 'wx'},
(err) => console.log(err)
);
}
this.root = {};
// create a json file with the given name if not exists
fpath = `${this.name}.json`;
if (!this.node.fs.existsSync(fpath)) {
this.node.fs.writeFileSync(
fpath,
JSON.stringify({}),
{flag: 'wx'},
(err) => console.log(err)
);
this.cache = {};
} else {
this.cache = JSON.parse(
this.node.fs.readFileSync(`${this.name}.json`)
);
}
}
}
// store cache
persistCache() {
const data = JSON.stringify(this.cache);
if (isQX) $prefs.setValueForKey(data, this.name);
if (isLoon || isSurge) $persistentStore.write(data, this.name);
if (isNode) {
this.node.fs.writeFileSync(
`${this.name}.json`,
data,
{flag: 'w'},
(err) => console.log(err)
);
this.node.fs.writeFileSync(
'root.json',
JSON.stringify(this.root),
{flag: 'w'},
(err) => console.log(err)
);
}
}
write(data, key) {
this.log(`SET ${key}`);
if (key.indexOf('#') !== -1) {
key = key.substr(1);
if (isSurge || isLoon) {
return $persistentStore.write(data, key);
}
if (isQX) {
return $prefs.setValueForKey(data, key);
}
if (isNode) {
this.root[key] = data;
}
} else {
this.cache[key] = data;
}
this.persistCache();
}
read(key) {
this.log(`READ ${key}`);
if (key.indexOf('#') !== -1) {
key = key.substr(1);
if (isSurge || isLoon) {
return $persistentStore.read(key);
}
if (isQX) {
return $prefs.valueForKey(key);
}
if (isNode) {
return this.root[key];
}
} else {
return this.cache[key];
}
}
delete(key) {
this.log(`DELETE ${key}`);
if (key.indexOf('#') !== -1) {
key = key.substr(1);
if (isSurge || isLoon) {
return $persistentStore.write(null, key);
}
if (isQX) {
return $prefs.removeValueForKey(key);
}
if (isNode) {
delete this.root[key];
}
} else {
delete this.cache[key];
}
this.persistCache();
}
// notification
notify(title, subtitle = '', content = '', options = {}) {
const openURL = options['open-url'];
const mediaURL = options['media-url'];
if (isQX) $notify(title, subtitle, content, options);
if (isSurge) {
$notification.post(
title,
subtitle,
content + `${mediaURL ? '\n多媒体:' + mediaURL : ''}`,
{
url: openURL,
}
);
}
if (isLoon) {
let opts = {};
if (openURL) opts['openUrl'] = openURL;
if (mediaURL) opts['mediaUrl'] = mediaURL;
if (JSON.stringify(opts) == '{}') {
$notification.post(title, subtitle, content);
} else {
$notification.post(title, subtitle, content, opts);
}
}
if (isNode || isScriptable) {
const content_ =
content +
(openURL ? `\n点击跳转: ${openURL}` : '') +
(mediaURL ? `\n多媒体: ${mediaURL}` : '');
if (isJSBox) {
const push = require('push');
push.schedule({
title: title,
body: (subtitle ? subtitle + '\n' : '') + content_,
});
} else {
console.log(`${title}\n${subtitle}\n${content_}\n\n`);
}
}
}
// other helper functions
log(msg) {
if (this.debug) console.log(msg);
}
info(msg) {
console.log(msg);
}
error(msg) {
console.log('ERROR: ' + msg);
}
wait(millisec) {
return new Promise((resolve) => setTimeout(resolve, millisec));
}
done(value = {}) {
if (isQX || isLoon || isSurge) {
$done(value);
} else if (isNode && !isJSBox) {
if (typeof $context !== 'undefined') {
$context.headers = value.headers;
$context.statusCode = value.statusCode;
$context.body = value.body;
}
}
}
})(name, debug);
}

View File

@ -0,0 +1,4 @@
## 青龙脚本

File diff suppressed because it is too large Load Diff