From 74a90d619044c445c31bd6bf87b30394138ceb17 Mon Sep 17 00:00:00 2001 From: RRRosmontis Date: Wed, 2 Sep 2026 18:54:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Pixiv=20token=20=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E5=AE=88=E6=8A=A4=EF=BC=9A=E6=AF=8F=2030-60=20?= =?UTF-8?q?=E5=88=86=E9=92=9F=E9=9A=8F=E6=9C=BA=E7=BB=AD=E6=9C=9F=EF=BC=8C?= =?UTF-8?q?refresh=5Ftoken=20=E8=BD=AE=E6=8D=A2=E5=8E=9F=E5=AD=90=E8=90=BD?= =?UTF-8?q?=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - refresh_token.py:启动即刷新,random 30~60min 循环,失败 5min 重试 - 每次保存新 access_token+refresh_token(Pixiv 会轮换),chmod 600 - pixiv-token-refresh.service:常驻守护,Restart=always - README 同步服务清单与部署说明 --- README.md | 16 +++--- source/pixiv/refresh_token.py | 84 +++++++++++++++++++++++++++++ systemd/pixiv-token-refresh.service | 18 +++++++ 3 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 source/pixiv/refresh_token.py create mode 100644 systemd/pixiv-token-refresh.service diff --git a/README.md b/README.md index 0414abf..3f43a2b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ source/ ├── openapi/main.py # 聚合层 (127.0.0.1:9888) /pixiv/get_image /bilibili/get_video ├── pixiv/ │ ├── pixiv.py # Pixiv 图片服务 (9088) +│ ├── refresh_token.py # Pixiv OAuth token 刷新守护 │ └── tokens.template.json # Pixiv token 模板 └── bilibili/ ├── bilibili.py # bilibili 视频服务 (19990) @@ -16,18 +17,19 @@ source/ ├── qr_login.py # 扫码登录获取 cookie └── qr_login_fast.py nginx/ -└── openapi.rrrosmontis.icu.conf # nginx 统一入口(/pixiv/ /bilibili/ /img-master/ 图片反代) +└── openapi.rrrosmontis.icu.conf # nginx 统一入口(/pixiv/ /bilibili/ /img-master/ /img-original/ 图片反代) systemd/ -├── openapi.service # 聚合层 -├── pixiv.service # Pixiv 图片服务 -├── bilibili.service # bilibili 视频服务 -└── bilibili-refresh.service # cookie 刷新守护(每 50–70 分钟随机刷新) +├── openapi.service # 聚合层 +├── pixiv.service # Pixiv 图片服务 +├── bilibili.service # bilibili 视频服务 +├── bilibili-refresh.service # cookie 刷新守护(每 50–70 分钟随机刷新) +└── pixiv-token-refresh.service # Pixiv token 刷新守护(每 30–60 分钟随机刷新) ``` ## 部署 1. token:复制 `source/pixiv/tokens.template.json` 为 `source/pixiv/tokens.json`,填入实际 pixiv token 2. bilibili cookie:放置 `source/bilibili/cookies.txt`(`name=value` 格式),或运行 `qr_login.py` 扫码生成 -3. 服务:将 `systemd/*.service` 安装到 `/etc/systemd/system/`,启用并启动 openapi / pixiv / bilibili / bilibili-refresh(`systemctl enable --now`) +3. 服务:将 `systemd/*.service` 安装到 `/etc/systemd/system/`,启用并启动 openapi / pixiv / bilibili / bilibili-refresh / pixiv-token-refresh(`systemctl enable --now`) 4. nginx:将 `nginx/openapi.rrrosmontis.icu.conf` 放入 `/etc/nginx/conf.d/`,`nginx -t && systemctl reload nginx` -5. 定时任务:无 cron/timer——bilibili-refresh 为常驻守护,内部循环每 50–70 分钟刷新 cookie,systemd `Restart=always` 兜底 +5. 定时任务:无 cron/timer——bilibili-refresh(每 50–70 分钟刷 cookie)与 pixiv-token-refresh(每 30–60 分钟刷 Pixiv OAuth token,轮换后的 refresh_token 原子落盘)均为常驻守护,内部循环随机间隔,systemd `Restart=always` 兜底 diff --git a/source/pixiv/refresh_token.py b/source/pixiv/refresh_token.py new file mode 100644 index 0000000..e468368 --- /dev/null +++ b/source/pixiv/refresh_token.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +# refresh_token.py — Pixiv OAuth token 定时刷新守护 +# 逻辑(照旧): 启动立即刷新一次, 之后每 random 30~60 分钟刷新一次, 失败 5 分钟后重试。 +# 每次刷新把新的 access_token + refresh_token 原子落盘: +# Pixiv 每次刷新会轮换 refresh_token, 必须保存新的, 否则续期链会断。 + +import json +import os +import random +import time +import traceback +from pathlib import Path + +import requests +import urllib3 + +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +TOKEN_PATH = Path(__file__).parent / "tokens.json" +UA = "PixivIOSApp/7.13.0 (iOS 14.6; iPhone)" +INTERVAL_RANGE = (30 * 60, 60 * 60) # 半小时 ~ 一小时 之间随机 +RETRY_INTERVAL = 5 * 60 # 失败后 5 分钟重试 + + +def log(msg): + print(time.strftime("[%Y-%m-%d %H:%M:%S]") + " " + str(msg), flush=True) + + +def do_refresh(): + data = json.loads(TOKEN_PATH.read_text(encoding="utf-8")) + rt = data.get("refresh_token") + if not rt: + raise RuntimeError("tokens.json 缺少 refresh_token") + + payload = { + "client_id": "MOBrBDS8blbauoSck0ZfDbtuzpyT", + "client_secret": "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj", + "grant_type": "refresh_token", + "refresh_token": rt, + "include_policy": 1, + "get_secure_url": 1, + } + headers = {"User-Agent": UA, "App-OS": "iOS", "App-OS-Version": "14.6"} + try: + resp = requests.post("https://oauth.secure.pixiv.net/auth/token", + data=payload, headers=headers, timeout=20, verify=True) + verify_mode = "CA验证" + except requests.exceptions.SSLError: + resp = requests.post("https://oauth.secure.pixiv.net/auth/token", + data=payload, headers=headers, timeout=20, verify=False) + verify_mode = "CA验证失败,回退不验证" + + if resp.status_code != 200: + raise RuntimeError(f"HTTP {resp.status_code}: {resp.text[:120]}") + j = resp.json() + new_at = j.get("access_token") + new_rt = j.get("refresh_token") + if not new_at or not new_rt: + raise RuntimeError(f"响应缺少 token 字段: keys={list(j.keys())}") + + data["access_token"] = new_at + data["refresh_token"] = new_rt + tmp = TOKEN_PATH.with_suffix(".json.tmp") + tmp.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") + os.chmod(tmp, 0o600) + os.replace(tmp, TOKEN_PATH) + log(f"刷新成功 ({verify_mode}) expires_in={j.get('expires_in')}s " + f"access_token={new_at[:8]}... refresh_token={new_rt[:8]}... 已落盘") + + +def main(): + log(f"守护启动, 刷新间隔 random {INTERVAL_RANGE[0]//60}~{INTERVAL_RANGE[1]//60} min") + while True: + try: + do_refresh() + time.sleep(random.uniform(*INTERVAL_RANGE)) + except Exception as e: + log(f"刷新失败: {e}") + traceback.print_exc() + time.sleep(RETRY_INTERVAL) + + +if __name__ == "__main__": + main() diff --git a/systemd/pixiv-token-refresh.service b/systemd/pixiv-token-refresh.service new file mode 100644 index 0000000..eec01dd --- /dev/null +++ b/systemd/pixiv-token-refresh.service @@ -0,0 +1,18 @@ +[Unit] +Description=Pixiv Token Refresh Daemon +After=network-online.target +Wants=network-online.target + +[Service] +Environment=PATH=/home/openapi/env/general/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +Environment=SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt +Type=simple +WorkingDirectory=/home/openapi/source/pixiv +ExecStart=/home/openapi/env/general/bin/python /home/openapi/source/pixiv/refresh_token.py +Restart=always +RestartSec=30 +StandardOutput=append:/var/log/pixiv_token_refresh.log +StandardError=append:/var/log/pixiv_token_refresh.log + +[Install] +WantedBy=multi-user.target