docs(porting): MoviePilot 推荐 / 探索对照与发现页取舍
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
ad3bf8926b
commit
27514f4985
1 file changed
+54
@@ -0,0 +1,54 @@
|
||||
# MoviePilot 推荐 / 探索对照(发现页)
|
||||
|
||||
上游:前端 `MoviePilot-Frontend/src/pages/{recommend,discover,browse}.vue`、`views/discover/*`、`utils/recommendSources.ts`;
|
||||
后端 `app/chain/{recommend,tmdb,douban,bangumi}.py`、`app/api/endpoints/{recommend,discover}.py`、`app/modules/douban/apiv2.py`、`app/modules/bangumi/bangumi.py`、`app/modules/themoviedb/tmdbapi.py`(v3.0.10-1)。
|
||||
|
||||
## MP 有什么
|
||||
|
||||
| 页面 | 结构 | 数据源 / 分类 |
|
||||
| --- | --- | --- |
|
||||
| 推荐 `/recommend` | 按分区横向滑动(`MediaCardSlideView`),每区「查看全部」进 `/browse/<api>`;顶部按「全部 / 电影 / 剧集 / 动漫 / 音乐 / 榜单」筛分区;分区可开关(存用户配置) | TMDB 流行趋势(`trending/all/week`)、TMDB 热门电影 / 剧集(`discover`,剧集限 zh/en/ja/ko)、豆瓣正在热映、豆瓣热门电影 / 剧集 / 动画、豆瓣最新电影 / 剧集(`movie|tv/recommend sort=R`)、豆瓣 Top250、豆瓣华语 / 全球口碑剧集榜、Bangumi 每日放送、AniList、音乐 |
|
||||
| 探索 `/discover` | 按来源分标签(TMDB / 豆瓣 / Bangumi / …),每个来源一组筛选芯片,下面是无限滚动网格(`MediaCardListView`,`page++`) | TMDB:类型(电影 / 剧集)、排序、风格、原始语言、评分(+最少评分人数);豆瓣:类型、排序(综合 / 首映 / 近期热度 / 高分)、风格、地区、年代(拼成 `tags`);Bangumi:分类、排序(排名 / 日期)、年份 |
|
||||
| 卡片 | 海报、评分、标题、年份;右上角「已入库 / 已订阅」标记;点开进媒体详情(豆瓣 / bgm 条目在详情页再识别 TMDB);卡片上可订阅 | — |
|
||||
|
||||
缓存:推荐链每个列表 `@cached(ttl=24h, skip_empty=True)`;TMDB / 豆瓣 / bgm 底层请求另有 `@cached(ttl=CONF.meta)`,失败(None)不缓存。
|
||||
|
||||
## 我们原来有什么
|
||||
|
||||
只有 bgm 每日放送、豆瓣实时热门电影 / 剧集三个标签,没有 TMDB 列表、榜单与筛选;卡片没有本地状态。
|
||||
|
||||
## 这次做了什么
|
||||
|
||||
页面选「综合 + 可拆分」:**推荐**(综合,按分区横排,每区「查看全部」带着同样的参数跳到探索)与**探索**(选来源后出筛选器,无限滚动),两者在同一个路由 `/console/discover?view=recommend|explore`,状态全部放在 URL 里,可分享、可回退。理由:MP 两页的分工(推荐看热点、探索做筛选)好用,但两页之间来回跳要重选条件;放一页、共享 URL 参数后「查看全部」就是带参数切到探索。
|
||||
|
||||
| 来源 | 列表 | 接口 |
|
||||
| --- | --- | --- |
|
||||
| TMDB | 流行趋势(日 / 周 × 全部 / 电影 / 剧集)、热门、正在上映 / 正在播出、即将上映 / 今日播出、高分、按条件筛选(类型、风格、原始语言、出品地区、年份或年代、最低评分、排序)、关键词搜索 | `GET /discover/tmdb` |
|
||||
| 豆瓣 | 榜单(实时热门、正在热映、热门、即将上映、Top250、国产 / 欧美 / 日 / 韩剧、动画、综艺、华语 / 全球口碑剧集榜)、标签(热门 / 最新 / 豆瓣高分 / 冷门佳片 / 华语 / 美剧…)、筛选(排序 + 风格 + 地区 + 年代,同 MP)、关键词搜索 | `GET /discover/douban` |
|
||||
| Bangumi | 每日放送、热门趋势、排行(可选年份)、最新、关键词搜索 | `GET /discover/bangumi-calendar`、`GET /discover/bangumi` |
|
||||
|
||||
卡片:海报(懒加载)、评分、标题、年份 · 类型 · 风格;本地状态只显示非默认值(已订阅 / 媒体库已有 / 下载中)。点卡片:有本地作品进媒体库详情;TMDB 条目进 `media/tmdb/:type/:id`;豆瓣 / bgm 条目先按名称 + 年份匹配 TMDB(原有匹配逻辑),确定就进作品页,不确定列候选。卡片上「订阅」「搜索资源」同样先拿到 TMDB 作品再开订阅表单 / 选站点。
|
||||
|
||||
豆瓣 / bgm 条目确定匹配后记在 `kv_cache discover.match`(30 天),下次列表据此标本地状态,再点也不用重新匹配;不确定 / 失败不记。
|
||||
|
||||
### 取舍与偏离
|
||||
|
||||
- **HTTP 直连,不登录,不用浏览器**:豆瓣(rexxar 带 `Referer: https://m.douban.com/`;桌面版 `j/search_subjects`、`j/subject_suggest` 带浏览器 UA)与 bgm(官方 API,只要 UA)2026-10-06 实测都能直接拿到。被风控(403、返回验证页而不是 JSON)时按失败处理、不缓存、界面报错可重试;以后真的频繁被拦,再考虑经内置浏览器代取(适配器的 `fetch` 是注入的,换成浏览器代理的 fetch 即可,本线不实现)。
|
||||
- **bgm 热门趋势**没有 API,抓 `bgm.tv/anime/browser?sort=trends` 的服务端渲染 HTML;HTML 是外部不可信字节,按 ADR-005 在沙箱任务 `bangumi.trends` 里解析(`parseBangumiBrowser`)。
|
||||
- **豆瓣搜索**用 `j/subject_suggest`(联想,不分页,约 10 条);MP 用要签名的 frodo 接口,我们不用。
|
||||
- **豆瓣筛选**用 rexxar `movie|tv/recommend`(MP 用 frodo 同名接口,参数相同);标签列表用桌面版 `j/search_subjects`。
|
||||
- **TMDB 列表缓存**:仍走 TMDB 请求缓存(`tmdb.request`,失败不缓存),但列表类路径(`/trending/`、`/discover/`、电影 / 剧集榜单)TTL 单独取 6 小时、空结果不超过它(`TmdbConfig.cache.listTtlMs`);我们详情缓存 30 天,列表不能跟着它。MP 为 24 小时(`CONF.meta` / `recommend_ttl`),这里取短一些,日榜不至于整天不变。
|
||||
- **MP 的音乐、AniList、插件扩展来源**不做;推荐分区的开关配置不做(分区不多,按「全部 / 电影 / 剧集 / 动画 / 榜单」筛即可)。
|
||||
- TMDB 风格、语言、地区字典写在 `@umt/contracts`(`TMDB_MOVIE_GENRES` 等),界面与服务端校验共用,不请求 `/genre/list`(同 MP)。
|
||||
|
||||
## 豆瓣 / bgm 请求缓存(对照 `DoubanApi.__invoke / __post`、`BangumiApi` 的 `@cached`)
|
||||
|
||||
| 上游 | 我们 |
|
||||
| --- | --- |
|
||||
| 每个请求 `@cached(maxsize=CONF.douban, ttl=CONF.meta, skip_none=True)`,键 = 函数 + 参数 | 列表 / 搜索请求经 `MetaRequestCache` 端口 → 服务端 `cachedCall`(region `douban.request` / `bangumi.request`,上限 5000 条);键 = `方法 + 参数排序后的地址 + 请求体`(`metaRequestKey`) |
|
||||
| TTL 只有一个 `CONF.meta` | 按类别取 `storage.cacheTtl`:搜索 `metaSearchDays`(缺省 1 天)、榜单 / 热门 / 每日放送 / 趋势页 `metaListHours`(缺省 6 小时)、空结果 `metaEmptyHours`(缺省 1 小时,不超过正常 TTL) |
|
||||
| `skip_none`:请求失败返回 None 不缓存 | 网络失败、非 2xx(含 403)、返回的不是 JSON(风控 / 验证页)、趋势页不是浏览页,适配器都抛错,`cachedCall` 不写 |
|
||||
| 条目详情同样走请求缓存 | 条目详情**不走**请求缓存:已有条目级缓存 `douban.subject` / `bangumi.subject`(30 天,存归一化后的标题 / 别名 / 年份,还收站点详情页与网页搜索得到的条目),再缓存一遍原始响应就是同一份数据存两遍;`meta.subject_miss`(6 小时)保留,是识别升级时防止反复打外站的负缓存,不属于请求缓存 |
|
||||
| 限流:无(靠缓存) | 每源进程内限流(豆瓣 2 并发、起始间隔 300 ms;bgm 3 并发、100 ms),只包真正发出的网络请求,缓存命中不占额度 |
|
||||
|
||||
设置字段只在 `contracts/settings.ts` 追加(`metaSearchDays`、`metaListHours`、`metaEmptyHours`),设置页界面由设置线决定是否展示。
|
||||
Reference in new issue
Block a user