Skip to content

种子浏览与媒体发现模块(种子详情 / 推荐 / 探索) ​

第三批移植原项目最后三个最大的站点/媒体功能。两个架构决策(已与用户确认锁定):

  • 按需联动(on-demand join):推荐/探索展示媒体元数据(海报/评分/简介),每项「在站点中查找」按钮复用既有 POST /api/v1/search(把标题当 keyword)实时返回各站命中种子——不预过滤、无 N×M 预算、零后端改动。
  • 信息流 vs 搜索:推荐 = 热门/趋势信息流(豆瓣热映/TMDB trending/Bangumi 热门);探索 = 关键词/分类跨源搜索媒体。两者共享「在站点查找」联动基础设施。

功能覆盖 ​

模块能力数据来源
种子浏览跨站搜索 → 点击单种查看详情页(简介 HTML/截图墙/MediaInfo/外链 ID/技术规格)details.php(NexusPHP HTML)/ MTeam /api/torrent/detail
推荐多源热门/趋势信息流(豆瓣热映·即将上映·剧集 / TMDB trending·popular / Bangumi 热门),按源+分类筛选,一键在站点查找豆瓣 frodo /api/v2/{movie,tv}/hot / TMDB /trending / Bangumi /v0/search/subjects?sort=heat
探索关键词跨源搜索媒体(豆瓣/TMDB/Bangumi),按源筛选,一键在站点查找复用既有 MediaChain.Search(跨源合并 + PosterCache)

后端结构 ​

种子详情(TorrentDetail)— capability 范式 ​

