//[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, "无法识别 uid:Cookie 中缺少 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 ? "更新" : "未变化")) + "成功")