Commit Graph
11 Commits
Author SHA1 Message Date
butubb d937ff5fe6 fix(db): _ensure_columns 改为按模型元数据推导,并补上漏加的调度字段
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
上一个提交加了 4 个调度字段,却没在 _ADDED_COLUMNS 里登记,后果是生产环境:
  - 任务列表接口报 Unknown column,UI 打不开任务列表
  - 调度器每 20 秒 tick 一次炸一次,定时任务完全不会触发
  最阴险的是启动完全正常——能连库、能起来,只是随后每条查询都失败。

- _ensure_columns 不再遍历手写清单,改为遍历 MonitorBase.metadata.sorted_tables,
  从根上消掉「加了字段忘了登记」这类漏
- 新增 _column_ddl:用 CreateColumn 渲染类型与可空性,并给 NOT NULL 列补 DEFAULT。
  模型的 default= 是 ORM 侧行为、不会进 DDL,而给已有数据的表加 NOT NULL 列必须有值,
  否则能否成功取决于服务端 sql_mode
- 主键列跳过:MySQL 不允许 AUTO_INCREMENT 与 DEFAULT 共存

新增 tests/test_monitor_column_migration.py 守住:每个 NOT NULL 列都必须能生成带
DEFAULT 的合法 ALTER。
2026-10-07 15:35:40 +08:00
butubb 8f4e5586e9 feat(schedule): 任务支持「每天定时 / 每周定时」,用选择器而不是手写 cron
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
- schedule.py: 新增调度计算模块(纯函数,便于单测)。三种模式:interval(每 N 分钟)/ daily(选钟点)/ weekly(选星期 + 钟点)
- 钟点模式是「固定时刻」而非「固定延迟」——从日历重算,所以某轮跑晚了不会把之后每一轮都拖晚。interval 保持原语义:从上一轮开始计时
- 抖动只加给 interval。给「每天 9:00」也加抖动就成了 9:00–9:01 随机触发,操作者选的时间被悄悄改掉,只会像 bug
- 模型 / schema / service: 新增 schedule_mode / schedule_hours / schedule_days / schedule_minute。时钟字段存逗号分隔文本——几个小整数、永远整体读写,单开一张表只会换来 join。interval_minutes 保留且仍是默认值,已有任务不受影响
- service: 改动任何调度字段都按合并后的状态重算 next_run_at。重新启用也算改动,否则停用一个月再打开会带着一个月前的 next_run_at,一保存就立即触发
- 前端: 运行方式三选一 + 小时/星期胶囊多选 + 分钟下拉,并实时预览结果句子。任务卡片改显示后端拼好的 schedule_label,避免列表和编辑器对同一计划给出两种说法
- 校验: 钟点模式至少选一个时间,按周至少选一个星期

tests/test_schedule.py 新增 24 个用例,含「恰好等于当前时刻的档位归属下一天」这个会让调度器自循环的边界。
2026-10-07 15:33:17 +08:00
butubb 242e3a7837 fix(chart): 纵轴自 0 起、刻度归位、数据点恢复为正圆
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
- 纵轴从 0 起,上界取整到好读的数(1/1.2/1.5/2/…)。此前按 [最小值,最大值] 自适应,491→506 这点变化被撑满整个图高、看着像暴涨,且上下两刻度就是 506 和 491 两个几乎一样的数,没有 0 做参照读不出量级
- 刻度线画在 0 / 中值 / 上界,标签贴在各自主线上、放进左侧刻度栏。原来是两个绝对定位的数字浮在图面上,会挤在一起读成一个数
- 数据点恢复为正圆:根因是 preserveAspectRatio="none" 把 600×160 的 viewBox 横向拉满容器,横纵缩放不一致,半径 4 的圆被压成椭圆。改为用 ResizeObserver 量出容器宽度、等比绘图
- 每个数据点都画出来(原先只画末点),点数多时自动缩小半径;悬停热区按点位间距铺满整段,不再固定 12px
- 当前值移到标题行,不再浮在图面上遮挡曲线
2026-10-07 15:26:42 +08:00
butubb c1068845a9 fix(deploy): 部署时必须强制重建容器
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
代码是 bind mount,容器配置与镜像都没变,所以裸的 `docker compose up -d` 会判定无需变更直接跳过,改了 .py 也不会生效。前端产物是磁盘上的静态文件、能即时生效,这一点很容易把问题盖住,直到有人改了后端代码才发现。

首次实测即命中:跑 deploy.sh 的输出是 'Container mediacrawler Running',没有重启。
2026-10-07 15:22:00 +08:00
butubb 89b7b1e825 fix: 封面图不再被图床拒绝,作品栏补上封面
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
- NoteCover: 新增共用封面组件,核心是 referrerPolicy="no-referrer"。小红书图床对带外部 Referer 的请求一律 403,而浏览器对跨域 <img> 默认就会带上本站源作为 Referer —— 于是封面全显示成破图,而 URL 本身完全正常。实测同一张图:无 Referer 200 / 67968B,Referer 为本站 403 / 0B
- CommentsFeed: 改用 NoteCover,修掉评论栏封面全部加载失败
- NotesTable: 作品栏此前完全没有渲染封面,补上缩略图;封面缺失时用占位块,避免行高随封面陆续到达而跳动

放在一个组件里而不是就地加属性,是为了让下一个显示封面的页面不会漏掉。
2026-10-07 15:21:29 +08:00
butubb fe45442b01 chore: deploy.sh 标记为可执行(Windows 上创建的文件没有 exec 位)
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
2026-10-07 11:14:13 +08:00
butubb 74a592024c feat: 部署改为 git 驱动,容器以宿主用户运行
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
服务器实测可经 Cloudflare 443 访问 Gitea 且 git 协议正常(此前我只测了 13000 端口就断言不可达,是错的),因此不再需要 tar + SFTP。

