feat: add pingme qx capture rewrite
This commit is contained in:
@@ -7,8 +7,10 @@
|
|||||||
```text
|
```text
|
||||||
conf/qdreader.conf # 起点读书 QX 远程重写订阅文本,参考 chickliu/qx 老仓库风格
|
conf/qdreader.conf # 起点读书 QX 远程重写订阅文本,参考 chickliu/qx 老仓库风格
|
||||||
conf/kyapp_qinglong.conf # 快音 CK → 青龙 KYAPP 自动更新重写订阅
|
conf/kyapp_qinglong.conf # 快音 CK → 青龙 KYAPP 自动更新重写订阅
|
||||||
|
conf/pingme.conf # PingMe → NiuPanel pingme_multi.js 抓包重写订阅
|
||||||
js/qdreader_cookie.js # 起点读书 QX Rewrite 脚本入口
|
js/qdreader_cookie.js # 起点读书 QX Rewrite 脚本入口
|
||||||
js/kyapp_qinglong_update.js # 快音 CK 抓取并更新青龙 KYAPP
|
js/kyapp_qinglong_update.js # 快音 CK 抓取并更新青龙 KYAPP
|
||||||
|
js/pingme_capture.js # PingMe 抓取 pingme_multi.js 所需账号 JSON
|
||||||
docs/qx-rewrite-lessons.md # 本次制作经验
|
docs/qx-rewrite-lessons.md # 本次制作经验
|
||||||
source/qdreader.upstream.js # 上游 QDReader 脚本备份
|
source/qdreader.upstream.js # 上游 QDReader 脚本备份
|
||||||
```
|
```
|
||||||
@@ -27,6 +29,12 @@ https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/qdreader.conf
|
|||||||
https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/kyapp_qinglong.conf
|
https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/kyapp_qinglong.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
PingMe → NiuPanel 抓包订阅地址:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/pingme.conf
|
||||||
|
```
|
||||||
|
|
||||||
## 订阅内容
|
## 订阅内容
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
hostname = api.pingmeapp.net
|
||||||
|
|
||||||
|
# PingMe:抓取 NiuPanel pingme_multi.js 所需账号配置
|
||||||
|
# 使用说明见 docs/pingme-capture.md
|
||||||
|
^https?:\/\/api\.pingmeapp\.net\/app\/(?:queryBalanceAndBonus|checkIn|videoBonus)(?:\?|$) url script-request-header https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/js/pingme_capture.js
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# PingMe → NiuPanel 抓包配置(Quantumult X)
|
||||||
|
|
||||||
|
## 订阅地址
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/pingme.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
这个 QX 重写监听 PingMe 官方接口:
|
||||||
|
|
||||||
|
```text
|
||||||
|
api.pingmeapp.net/app/queryBalanceAndBonus
|
||||||
|
api.pingmeapp.net/app/checkIn
|
||||||
|
api.pingmeapp.net/app/videoBonus
|
||||||
|
```
|
||||||
|
|
||||||
|
抓到后生成 NiuPanel 任务 `pingme_multi.js` 所需的账号 JSON 对象:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"url":"...","paramsRaw":{"...":"..."},"headers":{"User-Agent":"..."}}
|
||||||
|
```
|
||||||
|
|
||||||
|
NiuPanel 当前任务读取位置:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/app/data/scripts/pingme_ck.json
|
||||||
|
```
|
||||||
|
|
||||||
|
宿主机路径:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/Users/chick/.openclaw/workspace/niupanel/niupanel-data/scripts/pingme_ck.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用流程
|
||||||
|
|
||||||
|
1. Quantumult X 添加重写订阅:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/pingme.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 开启 MitM 并信任证书。
|
||||||
|
3. 确认 hostname 包含:
|
||||||
|
|
||||||
|
```text
|
||||||
|
api.pingmeapp.net
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 打开 PingMe App,触发余额、签到或视频奖励接口。
|
||||||
|
5. QX 弹窗标题显示 `CK 获取成功`,正文是完整 JSON 对象。
|
||||||
|
6. 将 JSON 对象追加到 NiuPanel 的 `pingme_ck.json`。
|
||||||
|
|
||||||
|
多账号格式仍按 `pingme_multi.js` 当前逻辑:每个账号一个 JSON 对象,多个账号可使用英文逗号分隔:
|
||||||
|
|
||||||
|
```text
|
||||||
|
{账号1JSON},{账号2JSON}
|
||||||
|
```
|
||||||
|
|
||||||
|
也支持 JSON 数组:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{"url":"...","paramsRaw":{},"headers":{}},{"url":"...","paramsRaw":{},"headers":{}}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安全说明
|
||||||
|
|
||||||
|
- 仓库不提交任何真实 CK、token、设备 ID 或 headers 明文。
|
||||||
|
- 脚本不上传数据,不请求第三方,只在 QX 本地保存最近一次抓取结果 `pingme_ck_last` 并弹窗展示。
|
||||||
|
- 重写范围只包含 `api.pingmeapp.net` 的三个任务相关接口。
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* PingMe CK 抓取 - Quantumult X Rewrite
|
||||||
|
*
|
||||||
|
* 订阅地址:
|
||||||
|
* https://gitea.chickliu.fun/Hermes/qx/raw/branch/main/conf/pingme.conf
|
||||||
|
*
|
||||||
|
* 功能:
|
||||||
|
* - 监听 api.pingmeapp.net/app/queryBalanceAndBonus、checkIn、videoBonus
|
||||||
|
* - 抓取 pingme_multi.js 需要的 url / paramsRaw / headers
|
||||||
|
* - 弹窗输出可直接追加到 NiuPanel /app/data/scripts/pingme_ck.json 的 JSON 对象
|
||||||
|
*
|
||||||
|
* 安全:不上传 CK,不请求第三方;仅在 QX 本地保存最近一次抓取结果。
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SCRIPT_NAME = 'PingMe'
|
||||||
|
|
||||||
|
function notify(subtitle, message) {
|
||||||
|
$notify(SCRIPT_NAME, subtitle || '', message || '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function done() {
|
||||||
|
$done({})
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPref(key, value) {
|
||||||
|
try { return $prefs.setValueForKey(String(value), key) } catch (e) { return false }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeader(headers, name) {
|
||||||
|
const lower = String(name).toLowerCase()
|
||||||
|
for (const k in (headers || {})) {
|
||||||
|
if (String(k).toLowerCase() === lower) return headers[k]
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRawQuery(url) {
|
||||||
|
const raw = String(url || '')
|
||||||
|
const qIndex = raw.indexOf('?')
|
||||||
|
if (qIndex < 0) return {}
|
||||||
|
const hashIndex = raw.indexOf('#', qIndex + 1)
|
||||||
|
const query = raw.slice(qIndex + 1, hashIndex >= 0 ? hashIndex : undefined)
|
||||||
|
const out = {}
|
||||||
|
query.split('&').forEach(pair => {
|
||||||
|
if (!pair) return
|
||||||
|
const idx = pair.indexOf('=')
|
||||||
|
if (idx < 0) return
|
||||||
|
const k = pair.slice(0, idx)
|
||||||
|
const v = pair.slice(idx + 1)
|
||||||
|
if (k) out[k] = v
|
||||||
|
})
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickHeaders(headers) {
|
||||||
|
const names = [
|
||||||
|
'User-Agent',
|
||||||
|
'Accept',
|
||||||
|
'Accept-Language',
|
||||||
|
'Authorization',
|
||||||
|
'Cookie',
|
||||||
|
'X-Requested-With',
|
||||||
|
'Content-Type',
|
||||||
|
'Origin',
|
||||||
|
'Referer'
|
||||||
|
]
|
||||||
|
const out = {}
|
||||||
|
names.forEach(name => {
|
||||||
|
const v = getHeader(headers, name)
|
||||||
|
if (v !== undefined && v !== null && String(v) !== '') out[name] = String(v)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 保留 PingMe/客户端自定义头,避免后续接口校验客户端参数。
|
||||||
|
Object.keys(headers || {}).forEach(k => {
|
||||||
|
const lk = String(k).toLowerCase()
|
||||||
|
if (
|
||||||
|
lk.startsWith('x-') ||
|
||||||
|
lk.indexOf('device') >= 0 ||
|
||||||
|
lk.indexOf('token') >= 0 ||
|
||||||
|
lk.indexOf('client') >= 0 ||
|
||||||
|
lk.indexOf('app') >= 0
|
||||||
|
) {
|
||||||
|
if (!/^content-length$/i.test(k) && !/^host$/i.test(k)) out[k] = String(headers[k])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRecord(req) {
|
||||||
|
const url = String(req.url || '')
|
||||||
|
const paramsRaw = parseRawQuery(url)
|
||||||
|
const headers = pickHeaders(req.headers || {})
|
||||||
|
return { url, paramsRaw, headers }
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasRequiredParams(record) {
|
||||||
|
const p = record && record.paramsRaw || {}
|
||||||
|
return Object.keys(p).length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatRecord(record) {
|
||||||
|
return JSON.stringify(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const req = typeof $request !== 'undefined' ? $request : null
|
||||||
|
if (!req || !req.url) {
|
||||||
|
notify('抓取失败', '没有 request 上下文')
|
||||||
|
return done()
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = buildRecord(req)
|
||||||
|
if (!hasRequiredParams(record)) {
|
||||||
|
notify('抓取失败', '当前请求缺少 URL 查询参数,请打开 PingMe 触发余额/签到/视频接口')
|
||||||
|
return done()
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = formatRecord(record)
|
||||||
|
setPref('pingme_ck_last', text)
|
||||||
|
notify('CK 获取成功', text)
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
main()
|
||||||
|
} catch (e) {
|
||||||
|
notify('脚本异常', String(e && e.message || e).slice(0, 220))
|
||||||
|
done()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user