开源地址:https://github.com/zkzkeep/packseed (MIT) 观澜,Wavegazer——观影观澜,站在岸上看自己的海。
今天想庆祝一下:我的 PT 全家桶「观澜」正式毕业了。从一个赌气的周末脚本,长成一个我自己每天都在用、并且觉得精致的 app。这篇把整个上线过程记下来。
一、起因:一口没咽下去的气
我的保种流程原本是业界标配:MoviePilot 管下载刮削,cross-seed 管辅种,IYUU 补刀。直到有一天,我发现 cross-seed 对着我硬盘里的《无耻之徒 S01-S11》《真探 S01-S03》这种多季合集包视而不见——它依赖 release 命名规范做匹配,PT 站常见的中文合集、非标准命名,它直接跳过。
可辅种的本质明明很简单:同样的文件内容,在另一个站找到对应种子,把 tracker 换过去继续做种。判断依据应该是"文件是否一致",而不是"名字长得像不像"。
行,你不认名字,我就不看名字。周末写了个脚本:体积预筛(±0.3%)+ 文件清单精确比对——把本地种子的相对路径和字节数做成集合,和候选种子的清单硬碰硬。名字爱叫什么叫什么。
第一次全量跑完:白色巨塔从 1 个站辅到 27 个站。cross-seed 拒收的合集包,全辅上了。
二、演化:从辅种脚本到全家桶
赌气脚本能跑之后,野心就藏不住了。既然 Prowlarr 已经聚合了我全部站点,那搜索下载为什么还要开 MP?既然下载完成事件我自己就能监听,那刮削入库为什么要靠别人?
于是它一步步吃掉了整条流水线:
面板搜索 → 一键推 qb 下载
↓ 下载完成(自动检测)
识别 → TMDB 匹配 → 硬链接进媒体库「中文名 (年份)/」
↓ ↓
通知 Emby 刷新 转种到 Transmission 保种
↓
扫描 tr → 全站辅种(体积+清单比对)
硬链接三方共享同一份文件:qb 下的、Emby 播的、tr 做种的,不重复占一个字节。
中间攻克的硬骨头,每一块都值得单独写一篇:
- 动漫识别:
[字幕组][标题][01-24]、第1123话这种番组命名专门解析;海贼王柯南这类千集长寿番,按话数自动匹配到最早开播的原版条目,不会配到重制版或真人版 - 音乐流水线:识别 FLAC/APE 特征 → 原结构入 Navidrome 库 → 自动配歌词 .lrc 和专辑封面
- 企业微信双向交互:纯标准库手写 AES-256-CBC 回调解密(S 盒都是伽罗瓦域现算的),微信里发片名→回片单→回数字→自动下载,还能 30 分钟内撤回
- Emby 驯服记:这是血泪最浓的一章。Emby 的 NFO 读取是玄学,RemoteSearch 会按名字瞎搜(把《火线》认成《穿越火线》),ReplaceAllMetadata=true 的刷新会把你刚写进去的身份自己拆掉重新瞎识别。最终唯一可靠的路:直接 POST 完整 dto 写死 Name/ProviderIds/年份/简介,之后永远只做增量刷新。从此 Emby 降级为纯播放器,刮削自给自足——每次入库自动生成 NFO + 海报 + 同人画 + 标准重命名,媒体包自包含,换任何播放器即插即用
MP 正式退休那天,我把它的容器停了,没舍得删。留个纪念。
三、门面:克莱因蓝
功能齐了,但界面素得像内部工具。我想要的是打开就开心的东西。
主色定了克莱因蓝 #002FA7——整页沉浸,不留黑色(压抑)。白色玻璃卡片浮在蓝底上,按钮用纯白配蓝字,进度条和强调数字用克莱因黄 #FFD400 撞色。蓝白撞出干净,蓝黄撞出精神。
名字也在这时定了:观澜。不再是辅种工具(PackSeed),是站在岸上看自己那片海。英文名 Wavegazer,走向国际化,哈哈。
既然叫观澜,就得有真的浪:
- Hero 区是一段真实的沙滩铺浪视频,自托管、带 HTTP Range、24 小时循环
- 最近入库是一条海报河:横向像水流一样缓缓淌过,每张海报还在上下轻晃,像漂在海面上
- 鼠标划过海报,macOS Dock 式磁吸放大——不是 CSS :hover 那种生硬的二值切换,是 JS 距离场:越靠近光标越大,邻居微微缩小,众星捧月
- 点海报,毛玻璃弹窗秒出简介,一键跳进 Emby 对应条目
图标是自画的 SVG:克莱因蓝底,白浪两叠,一轮克莱因黄的太阳。
四、产品化:让陌生人三分钟跑起来
开源之后遇到灵魂拷问:我自己的服务地址都在环境变量里,别人装了怎么知道该填什么?
答案是业界标准的"用户填 + 软件验"模式,做了一个完整的设置中心:八个分组(面板登录/下载保种/站点搜索/刮削/媒体库/通知/批量保种/其他),每项带中文提示,填完点「测试全部连接」逐项验证,保存热生效不用重启。配置落盘 settings.json,自动 chmod 600。
README 里把依赖分了层:qb/tr/Prowlarr 必装,TMDB/Emby 推荐,歌词/企微选配。复制 compose,填地址,三分钟接线。
五、彩蛋章节:资深 PTer 的保种转种
上线庆典前夜,我又给它加了一套给老 PTer 的玩具:
- 批量保种:填个总量(比如 2T),它自动翻页拉取整站种子列表、按条件筛选、去重、边拉边下、够量自动停。种子全部隔离在专用目录——不辅种、不入库、不打扰正常流水线,到期删目录即清仓。内建磁盘保护线和节流,不塞爆盘、不打爆站
- 这里还撞破了一个天花板:Prowlarr 的搜索接口不支持翻页,永远只给最新 50 条。解法是绕过它,直接复用它配置里的 Cookie 去扒站点
torrents.php列表页——真分页,想翻多深翻多深 - 缺种报告:每个内容在哪些站做种、哪些站搜不到,一张矩阵看清转种机会
- 半自动发种资料包:一键生成主标题/副标题/TMDB 简介 bbcode,复制去目标站人工发布。带禁转/独家标记的直接硬拦截,连"确认继续"的按钮都不给——这行代码是学费换来的,懂的都懂
六、技术底色与两次白屏的教训
全程坚持两条怪癖:
- 纯 Python 标准库,单文件。bencode 解析、Transmission RPC、qb API、TMDB 客户端、企微 AES、HTTP 服务器,全部手写,零依赖。
python packseed.py就是全部部署 - 网页也在这个文件里。HTML/CSS/JS 都是 Python 字符串模板
第 2 条让我两次栽进同一个坑:模板 JS 里写了 \n 和 \',Python 先把转义吃掉,渲染到浏览器就是残缺 JS,整页白屏。第二次之后立了铁律:模板里禁写一切反斜杠转义;验证必须用 Python 求值后的产物提取 JS 过 node --check——从源码正则提取等于白检。同一个坑摔两次,值得刻在石头上。
七、数字盘点
上线这天的战报:
- 接入站点 66 个,tr 里做种副本 900+
- 一部《大明王朝1566》同时在 41 个站做种
- cross-seed 辅不上的合集包,单源最多辅出 20+ 站
- 媒体库 25 部剧影全部自给自足刮削,NFO/海报/命名齐整
- 批量保种首夜:自动翻了 30+ 页,入队 1500+ 个种子,朝着 2T 目标匀速前进
- 代码:一个文件,约 3000 行,零第三方依赖
尾声
三个月前它叫 PackSeed,是对着 cross-seed 赌的一口气;今天它叫观澜,是我每天打开都会心情变好的东西。深蓝的页面上海浪在动,海报像船一样漂着,搜索框问我:今晚观什么澜?
自己的海,自己看。
MIT 开源,单文件,欢迎来玩:https://github.com/zkzkeep/packseed