internal/site/
├── adapter.go      TorrentDetailCapable(FetchTorrentDetail,type-assert 判断)
├── types.go        DetailDef(fields map,空则 EnsureDefaults 填 NexusPHP 默认)+ TorrentDetail DTO
├── defaults.go     DefaultNexusPHPDetail(details.php 选择器:#kdescr 简介/screenshots/imdb/douban/download)
└── seedetail.go    ParseTorrentDetail(复用 Extract/ApplyFilters/ResolveURL)+ extractMulti(screenshots/file_list 多值收集)
internal/site/schemas/seedetail.go
├── NexusPHP.FetchTorrentDetail   直接 GET 绝对 detailURL(不经 joinURL)+ loggedOut + ParseTorrentDetail
└── MTeam.FetchTorrentDetail      POST /api/torrent/detail {sn}(sn 从 detailURL 末段解析)+ mtSNFromDetailURL
internal/chain/site.go   SiteChain.TorrentDetail(sameHost SSRF 守卫 → 10min 缓存 → dispatchAdapter → 类型断言)
internal/api/v1/site.go  SiteHandler.TorrentDetail(?url=)

关键点:① detailURL 为绝对 URL(前端透传种子的 detail_url),chain 先做 sameHost 守卫(比对最后两段注册域,兼容 api.m-team.cc/kp.m-team.cc 同站不同子域;socket 层 ssrf=true 已拦私网 IP,此为授权层防 A 站 cookie 探测 B 站)。② 顺手修 MTeam bug:parseMTTorrent 原本不设 DetailURL,现补 kp.m-team.cc/detail/<id>(同时承载 id 供详情抓取解析 sn)。③ 选择器为代表默认,各站 DOM 差异需 /sites/inspect 实测校准。

Bangumi 客户端 — 新 MediaSource ​

internal/media/bangumi.go   Bangumi(v0 API,可选 Bearer token)+ Search(/v0/search/subjects filter.type [2,6]) + Detail(/v0/subjects/{id}) + Trending(sort=heat)
internal/media/media.go     TrendingCapable 接口(可选,不破坏 base MediaSource;MusicBrainz 跳过)
internal/media/{douban,tmdb,bangumi}.go   各源实现 Trending(豆瓣 /movie/hot·/coming·/tv/hot、TMDB /trending/{movie,tv}/week·/movie/popular、Bangumi heat)
internal/media/douban.go   豆瓣 frodo **双鉴权**:微信免签(默认主策略)+安卓 HMAC-SHA1 `_sig`/`_ts`(参考 MoviePilot `apiv2.py`,bestyize 真实抓包向量验证);`DOUBAN_SECRET` 非空→切签名为主,鉴权类失败(401/403/`sig`·`api_key` 的 400)自动互切兜底

关键点:① Bangumi 无需扩 MediaInfo——既有 Source/Type 字段够用(Bangumi→Source="bangumi"、动漫/三次元→TypeTV,前端按 source 区分)。② TrendingCapable 是可选接口(仿 *Capable 范式),推荐链类型断言跳过不支持者(MusicBrainz)。③ 图片反代 mediaImageHosts 加 lain.bgm.tv/bgm.tv(不防盗链,复用既有 utls mediaClient)。④ 配置 BANGUMI_TOKEN(可选,提升速率;空走匿名配额)。

寸光集(短剧)源 — 新 MediaSource + CategoryCapable ​

internal/media/cunguangji.go   寸光集(dj.hxpt.org / 寸光集 D:\www.ptang.top)短剧源:
                                 Search/Trending(/api/explore?sort=&q=&page=) + Detail(/api/explore/<id>),短剧→TypeTV
internal/media/media.go         CategoryCapable 接口(可选:声明源支持的 category;未实现者=支持全部,向后兼容)
internal/media/{douban,tmdb,bangumi,cunguangji}.go   各源实现 Categories()(豆瓣 movie/coming/tv、TMDB +anime/popular、Bangumi +real、寸光集=duanju)
internal/chain/recommend.go     扇出循环按 CategoryCapable 跳过不支持当前分类的源
站点 D:\www.ptang.top            新增公开只读 API /api/explore(列表/搜索) + /api/explore/<id>(详情),复用 lib/queries.ts;封面 lib/cover.ts.toExploreCoverSrc 返回站内相对路径 /api/img?url=…(站点自带反代绕防盗链),PTPatronus 端用配置 base 拼绝对地址(nginx 反代下 req.nextUrl.origin 不可靠,故不依赖站点感知自身公网域名)

关键点:① 寸光集是自有外部站点(短剧点评社区),无列表 JSON API,故在站点侧加只读 /api/explore(不污染既有 SSR/管理 API)。② CategoryCapable 让「短剧」分类只由寸光集响应——豆瓣/TMDB/Bangumi 不会各自回退默认热映污染;顺带修复「anime 让豆瓣回退热映」之类既有回退污染。③ 短剧归 TypeTV(影视/视频桶),Categories()=['duanju'],故默认分类(movie)下不参与。④ 配置 CUNGUANGJI_BASE(默认 https://dj.hxpt.org,可指本地实例联调)。⑤ 站点需重新发布到 dj.hxpt.org 才生效;前端选「寸光集」自动联动分类到「短剧」(互斥,避免空态)。

推荐链(RecommendChain)— 仅内存缓存 ​

internal/chain/recommend.go   RecommendChain(仿 AssessmentChain 但更简:仅内存缓存 30min,无 DB 持久化——趋势是临时数据)
                              RecommendFeeds(source,category,page,force):并发扇出(semaphore 4、每源 15s 超时、类型断言 TrendingCapable、容错合并)+ 缓存
internal/api/v1/media.go      MediaHandler.Recommend(?source=&category=&page=&refresh=1)+ Discover(复用 MediaChain.Search)
internal/app/app.go           mediaSources 加 Bangumi + 构造 RecommendChain 注入 api.Deps

关键点:推荐链不落库(趋势日级变化,内存 30min 缓存足够),比考核的 3 级缓存简单很多。

探索 + find-on-sites — 零新 chain/端点 ​

  • 探索:MediaHandler.Discover 直接调既有 MediaChain.Search(chain/media.go,已跨源合并 + PosterCache),source 参数做返回后过滤。无新 chain。
  • 在站点查找(find-on-sites):前端「在站点查找」按钮直接 POST /api/v1/search?keyword=<标题>(既有 SiteChain.SearchSites,已并发扇出 + 容错 + 返回各站 site.Torrent[])。零后端改动。

数据流(一条完整链路) ​

推荐页 → GET /media/recommend → 各源 Trending → []MediaInfo(海报走 /media/image 反代)→ 点项「在站点查找」→ POST /api/v1/search(标题当 keyword)→ 各站命中种子 → 点种子 → GET /sites/:id/torrent/detail?url= → TorrentDetail。全链路复用既有 infra(httpclient SSRF、ElementQuery 选择器引擎、dispatchAdapter、mediaImageHosts 反代)。

API ​

方法路径说明
GET/media/recommend推荐信息流(?source=douban|tmdb|bangumi|cunguangji&category=movie|tv|anime|coming|duanju&page=&refresh=1)
GET/media/discover跨源媒体搜索(?keyword=&year=&source=,复用 MediaChain.Search)
GET/sites/:id/torrent/detail种子详情页(?url=<详情页绝对 URL>,sameHost 守卫)
POST/search跨站搜索(复用既有,find-on-sites 联动用)

均挂 guarded 组。无新 cron(推荐是请求时实时拉取 + 内存缓存)。

前端 ​

  • Web:3 视图(SeedBrowse.vue 跨站搜索表+详情抽屉渲染简介HTML/截图墙/MediaInfo / Recommend.vue 卡片网格+源/分类 chip+在站点查找弹窗 / Discover.vue 搜索框+源 chip+媒体卡+在站点查找)+ 3 api(seedbrowse/recommend/discover)+ 路由 + 导航(GlassIcon 加 seedbrowse/recommend/discover 字形)。海报统一 <MediaPoster>。
  • Mobile:3 feature 页(seedbrowse/recommend/discover)+ 3 api + 账户页入口(不加底部 tab,7 槽已满)。新增共享 widget widgets/media_poster.dart(首批需海报的 Flutter 页:豆瓣走反代、TMDB/Bangumi 直连、失败回退 emoji)+ widgets/find_on_sites_sheet.dart(推荐/探索共用「在站点查找」抽屉)。

测试 ​

go test ./internal/site/... ./internal/media/... ./internal/chain/...:

  • 种子详情:NexusPHP details.php fixture(简介/截图[]/IMDBID/DoubanID/DownloadURL 绝对化)+ MTeam /api/torrent/detail JSON 映射 + parseMTTorrent 补 DetailURL 回归 + mtSNFromDetailURL 末段/query 抽 id。
  • Bangumi:search/detail fixture(Source/SourceID/PosterURL/年容差)+ Trending。
  • 推荐:豆瓣/TMDB/Bangumi Trending 端点 fixture + TMDB 未配置返 ErrNotConfigured。
  • RecommendChain:两假源 TrendingCapable 合并 + 二次命中缓存(源不重复调用)+ force 绕过缓存 + source 过滤 + 无 Trending 能力源跳过。

待校准(真实环境) ​

按 [[pt-site-data-references]] 选择器校准工作流,配真实站点后逐项钉值:

  1. 种子详情:NexusPHP Detail.Fields 各站选择器(可用 POST /api/v1/sites/inspect 对真实 details.php 校准)。
  2. MTeam /api/torrent/detail 端点路径/sn 参数名/字段名(description/body/mediaInfo/status);detailURL→sn 解析。
  3. Bangumi /v0/search/subjects 的 rating 形态(search 扁平 rating_score vs detail rating.score)。
  4. 豆瓣 frodo 热门路径与响应结构(/api/v2/movie/hot 等)。
  5. 各源 Trending 端点字段。