feat: E1002 新增公网图片服务(恒定 URL 现渲染)+底部改为 BTC 时K
- server.py:三条恒定 URL 并行——/e1002.png 内存现渲染 PNG(主力)、 /e1002.html 现代网页、/e1002-web.png 网页经无头 Chrome 截图后固化六色; 天气/橘喵/BTC 按 WEATHER_TTL/MAO_TTL/BTC_TTL 走内存缓存,过期才实拉、 失败沿用旧值;用量不读本机文件,改由 POST /push/usage(_gpt) 推送暂存 - push_client.py:本机把 Claude 用量快照推送到服务(X-Push-Token 鉴权) - btc_api.py:OKX/Coinbase/Huobi 免费接口逐源兜底,时K 近 72 小时,涨绿跌红 - data.py 拆出 weather_fetch/mao_fetch/btc_fetch 与 usage_from_raw, 统一按 TZ_NAME 时区;宽版只用点阵字体整数倍字号 12/24/36/48 - probe_server.py:验证平台对同一 URL 是否周期重抓(结论:Image 控件 不重抓,HTML 控件重抓) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
55
push_client.py
Normal file
55
push_client.py
Normal file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
推送端(本机运行)—— 把本机的用量原始快照 POST 到 server.py,服务端暂存、渲染时现算 pace。
|
||||
|
||||
推什么:
|
||||
- Claude:~/.claude/usage-snapshot.json 原文(statusline 生产,含 five_hour / seven_day / seven_day_fable / updated_at)→ POST /push/usage
|
||||
- ChatGPT:暂无本机数据源;将来有了按 data.GPT_WINDOWS 的键(five_hour / seven_day / seven_day_codex,各含 utilization + resets_at)
|
||||
组一个 dict → POST /push/usage_gpt。目前不推,服务端用 mock 并标「示例数据」。
|
||||
鉴权:请求头 X-Push-Token = PUSH_TOKEN。网络:直连(不走代理),连接类异常重试 2 次。
|
||||
调度:与喵喵设备推送同节律,由 launchd 每 5 分钟跑一次 `main.py --target push`(或加进 run.sh)。
|
||||
"""
|
||||
import json
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
import config
|
||||
import usage_local
|
||||
|
||||
RETRY_TIMES, RETRY_DELAY, TIMEOUT = 2, 2, 10
|
||||
|
||||
|
||||
def _post_json(url, payload):
|
||||
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||
req = urllib.request.Request(url, data=body, method="POST", headers={
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"X-Push-Token": config.PUSH_TOKEN,
|
||||
"User-Agent": "eink-push/push_client",
|
||||
})
|
||||
last = None
|
||||
for i in range(RETRY_TIMES + 1):
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=TIMEOUT) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
except urllib.error.HTTPError as e: # 4xx/5xx 不重试,直接报出服务端的说明
|
||||
raise RuntimeError(f"HTTP {e.code}: {e.read().decode('utf-8', 'replace')[:200]}") from e
|
||||
except urllib.error.URLError as e: # 连接类:重试
|
||||
last = e
|
||||
if i < RETRY_TIMES:
|
||||
time.sleep(RETRY_DELAY)
|
||||
raise RuntimeError(f"连接失败:{last}")
|
||||
|
||||
|
||||
def push_usage():
|
||||
if not config.PUSH_URL or not config.PUSH_TOKEN:
|
||||
raise SystemExit("[推送] 需在 .env 配置 PUSH_URL 与 PUSH_TOKEN")
|
||||
raw = usage_local.get_usage() # 缺文件直接抛错——没有快照就没什么可推
|
||||
resp = _post_json(config.PUSH_URL.rstrip("/") + "/push/usage", raw)
|
||||
print(f"[推送] Claude 用量快照已推送到 {config.PUSH_URL}:{resp}")
|
||||
return resp
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
push_usage()
|
||||
Reference in New Issue
Block a user