Files
qx/autman/qdreader_cookie_autman.js
T

167 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//[open_source: true]
//[create_at: 2026-05-17 02:50:00]
//[title: 起点读书签到]
//[author: Hermes]
//[service: BOSS]
//[class: 工具类]
//[version: 1.0.0]
//[platform: web,qq,wx,tg,tb]
//[public: false]
//[price: 0]
//[disable: false]
//[description: 起点读书(QDReader) Autman 路由插件:接收 Quantumult X 重写上传的 Cookie,按 uid 自动新增/更新;也可查看 Cookie 状态。实际每日签到建议仍由 QX 定时运行仓库内 qdreader.upstream.js,或把 QDREADER_COOKIE JSON 同步到 Node/青龙环境执行。]
//[router: /qdreader/cookie]
//[method: get]
//[method: post]
//[param: {"required":false,"key":"otto.qdreader_token","bool":false,"placeholder":"访问Token","name":"接口鉴权Token","desc":"外部请求携带 access_token 或 token;留空则不校验"}]
//[param: {"required":false,"key":"otto.qdreader_cookie_json","bool":false,"placeholder":"{\"uid\":\"cookie\"}","name":"QDReader Cookie JSON","desc":"由 QX 重写自动维护,JSON Map 格式"}]
var STORE_KEY = "qdreader_cookie_json"
function replyJSON(obj) {
if (typeof response === "function") response(obj)
else if (typeof sender !== "undefined" && sender.reply) sender.reply(obj)
else if (typeof sendText === "function") sendText(JSON.stringify(obj))
else console.log(JSON.stringify(obj))
}
function fail(code, msg, data) {
replyJSON({ ok: false, status: "fail", retcode: code, msg: msg, data: data || {} })
}
function ok(data, msg) {
replyJSON({ ok: true, status: "ok", retcode: 0, msg: msg || "success", data: data || {} })
}
function safeJsonParse(s, def) {
if (!s) return def
try { return JSON.parse(s) } catch (e) { return def }
}
function getStore() {
var raw = get(STORE_KEY) || "{}"
var obj = safeJsonParse(raw, {})
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return {}
return obj
}
function setStore(obj) {
var s = JSON.stringify(obj)
set(STORE_KEY, s)
return s
}
function getHeader(obj, name) {
if (!obj) return ""
var lower = String(name).toLowerCase()
for (var k in obj) if (String(k).toLowerCase() === lower) return obj[k]
return ""
}
function parseCookieString(cookie) {
var jar = {}
String(cookie || "").split(";").forEach(function (part) {
var i = part.indexOf("=")
if (i <= 0) return
var k = part.slice(0, i).trim()
var v = part.slice(i + 1).trim()
if (k) jar[k] = v
})
return jar
}
function b64decode(s) {
s = String(s || "")
try {
if (typeof Buffer !== "undefined") return Buffer.from(s, "base64").toString("utf8")
} catch (e) {}
try { return decodeURIComponent(escape(atob(s))) } catch (e) { return "" }
}
function uidFromQDHeader(qdheader) {
var decoded = b64decode(qdheader)
if (!decoded) return ""
var parts = decoded.split("|")
return String(parts[0] || "").trim()
}
function extractUid(cookie, body) {
var jar = parseCookieString(cookie)
var uid = uidFromQDHeader(jar.QDHeader || jar.qdheader || jar.QDHEADER || "")
if (uid) return uid
if (jar.uid) return String(jar.uid)
var obj = safeJsonParse(body, null)
try {
uid = obj && obj.Data && obj.Data.UserInfo && (obj.Data.UserInfo.UserId || obj.Data.UserInfo.userId)
if (uid) return String(uid)
} catch (e) {}
return ""
}
function readRequest() {
var method = typeof getMethod === "function" ? getMethod() : "get"
var params = typeof getRouterParams === "function" ? (getRouterParams() || {}) : {}
var body = {}
var raw = ""
if (String(method).toLowerCase() === "post") {
raw = typeof getRouterData === "function" ? (getRouterData() || "") : ""
body = safeJsonParse(raw, {})
}
return { method: method, params: params, body: body, raw: raw }
}
var req = readRequest()
var token = req.body.access_token || req.body.token || req.params.access_token || req.params.token || ""
var configuredToken = get("qdreader_token") || ""
if (configuredToken && configuredToken !== token) {
fail(-1, "token错误")
return
}
var action = req.body.action || req.params.action || "status"
var cookie = req.body.cookie || req.body.ck || req.params.cookie || req.params.ck || ""
var uid = req.body.uid || req.params.uid || ""
var responseBody = req.body.response_body || req.body.body || ""
if (action === "status") {
var store = getStore()
ok({ count: Object.keys(store).length, uids: Object.keys(store), envName: "QDREADER_COOKIE" }, "起点读书 Cookie 接收插件已启用")
return
}
if (action === "delete") {
var storeDel = getStore()
if (!uid) { fail(-2, "uid不能为空"); return }
var existed = !!storeDel[uid]
delete storeDel[uid]
var rawDel = setStore(storeDel)
ok({ uid: uid, existed: existed, count: Object.keys(storeDel).length, qdreader_cookie: rawDel }, existed ? "已删除" : "原本不存在")
return
}
if (action === "replace_all") {
var incoming = req.body.cookies || req.body.qdreader_cookie || req.body.QDREADER_COOKIE || req.params.cookies || ""
var obj = typeof incoming === "object" ? incoming : safeJsonParse(incoming, null)
if (!obj || typeof obj !== "object" || Array.isArray(obj)) { fail(-3, "cookies 必须是 JSON Map"); return }
var rawAll = setStore(obj)
ok({ count: Object.keys(obj).length, uids: Object.keys(obj), qdreader_cookie: rawAll }, "已整体替换")
return
}
// default: update cookie
if (!cookie) {
fail(-4, "cookie不能为空", { usage: "POST JSON: {action:'update', uid:'可选', cookie:'Cookie字符串', response_body:'可选'}" })
return
}
uid = uid || extractUid(cookie, responseBody)
if (!uid) {
fail(-5, "无法识别 uidCookie 中缺少 QDHeader/uid,或 response_body 无 UserInfo.UserId")
return
}
var store = getStore()
var isNew = !store[uid]
var changed = store[uid] !== cookie
store[uid] = cookie
var rawStore = setStore(store)
ok({ uid: uid, is_new: isNew, changed: changed, count: Object.keys(store).length, envName: "QDREADER_COOKIE", qdreader_cookie: rawStore }, (isNew ? "新增" : (changed ? "更新" : "未变化")) + "成功")