mirror of
https://github.com/smallfawn/QLScriptPublic.git
synced 2026-11-05 22:36:53 +08:00
Improve README updater workflow and relocate chery
Enhance .github workflow to robustly detect changed .js/.py files (uses git diff HEAD~1..HEAD with fallback), extract Env names, require anchor markers in README, and parse/update the markdown table safely; add clearer Chinese logs and adjust commit/push step messaging. Insert anchor comments into README.md to mark the table region. Remove legacy chery.js and cheryev.js files and add a new daily/chery.js implementation (refactored script using axios/CryptoJS and modular Env tool).
This commit is contained in:
1 parent
e599f538e3
commit
b85c26039b
5 files changed
+295
-438
No files matched your search
@@ -35,82 +35,117 @@ jobs:
|
||||
import datetime
|
||||
import subprocess
|
||||
|
||||
# 1. 获取更改的文件列表
|
||||
# 1. 获取更改的文件列表(最近一次提交)
|
||||
try:
|
||||
# 获取当前提交与上一次提交之间的差异文件
|
||||
diff_cmd = ['git', 'diff', '--name-only', 'HEAD~1', 'HEAD']
|
||||
result = subprocess.run(diff_cmd, capture_output=True, text=True, check=True)
|
||||
changed_files = result.stdout.splitlines()
|
||||
except subprocess.CalledProcessError:
|
||||
# 如果没有上一次提交(例如第一次提交),则检查所有文件
|
||||
diff_cmd = ['git', 'diff', '--name-only', '--cached']
|
||||
result = subprocess.run(diff_cmd, capture_output=True, text=True, check=True)
|
||||
changed_files = result.stdout.splitlines()
|
||||
except Exception:
|
||||
changed_files = []
|
||||
|
||||
# 筛选出 .js 或 .py 且实际存在的文件
|
||||
target_files = [f for f in changed_files if (f.endswith('.js') or f.endswith('.py')) and os.path.exists(f)]
|
||||
if not target_files:
|
||||
print("No relevant file changes.")
|
||||
print("没有检测到相关脚本文件的变更,退出。")
|
||||
exit(0)
|
||||
|
||||
# 2. 提取 Env 名称
|
||||
# 2. 从变更文件中提取 Env 名称
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
updates = {}
|
||||
for f in target_files:
|
||||
with open(f, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
# 匹配 Env("名称") 或 Env('名称')
|
||||
match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', content)
|
||||
if match:
|
||||
updates[match.group(1)] = now
|
||||
|
||||
if not updates:
|
||||
print("No Env tags found in changed files.")
|
||||
print("变更的脚本文件中未找到 Env 标签,退出。")
|
||||
exit(0)
|
||||
|
||||
# 3. 修改 README
|
||||
# 3. 修改 README.md 中的表格
|
||||
readme_path = 'README.md'
|
||||
with open(readme_path, 'r', encoding='utf-8') as f:
|
||||
full_text = f.read()
|
||||
|
||||
# --- 核心修复:定义明确的锚点 ---
|
||||
start_tag = ""
|
||||
end_tag = ""
|
||||
# 定义锚点标记(请确保 README.md 中已添加这两个注释)
|
||||
start_tag = "<!-- README_TABLE_START -->"
|
||||
end_tag = "<!-- README_TABLE_END -->"
|
||||
|
||||
if start_tag not in full_text or end_tag not in full_text:
|
||||
print("Error: Anchor tags not found in README.md")
|
||||
print("错误:在 README.md 中未找到锚点标记!")
|
||||
print("请添加以下两行注释包裹表格区域:")
|
||||
print(f"{start_tag}")
|
||||
print(f"{end_tag}")
|
||||
exit(1)
|
||||
|
||||
# 分割文本
|
||||
pre_part, temp = full_text.split(start_tag)
|
||||
table_section, post_part = temp.split(end_tag)
|
||||
|
||||
# 处理旧表格内容
|
||||
# 解析现有表格
|
||||
lines = table_section.strip().split('\n')
|
||||
new_table_lines = []
|
||||
updated_names = set()
|
||||
header = []
|
||||
separator = []
|
||||
body_lines = []
|
||||
mode = 'header'
|
||||
|
||||
for line in lines:
|
||||
if line.strip().startswith('|') and '---' not in line and '脚本名称' not in line:
|
||||
parts = [p.strip() for p in line.split('|')]
|
||||
if len(parts) >= 4:
|
||||
name = parts[1]
|
||||
if name in updates:
|
||||
line = f"| {name} | {updates[name]} | ✅ |"
|
||||
updated_names.add(name)
|
||||
if line.strip():
|
||||
new_table_lines.append(line)
|
||||
line_stripped = line.strip()
|
||||
if not line_stripped.startswith('|'):
|
||||
continue
|
||||
if '脚本名称' in line_stripped:
|
||||
header.append(line)
|
||||
mode = 'separator'
|
||||
elif '---' in line_stripped and mode == 'separator':
|
||||
separator.append(line)
|
||||
mode = 'body'
|
||||
else:
|
||||
if mode == 'body':
|
||||
body_lines.append(line)
|
||||
|
||||
# 添加新脚本
|
||||
for name, time in updates.items():
|
||||
if name not in updated_names:
|
||||
new_table_lines.append(f"| {name} | {time} | ✅ |")
|
||||
if not header or not separator:
|
||||
print("错误:README 表格格式无效,缺少表头或分隔行。")
|
||||
exit(1)
|
||||
|
||||
# 组装
|
||||
header = ["| 脚本名称 | 最后一次更新时间 | 当前状态 |", "| :--- | :----: | :----: |"]
|
||||
final_table = "\n".join(header + new_table_lines)
|
||||
# 更新已有行,并记录已存在的脚本名称
|
||||
existing_names = set()
|
||||
new_body_lines = []
|
||||
for line in body_lines:
|
||||
parts = [p.strip() for p in line.split('|')]
|
||||
if len(parts) >= 4:
|
||||
name = parts[1]
|
||||
existing_names.add(name)
|
||||
if name in updates:
|
||||
line = f"| {name} | {updates[name]} | ✅ |"
|
||||
new_body_lines.append(line)
|
||||
|
||||
# 添加新增的脚本
|
||||
for name, tm in updates.items():
|
||||
if name not in existing_names:
|
||||
new_body_lines.append(f"| {name} | {tm} | ✅ |")
|
||||
|
||||
# 重新组合完整表格
|
||||
final_table = "\n".join(header + separator + new_body_lines)
|
||||
final_content = f"{pre_part}{start_tag}\n{final_table}\n{end_tag}{post_part}"
|
||||
|
||||
# 写回 README.md
|
||||
with open(readme_path, 'w', encoding='utf-8') as f:
|
||||
f.write(final_content)
|
||||
|
||||
print("README.md 表格更新成功。")
|
||||
EOF
|
||||
|
||||
python update_readme.py
|
||||
|
||||
- name: 提交并推送
|
||||
- name: 提交并推送变更
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
@@ -119,5 +154,5 @@ jobs:
|
||||
git commit -m "docs: 自动更新脚本状态 [skip ci]"
|
||||
git push
|
||||
else
|
||||
echo "Nothing to commit"
|
||||
echo "README.md 无变更,无需提交。"
|
||||
fi
|
||||
@@ -1,5 +1,5 @@
|
||||
### 脚本功能列表
|
||||
|
||||
<!-- README_TABLE_START -->
|
||||
| 脚本名称 | 最后一次更新时间 | 当前状态 |
|
||||
| :--- | :----: | :----: |
|
||||
| 海底捞签到 | 2026-04-02 09:00:00 | ✅ |
|
||||
@@ -8,6 +8,8 @@
|
||||
| 爱玛会员俱乐部 | 2026-04-02 09:08:43 | ✅ |
|
||||
| 快手极速版 | 2026-04-02 09:08:43 | ✅ |
|
||||
|
||||
<!-- README_TABLE_END -->
|
||||
|
||||
# 青龙面板拉库命令
|
||||
|
||||
`ql repo https://github.com/smallfawn/QLScriptPublic.git backup main`
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
/**
|
||||
* new Env("奇瑞汽车")
|
||||
* cron 09 18 * * * test_v2.js
|
||||
* Show:多账号分隔符@ 多变量分隔符&
|
||||
* 变量名:chery_data
|
||||
* 变量值:mobile-consumer-sapp.chery.cn请求头Authorization 去掉bearer
|
||||
* scriptVersionNow = "0.0.1";
|
||||
*/
|
||||
|
||||
const $ = new Env("奇瑞汽车");
|
||||
const ckName = "chery_data";
|
||||
const Notify = 1; //0为关闭通知,1为打开通知,默认为1
|
||||
let envSplitor = ["@", "\n"]; //多账号分隔符
|
||||
let strSplitor = '&'; //多变量分隔符
|
||||
let scriptVersionNow = "0.0.1";
|
||||
const JSConfig = {
|
||||
jsUrl: "https://originfastly.jsdelivr.net/gh/smallfawn/Note@main/JavaScript/test_v2.js",
|
||||
noticeUrl: `https://originfastly.jsdelivr.net/gh/smallfawn/Note@main/Notice.json`,
|
||||
}
|
||||
|
||||
|
||||
class UserInfo {
|
||||
constructor(str) {
|
||||
this.index = ++$.userIdx;
|
||||
this.ck = str.split(strSplitor)[0]; //单账号多变量分隔符
|
||||
this.ckStatus = true;
|
||||
this.headers_get = {
|
||||
"Host": "mobile-consumer-sapp.chery.cn",
|
||||
"Connection": "keep-alive",
|
||||
"Authorization": "Bearer " + this.ck,
|
||||
"accept-language": "zh-CN,zh",
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/81.0.4044.138 Mobile Safari/537.36 android/1.0.0",
|
||||
"content-type": "application/json",
|
||||
"Accept": "*/*",
|
||||
"Origin": "https://hybrid-sapp.chery.cn",
|
||||
"X-Requested-With": "com.digitalmall.chery",
|
||||
"Sec-Fetch-Site": "same-site",
|
||||
"Sec-Fetch-Mode": "cors",
|
||||
"Sec-Fetch-Dest": "empty",
|
||||
"Referer": "https://hybrid-sapp.chery.cn/package-mine/pages/sign-in/sign-in",
|
||||
"Accept-Encoding": "gzip, deflate"
|
||||
};
|
||||
this.articleIdList = null
|
||||
this.user_name = ``
|
||||
this.user_point = ``
|
||||
|
||||
}
|
||||
async main() {
|
||||
await this.user_info()
|
||||
if (this.ckStatus == true) {
|
||||
await this.task_signIn()
|
||||
await this.article_list()
|
||||
for (let articleId of this.articleIdList) {
|
||||
await this.task_share(articleId)
|
||||
}
|
||||
$.msg(`[昵称] ${this.user_name}`, `积分${this.user_point}`, `正常`)
|
||||
}
|
||||
|
||||
}
|
||||
async user_info() {
|
||||
try {
|
||||
let options = {
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/user/current/details?access_token=${this.ck}&terminal=3`,
|
||||
headers: this.headers_get,
|
||||
},
|
||||
result = await httpRequest(options);
|
||||
//console.log(options);
|
||||
//console.log(result);
|
||||
if (result.status == 200) {
|
||||
$.DoubleLog(`✅账号[${this.index}] 【昵称】[${result.data.displayName}] 【积分】[${result.data.pointAccount.payableBalance}]🎉`);
|
||||
this.user_name = result.data.displayName
|
||||
this.user_point = result.data.pointAccount.payableBalance
|
||||
this.ckStatus = true;
|
||||
} else {
|
||||
$.DoubleLog(`❌账号[${this.index}] [${result.message}]`);
|
||||
this.ckStatus = false;
|
||||
//console.log(result);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
async task_signIn() {
|
||||
try {
|
||||
let options = {
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/event/trigger?access_token=${this.ck}`,
|
||||
headers: {
|
||||
"Host": "mobile-consumer-sapp.chery.cn",
|
||||
"Connection": "keep-alive",
|
||||
"Content-Length": "23",
|
||||
"Authorization": "Bearer " + this.ck,
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/81.0.4044.138 Mobile Safari/537.36 android/1.0.0",
|
||||
"content-type": "application/json",
|
||||
"Accept": "/",
|
||||
"Origin": "https://hybrid-sapp.chery.cn",
|
||||
"X-Requested-With": "com.digitalmall.chery",
|
||||
"Sec-Fetch-Site": "same-site",
|
||||
"Sec-Fetch-Mode": "cors",
|
||||
"Sec-Fetch-Dest": "empty",
|
||||
"Referer": "https://hybrid-sapp.chery.cn/package-mine/pages/sign-in/sign-in",
|
||||
"Accept-Encoding": "gzip, deflate"
|
||||
},
|
||||
body: JSON.stringify({ "eventCode": "SJ10002" })
|
||||
|
||||
},
|
||||
result = await httpRequest(options);
|
||||
//console.log(options);
|
||||
//console.log(result);
|
||||
if (result.status == 200) {
|
||||
$.DoubleLog(`✅账号[${this.index}] 【签到】[${result.message}]🎉`);
|
||||
} else {
|
||||
$.DoubleLog(`❌账号[${this.index}] 【签到】[${result.message}]`);
|
||||
//console.log(result);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
async article_list() {
|
||||
try {
|
||||
let options = {
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/community/recommend/contents?pageNo=1&pageSize=10&access_token=${this.ck}&terminal=3`,
|
||||
headers: {
|
||||
"user-agent": "Dart/2.17 (dart:io)",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"appversion": `2.17.6 (stable) (Tue Jul 12 12:54:37 2022 +0200) on "android_arm64"`,
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"accept-encoding": "gzip, deflate",
|
||||
"host": "mobile-consumer-sapp.chery.cn",
|
||||
"content-type": "application/json; charset=UTF-8",
|
||||
"agent": "android",
|
||||
"request-channel": "app",
|
||||
},
|
||||
},
|
||||
result = await httpRequest(options);
|
||||
//console.log(options);
|
||||
//console.log(result);
|
||||
if (result.status == 200) {
|
||||
$.DoubleLog(`✅账号[${this.index}] 【获取文章】[${result.message}]🎉`);
|
||||
this.articleIdList = [result.data.data[0].content.id, result.data.data[1].content.id]
|
||||
} else {
|
||||
$.DoubleLog(`❌账号[${this.index}] 【获取文章】[${result.message}]`);
|
||||
//console.log(result);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
async task_share(articleId) {
|
||||
|
||||
try {
|
||||
let options = {
|
||||
url: `https://mobile-consumer-sapp.chery.cn//web/community/contents/${articleId}/share?access_token=${this.ck}&terminal=3`,
|
||||
headers: {
|
||||
"user-agent": "Dart/2.17 (dart:io)",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"appversion": `2.17.6 (stable) (Tue Jul 12 12:54:37 2022 +0200) on "android_arm64"`,
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"accept-encoding": "gzip, deflate",
|
||||
"host": "mobile-consumer-sapp.chery.cn",
|
||||
"content-type": "application/json; charset=UTF-8",
|
||||
"agent": "android",
|
||||
"request-channel": "app",
|
||||
},
|
||||
body: JSON.stringify({ "contentId": articleId })
|
||||
},
|
||||
result = await httpRequest(options);
|
||||
//console.log(options);
|
||||
//console.log(result);
|
||||
if (result.status == 200) {
|
||||
$.DoubleLog(`✅账号[${this.index}] 【分享】[${result.message}]🎉`);
|
||||
} else {
|
||||
$.DoubleLog(`❌账号[${this.index}] 【分享】[${result.message}]`);
|
||||
//console.log(result);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function start() {
|
||||
//await _getVersion();
|
||||
//await _getNotice();
|
||||
let taskall = [];
|
||||
for (let user of $.userList) {
|
||||
if (user.ckStatus) {
|
||||
taskall.push(await user.main());
|
||||
}
|
||||
}
|
||||
await Promise.all(taskall);
|
||||
}
|
||||
|
||||
!(async () => {
|
||||
if (!(await checkEnv())) return;
|
||||
if ($.userList.length > 0) {
|
||||
await start();
|
||||
} await $.SendMsg($.message);
|
||||
})().catch((e) => console.log(e)).finally(() => $.done());
|
||||
|
||||
//********************************************************
|
||||
/**
|
||||
* 变量检查与处理
|
||||
* @returns
|
||||
*/
|
||||
async function checkEnv() {
|
||||
let userCookie = ($.isNode() ? process.env[ckName] : $.getdata(ckName)) || "";
|
||||
//let userCount = 0;
|
||||
if (userCookie) {
|
||||
// console.log(userCookie);
|
||||
let e = envSplitor[0];
|
||||
for (let o of envSplitor)
|
||||
if (userCookie.indexOf(o) > -1) {
|
||||
e = o;
|
||||
break;
|
||||
}
|
||||
for (let n of userCookie.split(e)) n && $.userList.push(new UserInfo(n));
|
||||
//userCount = $.userList.length;
|
||||
} else {
|
||||
console.log("未找到CK");
|
||||
return;
|
||||
}
|
||||
return console.log(`共找到${$.userList.length}个账号`), true; //true == !0
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
function httpRequest(options, timeout = 1 * 1000) {
|
||||
method = options.method ? options.method.toLowerCase() : options.body ? "post" : "get";
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
$[method](options, (err, resp, data) => {
|
||||
try {
|
||||
if (err) {
|
||||
console.log(JSON.stringify(err));
|
||||
$.logErr(err);
|
||||
} else {
|
||||
try { data = JSON.parse(data); } catch (error) { }
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
$.logErr(e, resp);
|
||||
} finally {
|
||||
resolve(data);
|
||||
}
|
||||
})
|
||||
}, timeout)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 获取远程版本
|
||||
*/
|
||||
async function _getVersion() {
|
||||
const options = { url: JSConfig.jsUrl };
|
||||
let httpResult = await httpRequest(options)
|
||||
const regex = /scriptVersionNow\s*=\s*(["'`])([\d.]+)\1/;
|
||||
const match = httpResult.match(regex);
|
||||
const scriptVersionLatest = match ? match[2] : "";
|
||||
$.DoubleLog(`\n====== 当前版本:${scriptVersionNow} 📌 最新版本:${scriptVersionLatest} ======`);
|
||||
}
|
||||
/**
|
||||
* 获取远程通知
|
||||
*/
|
||||
async function _getNotice() {
|
||||
const options = { url: JSConfig.noticeUrl };
|
||||
let httpResult = await httpRequest(options)
|
||||
const notice = httpResult.notice.replace(/\\n/g, "\n");
|
||||
$.DoubleLog(notice);
|
||||
}
|
||||
// ==================== API ==================== //
|
||||
function Env(t, e) { class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, a) => { s.call(this, t, (t, s, r) => { t ? a(t) : e(s) }) }) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.userList = []; this.userIdx = 0; this.message = ""; this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.encoding = "utf-8", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name},开始!`) } getEnv() { return "undefined" != typeof $environment && $environment["surge-version"] ? "Surge" : "undefined" != typeof $environment && $environment["stash-version"] ? "Stash" : "undefined" != typeof module && module.exports ? "Node.js" : "undefined" != typeof $task ? "Quantumult X" : "undefined" != typeof $loon ? "Loon" : "undefined" != typeof $rocket ? "Shadowrocket" : void 0 } isNode() { return "Node.js" === this.getEnv() } isQuanX() { return "Quantumult X" === this.getEnv() } isSurge() { return "Surge" === this.getEnv() } isLoon() { return "Loon" === this.getEnv() } isShadowrocket() { return "Shadowrocket" === this.getEnv() } isStash() { return "Stash" === this.getEnv() } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson(t, e) { let s = e; const a = this.getdata(t); if (a) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise(e => { this.get({ url: t }, (t, s, a) => e(a)) }) } runScript(t, e) { return new Promise(s => { let a = this.getdata("@chavy_boxjs_userCfgs.httpapi"); a = a ? a.replace(/\n/g, "").trim() : a; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [i, o] = a.split("@"), n = { url: `http://${o}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": i, Accept: "*/*" }, timeout: r }; this.post(n, (t, e, a) => s(a)) }).catch(t => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), a = !s && this.fs.existsSync(e); if (!s && !a) return {}; { const a = s ? t : e; try { return JSON.parse(this.fs.readFileSync(a)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), a = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : a ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get(t, e, s) { const a = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of a) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set(t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, a) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[a + 1]) >> 0 == +e[a + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, a] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, a, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, a, r] = /^@(.*?)\.(.*?)$/.exec(e), i = this.getval(a), o = a ? "null" === i ? null : i || "{}" : "{}"; try { const e = JSON.parse(o); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), a) } catch (e) { const i = {}; this.lodash_set(i, r, t), s = this.setval(JSON.stringify(i), a) } } else s = this.setval(t, e); return s } getval(t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.read(t); case "Quantumult X": return $prefs.valueForKey(t); case "Node.js": return this.data = this.loaddata(), this.data[t]; default: return this.data && this.data[t] || null } } setval(t, e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.write(t, e); case "Quantumult X": return $prefs.setValueForKey(t, e); case "Node.js": return this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0; default: return this.data && this.data[e] || null } } initGotEnv(t) { this.got = this.got ? tLine truncated
|
||||
//Env rewrite:smallfawn Update-time:23-07-26 newAdd:DoubleLog & SendMsg & ChangeMessage
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
/**
|
||||
* cron 5 15 * * * V3.js
|
||||
* Show:
|
||||
* 变量名:cheryev
|
||||
* 变量值:midend.icar-ecology.com Headers中 token的值 多账号换行或者 @ 分隔
|
||||
*/
|
||||
|
||||
const $ = new Env("奇瑞Ev");
|
||||
const ckName = "cheryev";
|
||||
let envSplitor = ["@", "\n"]; //多账号分隔符
|
||||
let strSplitor = "&"; //多变量分隔符
|
||||
let userIdx = 0;
|
||||
let userList = [];
|
||||
class UserInfo {
|
||||
constructor(str) {
|
||||
this.index = ++userIdx;
|
||||
this.ck = str.split(strSplitor)[0]; //单账号多变量分隔符
|
||||
this.ckStatus = true;
|
||||
}
|
||||
async main() {
|
||||
await this.user_info();
|
||||
}
|
||||
async user_info() {
|
||||
try {
|
||||
let options = {
|
||||
url: `https://midend.icar-ecology.com/credits/task/app/v1/attendance`,
|
||||
headers: {
|
||||
"app": "cheryev",
|
||||
"authorization": `Bearer ${this.ck}`,
|
||||
"app-v": "2.9.0",
|
||||
//"uid": "1721053872548581377",
|
||||
"net-type": "wifi",
|
||||
"lng": 0.00,
|
||||
"channel": 2,
|
||||
"dev-id": "29f8b4555e18235b6b1ef94fa59541f7a",
|
||||
"platform": 7,
|
||||
"dev-model": "MI8Lite",
|
||||
"lat": 0.00,
|
||||
"token": `${this.ck}`,
|
||||
"Content-Length": 0,
|
||||
"Host": "midend.icar-ecology.com",
|
||||
"Connection": "Keep-Alive",
|
||||
"Accept-Encoding": "gzip",
|
||||
"User-Agent": "okhttp/4.10.0"
|
||||
},
|
||||
body: JSON.stringify({})
|
||||
},
|
||||
result = await httpRequest(options);
|
||||
//console.log(options);
|
||||
//console.log(result);
|
||||
if (result.data.success == true) {
|
||||
console.log(`✅账号[${this.index}] 签到成功 => 获得${result.data.rewardPoints}🎉`);
|
||||
} else {
|
||||
console.log(`❌账号[${this.index}] 签到 => 失败`);
|
||||
console.log(JSON.stringify(result));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function start() {
|
||||
let taskall = [];
|
||||
for (let user of userList) {
|
||||
if (user.ckStatus) {
|
||||
taskall.push(await user.main());
|
||||
}
|
||||
}
|
||||
await Promise.all(taskall);
|
||||
}
|
||||
|
||||
!(async () => {
|
||||
if (!(await checkEnv())) return;
|
||||
if (userList.length > 0) {
|
||||
await start();
|
||||
}
|
||||
})()
|
||||
.catch((e) => console.log(e))
|
||||
.finally(() => $.done());
|
||||
|
||||
//********************************************************
|
||||
/**
|
||||
* 变量检查与处理
|
||||
* @returns
|
||||
*/
|
||||
async function checkEnv() {
|
||||
let userCookie = ($.isNode() ? process.env[ckName] : $.getdata(ckName)) || "";
|
||||
if (userCookie) {
|
||||
console.log(userCookie);
|
||||
let e = envSplitor[0];
|
||||
for (let o of envSplitor)
|
||||
if (userCookie.indexOf(o) > -1) {
|
||||
e = o;
|
||||
break;
|
||||
}
|
||||
for (let n of userCookie.split(e)) n && userList.push(new UserInfo(n));
|
||||
} else {
|
||||
console.log("未找到CK");
|
||||
return;
|
||||
}
|
||||
return console.log(`共找到${userList.length}个账号`), true; //true == !0
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
function httpRequest(options, timeout = 5 * 1000) {
|
||||
method = options.method
|
||||
? options.method.toLowerCase()
|
||||
: options.body
|
||||
? "post"
|
||||
: "get";
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
$[method](options, (err, resp, data) => {
|
||||
try {
|
||||
if (err) {
|
||||
console.log(JSON.stringify(err));
|
||||
$.logErr(err);
|
||||
} else {
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch (error) { }
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
$.logErr(e, resp);
|
||||
} finally {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
// prettier-ignore
|
||||
function Env(t, s) { return new (class { constructor(t, s) { (this.name = t), (this.data = null), (this.dataFile = "box.dat"), (this.logs = []), (this.logSeparator = "\n"), (this.startTime = new Date().getTime()), Object.assign(this, s), this.log("", `\ud83d\udd14${this.name},\u5f00\u59cb!`) } 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 } getScript(t) { return new Promise((s) => { this.get({ url: t }, (t, e, i) => s(i)) }) } runScript(t, s) { return new Promise((e) => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let o = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); (o = o ? 1 * o : 20), (o = s && s.timeout ? s.timeout : o); const [h, a] = i.split("@"), r = { url: `http://${a}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: o }, headers: { "X-Key": h, Accept: "*/*" }, }; this.post(r, (t, s, i) => e(i)) }).catch((t) => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { (this.fs = this.fs ? this.fs : require("fs")), (this.path = this.path ? this.path : require("path")); const t = this.path.resolve(this.dataFile), s = this.path.resolve(process.cwd(), this.dataFile), e = this.fs.existsSync(t), i = !e && this.fs.existsSync(s); if (!e && !i) return {}; { const i = e ? t : s; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { (this.fs = this.fs ? this.fs : require("fs")), (this.path = this.path ? this.path : require("path")); const t = this.path.resolve(this.dataFile), s = this.path.resolve(process.cwd(), this.dataFile), e = this.fs.existsSync(t), i = !e && this.fs.existsSync(s), o = JSON.stringify(this.data); e ? this.fs.writeFileSync(t, o) : i ? this.fs.writeFileSync(s, o) : this.fs.writeFileSync(t, o) } } lodash_get(t, s, e) { const i = s.replace(/\[(\d+)\]/g, ".$1").split("."); let o = t; for (const t of i) if (((o = Object(o)[t]), void 0 === o)) return e; return o } lodash_set(t, s, e) { return Object(t) !== t ? t : (Array.isArray(s) || (s = s.toString().match(/[^.[\]]+/g) || []), (s.slice(0, -1).reduce((t, e, i) => Object(t[e]) === t[e] ? t[e] : (t[e] = Math.abs(s[i + 1]) >> 0 == +s[i + 1] ? [] : {}), t)[s[s.length - 1]] = e), t) } getdata(t) { let s = this.getval(t); if (/^@/.test(t)) { const [, e, i] = /^@(.*?)\.(.*?)$/.exec(t), o = e ? this.getval(e) : ""; if (o) try { const t = JSON.parse(o); s = t ? this.lodash_get(t, i, "") : s } catch (t) { s = "" } } return s } setdata(t, s) { let e = !1; if (/^@/.test(s)) { const [, i, o] = /^@(.*?)\.(.*?)$/.exec(s), h = this.getval(i), a = i ? ("null" === h ? null : h || "{}") : "{}"; try { const s = JSON.parse(a); this.lodash_set(s, o, t), (e = this.setval(JSON.stringify(s), i)) } catch (s) { const h = {}; this.lodash_set(h, o, t), (e = this.setval(JSON.stringify(h), i)) } } else e = this.setval(t, s); return e } getval(t) { return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? ((this.data = this.loaddata()), this.data[t]) : (this.data && this.data[t]) || null } setval(t, s) { return this.isSurge() || this.isLoon() ? $persistentStore.write(t, s) : this.isQuanX() ? $prefs.setValueForKey(t, s) : this.isNode() ? ((this.data = this.loaddata()), (this.data[s] = t), this.writedata(), !0) : (this.data && this.data[s]) || null } initGotEnv(t) { (this.got = this.got ? this.got : require("got")), (this.cktough = this.cktough ? this.cktough : require("tough-cookie")), (this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar()), t && ((t.headers = t.headers ? t.headers : {}), void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get(t, s = () => { }) { t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), this.isSurge() || this.isLoon() ? $httpClient.get(t, (t, e, i) => { !t && e && ((e.body = i), (e.statusCode = e.status)), s(t, e, i) }) : this.isQuanX() ? $task.fetch(t).then((t) => { const { statusCode: e, statusCode: i, headers: o, body: h } = t; s(null, { status: e, statusCode: i, headers: o, body: h }, h) }, (t) => s(t)) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, s) => { try { const e = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); this.ckjar.setCookieSync(e, null), (s.cookieJar = this.ckjar) } catch (t) { this.logErr(t) } }).then((t) => { const { statusCode: e, statusCode: i, headers: o, body: h, } = t; s(null, { status: e, statusCode: i, headers: o, body: h }, h) }, (t) => s(t))) } post(t, s = () => { }) { if ((t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), delete t.headers["Content-Length"], this.isSurge() || this.isLoon())) $httpClient.poLine truncated
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Description: 奇瑞汽车
|
||||
cron: 8 30 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
APP 抓包的登录接口uaa2c.chery.cn 里面的返回的access_token就是环境变量需要的token,多个账号换行或者&
|
||||
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。
|
||||
2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。
|
||||
3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。
|
||||
4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。
|
||||
5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。
|
||||
6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("./tools/env")
|
||||
const $ = new Env("奇瑞汽车");
|
||||
let ckName = `chery`;
|
||||
const strSplitor = "#";
|
||||
const axios = require("axios");
|
||||
const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram"
|
||||
|
||||
const CryptoJS = require("crypto-js");
|
||||
class Task {
|
||||
constructor(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
this.ckStatus = false;
|
||||
this.articleIdList = []
|
||||
|
||||
}
|
||||
encryptParams(e) {
|
||||
const t = CryptoJS.enc.Base64.parse("vVfnp9ozfDQyonMKuqgZUWjtdV+7PtBqtMCwJqz2HKQ=")
|
||||
, n = CryptoJS.lib.WordArray.random(16)
|
||||
, o = CryptoJS.AES.encrypt(e, t, {
|
||||
iv: n,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
})
|
||||
, i = CryptoJS.lib.WordArray.create();
|
||||
return i.concat(n),
|
||||
i.concat(o.ciphertext),
|
||||
CryptoJS.enc.Base64.stringify(i).replace(/\+/g, "-")
|
||||
}
|
||||
|
||||
async run() {
|
||||
|
||||
await this.info()
|
||||
if (this.ckStatus == true) {
|
||||
await this.signIn()
|
||||
await this.contentsList()
|
||||
for (let articleId of this.articleIdList) {
|
||||
await this.taskShare(articleId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async signIn() {
|
||||
let options = {
|
||||
method: 'POST',
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/event/trigger?encryptParam=${encodeURIComponent(this.encryptParams(`access_token=${this.token}&terminal=3`))}`,
|
||||
headers: {
|
||||
"user-agent": "Dart/2.19 (dart:io)",
|
||||
"appversioncode": "26030901",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"appversion": "3.6.9",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"accept-encoding": "gzip, deflate",
|
||||
"host": "mobile-consumer-sapp.chery.cn",
|
||||
"content-type": "application/json; charset=UTF-8",
|
||||
"agent": "android",
|
||||
"encryptflag": "true",
|
||||
"request-channel": "app"
|
||||
},
|
||||
data:
|
||||
Buffer.from(this.encryptParams(JSON.stringify({ "eventCode": "SJ10002" })), "utf-8"),
|
||||
transformRequest: [(d, headers) => d]
|
||||
};
|
||||
let { data: result } = await axios.request(options);
|
||||
if (result.status == 200) {
|
||||
$.log(`✅账号[${this.index}] 【签到】[${result.message}]🎉`);
|
||||
} else {
|
||||
$.log(`❌账号[${this.index}] 【签到】[${result.message}]`);
|
||||
//console.log(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
async info() {
|
||||
let options = {
|
||||
method: 'GET',
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/user/current/details?encryptParam=${encodeURIComponent(this.encryptParams(`access_token=${this.token}&terminal=3`))}`,
|
||||
headers: {
|
||||
"user-agent": "Dart/2.19 (dart:io)",
|
||||
"appversioncode": "26030901",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"appversion": "3.6.9",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"accept-encoding": "gzip, deflate",
|
||||
"host": "mobile-consumer-sapp.chery.cn",
|
||||
"content-type": "application/json; charset=UTF-8",
|
||||
"agent": "android",
|
||||
"encryptflag": "true",
|
||||
"request-channel": "app"
|
||||
},
|
||||
}
|
||||
let { data: result } = await axios.request(options);
|
||||
if (result.status == 200) {
|
||||
$.log(`✅账号[${this.index}] 【昵称】[${result.data.displayName}] 【积分】[${result.data.pointAccount.payableBalance}]🎉`);
|
||||
this.userName = result.data.displayName
|
||||
this.userPoint = result.data.pointAccount.payableBalance
|
||||
this.ckStatus = true;
|
||||
} else {
|
||||
$.log(`❌账号[${this.index}] [${result.message}]`);
|
||||
this.ckStatus = false;
|
||||
//console.log(result);
|
||||
}
|
||||
}
|
||||
|
||||
async taskShare(articleId) {
|
||||
|
||||
try {
|
||||
let options = {
|
||||
method: 'POST',
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/community/contents/${articleId}/share?encryptParams=${this.encryptParams(`access_token=${this.token}&terminal=3`)}`,
|
||||
headers: {
|
||||
"user-agent": "Dart/2.19 (dart:io)",
|
||||
"appversioncode": "26030901",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"appversion": "3.6.9",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"accept-encoding": "gzip, deflate",
|
||||
"host": "mobile-consumer-sapp.chery.cn",
|
||||
"content-type": "application/json; charset=UTF-8",
|
||||
"agent": "android",
|
||||
"encryptflag": "true",
|
||||
"request-channel": "app"
|
||||
},
|
||||
data: Buffer.from(this.encryptParams(JSON.stringify({ "contentId": articleId })), "utf-8")
|
||||
, transformRequest: [(d, headers) => d]
|
||||
}
|
||||
let { data: result } = await axios.request(options);
|
||||
if (result.status == 200) {
|
||||
$.log(`✅账号[${this.index}] 【分享】[${result.message}]🎉`);
|
||||
} else {
|
||||
$.log(`❌账号[${this.index}] 【分享】[${result.message}]`);
|
||||
//console.log(result);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
async contentsList() {
|
||||
|
||||
try {
|
||||
let options = {
|
||||
method: 'GET',
|
||||
url: `https://mobile-consumer-sapp.chery.cn/web/community/recommend/contents?encryptParam=${encodeURIComponent(this.encryptParams(`pageNo=1&pageSize=10&access_token=${this.token}&terminal=3`))}`,
|
||||
headers: {
|
||||
"user-agent": "Dart/2.19 (dart:io)",
|
||||
"appversioncode": "26030901",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"appversion": "3.6.9",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"accept-encoding": "gzip, deflate",
|
||||
"host": "mobile-consumer-sapp.chery.cn",
|
||||
"content-type": "application/json; charset=UTF-8",
|
||||
"agent": "android",
|
||||
"encryptflag": "true",
|
||||
"request-channel": "app"
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
let { data: result } = await axios.request(options);
|
||||
if (result.status == 200) {
|
||||
$.log(`✅账号[${this.index}] 【获取文章】[${result.message}]🎉`);
|
||||
this.articleIdList = [result.data.data[0].content.id, result.data.data[1].content.id]
|
||||
} else {
|
||||
$.log(`❌账号[${this.index}] 【获取文章】[${result.message}]`);
|
||||
//console.log(result);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
!(async () => {
|
||||
await getNotice()
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
.catch((e) => console.log(e))
|
||||
.finally(() => $.done());
|
||||
|
||||
async function getNotice() {
|
||||
let options = {
|
||||
url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`,
|
||||
headers: {
|
||||
"User-Agent": defaultUserAgent,
|
||||
}
|
||||
}
|
||||
let { data: res } = await axios.request(options);
|
||||
$.log(res)
|
||||
return res
|
||||
}
|
||||
Reference in new issue
Block a user