- docker-compose: 增加 user: "1000:1000"。容器此前以 root 运行,写进挂载目录的每轮 jsonl 产物都是 root 属主,导致宿主用户连自己的部署目录都挪不动 —— 这在把部署迁到 /mnt/data 时实际发生了
- deploy.sh: 一条命令走完 拉代码 →(webui/ 有改动时)重建前端 → 重启容器。前端产物 api/webui 是 gitignore 的,git pull 带不过来,必须在服务器上重建一次
- Dockerfile: 补 npm 包。corepack 只管 yarn/pnpm 不管 npm,而前端要在服务器上重建;这样服务器只需要 Docker,不必另配 Node 环境
2026-10-07 11:13:43 +08:00
butubb cffb407d15 feat: 生产库克隆脚本 + 容器补 Node 运行时
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
- tools/clone_database.py: 同服务器跨库克隆并建立独立应用账号的 provisioning 脚本。本机与服务器都没有 mysql 客户端,所以走 INSERT...SELECT 而非 dump/reload。刻意只读写命令行指定的两个 schema,且给应用单开账号而不是复用管理员
- Dockerfile: 补 nodejs。douyin/help.py 在模块导入阶段就执行 execjs.compile(libs/douyin.js),缺 JS 运行时会抛 RuntimeUnavailableError;而 main.py 要导入全部 7 个平台,于是整个应用连带环境自检一起挂掉

已在 192.168.20.220 上验证:7 个平台导入全部通过。
2026-10-07 11:08:11 +08:00
butubb bcc7361145 refactor: 镜像只装依赖,代码改为挂载
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
- Dockerfile: 去掉 COPY . .,镜像退化为纯依赖层,改代码不再需要重建镜像
- Dockerfile: 补 libgl1 / libxcb1 / libglib2.0-0 等 X11 库。opencv-python 在导入时需要它们,而 tools/utils.py 会经 slider_util 导入 cv2 —— 缺了不是某个边角功能挂掉,是整个应用起不来(已在真机冒烟中验证)
- Dockerfile: 补 tzdata,否则 TZ=Asia/Shanghai 被静默忽略,所有时间戳落成 UTC
- Dockerfile: apt 与 pip 均改走国内源。deb.debian.org 实测约 13 kB/s,96 MB 构建依赖要跑半小时以上
- docker-compose: 挂载 ./ 到 /app,部署流程从「重建镜像」变成「重传 + 重启」
- main.py: 启动时若缺 api/webui/index.html 就打印警告,避免只返回一段 JSON 却看着一切正常
2026-10-07 10:57:44 +08:00
butubb 37ca1b1cd6 feat: CDP 接管开关 + 扫码登录面板 + Docker 部署
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
- runner: enable_cdp_mode 从硬编码 False 改为系统设置 cdp_enabled。服务器部署下爬虫接管已开启远程调试的 Chrome(默认 9222),复用其 profile 登录态;本机桌面默认仍为关,行为不变
- qrlogin: 新增 CDP 扫码登录。Chrome 在服务器上跑于 Xvfb,show_qrcode 依赖的 PIL 桌面看图程序不存在,二维码无处可显示;改为经 CDP 从页面取出二维码交给 WebUI 渲染。刻意复用 browser.contexts[0](新建 context 是无痕 profile,扫了也白扫),且绝不调用 browser.close()(会连带关掉操作者自己的 Chrome)
- webui: 设置页新增扫码面板,替换原本跳到采集页看终端二维码的入口
- Dockerfile / .dockerignore / docker-compose.yml: 服务器部署。host 网络是必需而非图省事——容器里 127.0.0.1:9222 必须落到宿主机回环
- UPSTREAM.md: 补充 gitcode 镜像,用于 GitHub 大包传输必断时补历史
2026-10-07 10:41:11 +08:00
butubb 4e60524f37 feat: 监控面板 / 登录鉴权 / 多平台切换 / MySQL
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
在上游 MediaCrawler 之上新增一层:

- 监控层 api/monitor/ —— 多博主/多笔记的定时采集、指标快照差分、报表、
  企业微信通知。每轮采集写入独立目录,差分才成立。
- WebUI 登录鉴权 api/auth.py —— PBKDF2 口令 + 服务端会话,/api 全接口防护。
  WebSocket 单独加依赖:BaseHTTPMiddleware 对 ws 作用域直接放行,覆盖不到。
- 全局平台切换 + 能力矩阵 —— 如实区分「爬虫模块支持」与「监控层已接线」,
  未接通的平台直接拒绝建任务,而不是静默跑空。
- 监控库改用 MySQL 5.7(可回退 SQLite 供测试):逐表强制 utf8mb4
  (服务端与库默认都是 latin1),启动校验所连 schema 以防写错库,
  连接池 recycle + pre_ping 应对 MySQL 的 8 小时空闲断连。

修复上游缺陷:

- xhs/core.py: 主页抓取失败会跳掉整个博主,导致一条作品都抓不到,
  而那份资料只喂给一个空函数。改为尽力而为,失败不中断。
- xhs/login.py: cookie 登录只注入 web_session,冷启动签名会失败。
  新增 INJECT_ALL_COOKIES 开关(默认关闭,原有行为不变)。
- requirements.txt: 补上 websockets。它在上游 pyproject.toml 里有声明、
  这里漏了,导致 uvicorn 没有 WebSocket 能力,实时日志流从未工作。

改动过的上游文件清单及合并方式见 UPSTREAM.md。

测试:492 passed(另有 1 个既有的 Windows/gbk 上游测试失败,与本改动无关)
2026-10-07 09:58:40 +08:00