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:
smallfawn committed 2026-04-02 16:07:18 +08:00
1 parent e599f538e3
commit b85c26039b
5 files changed
+295 -438

No files matched your search

+65 -30
View File
@@ -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
+3 -1
View File
@@ -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`
-272
View File
@@ -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
View File
@@ -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
View File
@@ -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
}