Files
UHD_Media_Tool/docs/porting/movieclaw-assessment.md
2026-09-27 18:19:46 +08:00

20 KiB
Raw Permalink Blame History

MovieClaw 可复用资产评估(MIT 边界核对)

核对日期 2026-09-27。本文不是法律意见,只记录可以复核的事实和保守的工程建议。它补充 license-and-provenance.md §1 和 §4 的待办项"MovieClaw 是否有可用的 ≤v0.27.0 MIT tag"。

源码只读克隆在 spikes/movieclaw-src/repo(spikes/movieclaw-src/.gitignore 的内容是 *,不进 git)。工作区检出在 v0.27.0。仓库地址是 https://github.com/movieclaw/movieclaw,来自 REQ 附录 [S16]。

1. 许可时间线(以 LICENSE 文件内容为准)

逐个 tag 读取 git show <tag>:LICENSE 和 pyproject.toml 的 version,再用 git log --follow -- LICENSE 核对 LICENSE 的每一次改动。

时间(+0800) 提交 / tag LICENSE 内容 说明
2026-05-08 cbc54c1 首次提交 MIT,版权人 yipengfei
2026-07-18 至 08-26 torrent-ner-v1 到 v0.18.0,共 21 个 tag MIT,版权人 yipengfei 每个 tag 都读过
2026-08-30 21:00 50b43fe MIT,版权人改为 MovieClaw 只改了版权人,许可种类没变
2026-08-31 至 09-18 v0.19.0 到 v0.26.0 MIT,版权人 MovieClaw 每个 tag 都读过
2026-09-24 v0.27.0 = c79bb1b0(最后一个 MIT tag) MIT,Copyright (c) 2026 MovieClaw,文件 md5 73a392ea… pyproject 版本是 0.27.0,license = { text = "MIT" }
2026-09-26 20:04 403a3547(最后一个 MIT 提交,没有 tag) MIT 在 v0.27.0 之后又有 14 个提交,改的都是播放、Worker 和 Web 外壳
2026-09-26 23:55 251f1988(许可切换,#457) MovieClaw License,即 Apache-2.0 加非商业附加条件 这次提交还改了 README、pyproject 的 license 字段和 movieclaw_jellyfin/authhdr.py。version 仍是 0.27.0
2026-09-27 03:34 fc9eb724(REQ 附录快照) 附条件许可 本项目的 ledger CL-009 和 CL-010 目前锚定在这个提交上,它属于新许可
2026-09-27 main = eb467dcb 附条件许可 从 v0.27.0 到 main,共改动 163 个文件,新增 15111 行,删除 2892 行

结论。 应当以 tag v0.27.0(c79bb1b0)作为 MIT 基线。403a354 也带 MIT LICENSE,但新许可第五条写的是"v0.27.0 及之前发布的版本"。没有打 tag 的提交是否算"发布"存在争议,所以不用它。另外,本文关心的所有文件在 v0.27.0..403a354 之间都没有变化(见 §2.3),放弃这个提交没有任何损失。

2. 站点定义

2.1 v0.27.0 中 src/movieclaw_tracker/sites/configs/ 的全部文件(24 个)

_template.yaml 以及下面 23 个站点:

site_id 名称 框架 分页偏移 H&R 选择器 促销规则 促销截止时间 覆盖 login_* 覆盖字段数
audiences 观众 nexusphp -1 — 默认 img.pro_* — — 8
chdbits 彩虹岛 nexusphp -1 — 默认 有 有 14
hhanclub 憨憨 nexusphp(自定义 div 模板) -1 有 自定义 — 有 33
mteam M-Team api,另有 custom/mteam.py 0 —(API 不提供) — — — 0
agsvpt AGSVPT nexusphp -1 — 默认 — — 12
hdarea HDArea nexusphp -1 — 自定义 — — 27
hddolby HDDolby nexusphp -1 — 自定义 — — 27
hdfans HDFans nexusphp -1 — 自定义 — — 27
hdhome 高清家园 nexusphp -1 有 默认 — — 14
hdsky HDSky nexusphp -1 — 自定义 — 有 32
hdtime HDTime nexusphp -1 — 自定义 — — 27
hdvideo HDVIDEO nexusphp -1 — 自定义 — 有 32
keepfrds 朋友 nexusphp -1 — 自定义 — — 11
nicept NicePT nexusphp -1 有 自定义 — — 27
ourbits OurBits nexusphp,另有 custom/ourbits.py(cat[] 参数) -1 有 默认 — — 12
piggo 猪猪 nexusphp -1 — 自定义 — — 27
pter 猫站 nexusphp -1 — 默认 — — 12
pthome 铂金家 nexusphp -1 — 默认 — — 13
pttime PTTime nexusphp -1 — 自定义 — — 27
soulvoice 聆音 nexusphp -1 — 自定义 — — 27
ssd 不可说 nexusphp -1 — 自定义 有 有 25
tjupt 北洋园 nexusphp 0 — 默认 — 有 26
ttg 听听歌 nexusphp,另有 custom/ttg.py 0 — 自定义 有 有 13

没有任何一个站点配置了 hr_seed_hours,它只在模板里出现过。

2.2 四个重点站点的字段结构(v0.27.0)

YAML 的顶层键包括 site_id、display_name、base_url、framework,以及可选的 web_base_url、auth.supported、min_request_interval、timezone、custom_class、selectors、categories。selectors 只写需要覆盖的键,没写的键沿用 movieclaw_tracker/selectors.py 中 NexusPHPSelectors 的默认值。

  • audiences:base_url 是 https://audiences.me。行选择器是 table.torrents > tr:has(table.torrentname)。分类取自 a[href^='?cat=']::attr(href),副标题是 span.torrent-subtitle-line,page_offset 为 -1。用户资料里,上传量和下载量取自 userbar 的 span.site-userbar__compact-metric--uploaded,下载同理。分类映射为 movie 401、tv 402/403、documentary 406。这些选择器只覆盖了列表和用户资料:促销、H&R、详情页都沿用默认值,没有 search 相关的参数。
  • hhanclub:base_url 是 https://hhanclub.net。列表是 div 卡片结构,行选择器为 div.torrent-table-sub-info,标题、副标题、大小、做种、下载、完成、发布者、时间(带 span[title] 回退)、详情和下载链接都有专用的 div.torrent-info-text-* 选择器。促销使用 span.promotion-tag-*,新旧两套类名共 8 条下载系数规则、4 条上传系数规则。H&R 用 div.torrent-info-hr 识别。用户资料取自顶栏,有 10 项,其中很多依赖 ::next_sibling_text。详情页是 Tailwind 的 div 结构,用 :contains('标题') 定位。分类有 6 组,另外在注释里写了 401 到 412 的完整分类表。
  • chdbits:base_url 是 https://ptchdbits.co(注释写明 2026-08-01 从 chdbits.co 换了域名)。行选择器与 audiences 相同,副标题是 font.subtitle。促销沿用默认的 img.pro_*,截止时间取 td.embedded > span[title]。登录成功的判定是 a[href='logout.php']。用户资料取自顶栏的 font.color_* 加 ::next_sibling_text,VIP 组用 a[class^='VIP'] 识别。分类有 6 组。
  • mteam:base_url 是 https://api.m-team.cc,web_base_url 是 https://tp.m-team.cc,framework: api,auth.supported: [apikey],min_request_interval 为 1.0。分类表有 8 组,把成人内容的 14 个 ID 单独列出。接口逻辑在 sites/custom/mteam.py(509 行),用到 /api/torrent/search、/api/torrent/detail、/api/torrent/genDlToken、/api/member/profile、/api/tracker/myPeerStatus,还有 mode=adult 独立索引和 mallSingleFree 覆盖。

2.3 与 main 的差异

git diff --stat v0.27.0 main -- src/movieclaw_tracker/ 的输出为空:整个 tracker 包(站点配置、custom/*.py、frameworks/nexusphp.py、selectors.py、auth.py、http.py、ratelimit.py、registry.py)在 main 上没有任何新增或修改。站点配置目录最后一次改动是 ff5a839(2026-09-05,OurBits 的 cat[])。所以就站点定义而言,main 上不存在受新许可约束的增量,v0.27.0 的版本就是最新版本。

3. 其他资产分类

结论同上。对下列路径执行 git diff --stat v0.27.0 main,结果都为空:src/movieclaw_downloader、src/movieclaw_agent、apps/web/lib/{task-activity,job-attention,agent-activity,agent-media-cards}.ts、apps/web/components/{agent-conversation-view,task-center-view,agent-media-cards}.tsx、src/movieclaw_api/services/{download_health,diagnosis_handoff}.py、docs/design/agent-skills.md。

3.1 可以直接移植(MIT,取 v0.27.0)

资产(v0.27.0 路径) 规模 建议落点 备注
src/movieclaw_tracker/sites/configs/*.yaml(23 个站点) 36–95 行/个 packages/adapters/src/sites/definitions/<id>.json,并在 registry.ts 登记 需要转换 schema,映射见 §4。选择器是 MC 作者实测的结果,仍须用我们自己的账号核验
sites/custom/mteam.py 509 对照 packages/adapters/src/sites/mteam/* 补齐 detail、profile、myPeerStatus、adult 索引、mallSingleFree 现有实现是按 MP 做 behavior-ref,可以把 MC 的 detail 字段直接作为依据
sites/custom/ourbits.py、ttg.py 41、302 packages/adapters/src/sites/<id>/ TTG 不是标准 NexusPHP 结构,要另写 spider
frameworks/nexusphp.py、selectors.py 518、169 spider/* 的补充:::next_sibling_text、:contains、促销截止时间正则、用户资料解析(M2) 本项目的 spider 已按 MP 实现,这里只借用 MP 没有的能力
auth.py(cookie、账号密码模拟登录、apikey) 506 M2 站点登录 账号密码登录涉及站点规则,按需使用
src/movieclaw_downloader/clients/transmission.py、base.py、models.py、torrent.py 493、151、206、112 packages/adapters/src/transmission/*(新增) 本项目目前只有 qB
src/movieclaw_downloader/clients/qbittorrent.py 543 对照 packages/adapters/src/qbittorrent/* 可以补 set_file_selection、限速、set_location
src/movieclaw_api/services/download_health.py、diagnosis_handoff.py 298、657 packages/tasks 或 packages/agent REQ §13.4 提到的根因聚合和诊断上下文。关联键要加入下载器实例 ID(REQ §13.4 末段)
apps/web/lib/task-activity.ts、job-attention.ts、agent-activity.ts、agent-media-cards.ts 178、43、34、135 apps/web/src/lib/* 纯逻辑,改动最小
apps/web/components/agent-conversation-view.tsx、task-center-view.tsx、agent-media-cards.tsx 872、2345、518 apps/web 同样是 React,但依赖 Next 和 MC 的 @/components/*、@/lib/api/*,只能取局部。建议只移植交互结构,样式按本项目的设计系统重写
docs/design/agent-skills.md 以及 src/movieclaw_agent/skills.py — packages/agent Markdown Skills 的加载和覆盖机制。REQ §606 已经决定不照搬"同名覆盖立即生效"

3.2 不需要,或者不能按 MC 的许可处理

资产 原因
src/movieclaw_agent/builtin-skills/skill-creator/* 附带自己的 LICENSE.txt(Apache-2.0,第三方组件),不属于 MC 的 MIT 范围。需要时去上游取,并遵守 Apache-2.0
apps/web/vendor/liquid-glass/* 第三方 MIT,版权人是 "Liquid Glass OSS contributors",与我们的需求无关
RSS 处理 MC 在 v0.27.0 没有独立的 RSS 解析模块,只在 movieclaw_db/models/site_torrent.py 定义了 RSS 来源枚举和"RSS 观测不写易变层"的规则。这条设计思路可以参考,没有代码可移植
通用 NexusPHP 解析器 见 §3.1,可以移植。本项目已有基于 MP 的 spider,不必替换

3.3 只能参考(新许可,v0.27.0 之后)

main 上新增的内容集中在 macos/MovieClawTranscoder(Mac 转码 Worker)、播放和 Jellyfin 兼容(movieclaw_playback、movieclaw_jellyfin)、Web 外壳主题、订阅规则组适用范围(#446)、发布说明写作指南,以及 docs/design/* 的新文档。这些都不在本项目首期范围内。如果需要参考,只读设计思路,不复制代码,并按 data-ref/behavior-ref 登记,提交号写到具体提交,不写 main。

4. YAML 到本项目 schema 的字段映射

本项目的 schema 定义在 packages/adapters/src/sites/spider/schema.ts(MP indexer schema 加上 umt 扩展)。MC 的选择器是 parsel/cssselect 语法。

MC 键 本项目键 转换规则
site_id / display_name id / name 和 umt.displayName 原样
base_url domain 补上末尾的 /
web_base_url 馒头使用 mteam/definition.ts 仅用于 API 型站点
framework: nexusphp 或 api 加 custom_class umt.kind / parser 自定义类要单独写 TS 适配器
min_request_interval(秒) umt.rateLimit.minIntervalMs ×1000。不配置时 MC 默认 3 秒,与我们一致
timezone(IANA) umt.timezone Asia/Shanghai 转为 +08:00
auth.supported 凭据配置(SecretResolver) 只取信息:该站支持 cookie、账号密码还是 apikey
selectors.search_path、search_keyword_param search.paths[].path、search.params 默认是 torrents.php 和 search。MC 没有配置 search_area
selectors.page_offset browse.start -1 对应 start: 0,0 对应 start: 1
torrent_row_css torrents.list.selector 本项目用 htmlparser2 解析,不插入 tbody,可以直接使用
torrent_title_css fields.title_default
torrent_subtitle_css fields.description
torrent_category_css(X::attr(href)) fields.category = {selector:X, attribute:"href", filters:[querystring cat]} 通用规则:X::attr(a) 转为 {selector:X, attribute:a};X::text 转为 {selector:X}
torrent_size/seeders/leechers/snatched_css size/seeders/leechers/grabs
torrent_time_css / torrent_time_fallback_css date_added(带 attribute title)/ date_elapsed 复用现有的 date 模板
torrent_uploader_css 无对应字段 可以不取,或放进 raw
promo_download_rules / promo_upload_rules downloadvolumefactor.case / uploadvolumefactor.case 保持声明顺序,末尾补 "*": 1。本项目用浮点,没有 MP 的 int 问题
torrent_promo_deadline_css / _attr / _re fields.freedate 的 {selector, attribute, filters:[re_search]}
torrent_hr_css fields.hr 没配置时保持 unknown,与 MC 的"未知"语义一致
hr_seed_hours umt 需要新增,例如 umt.hrSeedHours 所有站点都没配,暂不实现
torrent_detail_url_css / torrent_download_url_css details / download
login_success_css umt.loginSuccess
detail_*_css umt.detail.* 目前 umt.detail 是 rowhead 表格模型,HHClub 的 div 详情页放不进去,需要扩展成逐字段选择器
profile_*_css M2 用户数据 schema(新增) 需要支持 ::next_sibling_text(取紧随其后的文本节点)和 :contains()
categories.{movie,tv,...} category.movie/tv/music[{id}] 与 umt.categoryNames MP 只区分 movie、tv、music 三类,documentary、anime、game、av、other 只进 categoryNames,保留原始 ID(对应 README 中的偏离项 1)
MC 的分类请求参数 cat<id>=1 SpiderCategoryItem(缺省行为) OurBits 需要 param: "cat[]"

与现有 audiences.json 的差异。 下面这些点用 MC 的值去核对:分类选择器 MC 用 ^=,我们用 *=;标题 MC 取链接文本,我们优先取 title 属性;search_area=4 在 MC 里没有出现;H&R 两边都没有配置;用户资料用的是 userbar 的 compact-metric 类。MC 的定义同样没有覆盖 td:nth-child 列号,沿用的是默认的 5 到 8 列,与我们的配置一致。

5. 新许可条款转述(main:LICENSE,299 行,以中文版为准)

  1. 结构:以 Apache-2.0 全文为基础,另加附加条件。两者冲突时,附加条件优先。适用中华人民共和国法律。
  2. 免费使用范围:只限非商业用途,并且可以为这些用途修改。非商业用途包括:(1) 个人或家庭自用,包括部署在自己的设备或自己租用的服务器上;(2) 在家庭成员和亲友范围内非营利地共享;(3) 学习、研究和教学。
  3. 需要书面授权的商业用途:(1) 以 SaaS、托管、多租户等形式向第三方提供,不论是否收费;(2) 出售、出租,或者预装、捆绑到收费的硬件(包括 NAS)或服务中;(3) 收费部署、代运维,或者作为付费会员、收费社群的权益;(4) 公司或营利组织在经营活动中使用,包括内部使用;(5) 其他以直接或间接获取经济利益为目的的使用。
  4. 再分发:只允许非商业分发。分发时要附上许可全文并保留各项声明,修改版本要显著注明修改内容。衍生作品必须继续适用本许可,不得改用其他许可,也不得削弱附加条件。
  5. 历史版本:v0.27.0 及之前发布的版本仍适用 MIT。
  6. 贡献:贡献者同意版权人可以更改许可,也可以把贡献用于商业授权。

"内部使用"是否受限,取决于使用主体:个人或家庭自托管明确免费;公司或营利组织的内部使用明确需要授权。

保守建议:本项目的使用主体是谁(个人、家庭,还是公司或营利组织),应由用户自己确认。在确认之前,对 v0.27.0 之后的内容一律只读设计思路。按目前的核对结果,本项目需要的资产都已在 v0.27.0 中,没有必要触碰新许可下的内容。

6. 风险与建议

  1. ledger 需要改锚点:license-and-provenance.md 中 CL-009 和 CL-010 锚定的 fc9eb72 在许可切换之后。建议追加新行,锚定到 v0.27.0(c79bb1b0)、许可 MIT,旧行按 §3.3 的规则标记为 retired,不删除。这两个文件在两个提交里的内容完全相同,已用 diff 核实。
  2. 现有政策禁止 copied:license-and-provenance.md §2 和 §3.3 规定"不应出现 copied,出现即 CI 失败"。如果要直接转换 MC 的 YAML 选择器值,需要用户先修改这条政策。建议新增 kind=copied-mit:要求 notice_required=是,在仓库根目录的 THIRD_PARTY_NOTICES 或 packages/adapters/src/sites/definitions/NOTICE 中附上 MC v0.27.0 的 MIT 全文和 Copyright (c) 2026 MovieClaw(v0.18.0 及之前的版本版权人是 yipengfei,取 v0.27.0 即可);每个 JSON 的 _provenance 写明 movieclaw@c79bb1b0:<路径>。这份文档的写作范围不包括修改政策文件。
  3. MIT 已经足够宽松:它允许商业使用、修改和再分发,只要求保留版权和许可声明。MIT 授权不能被追溯撤回,这是通行理解,但不作法律结论。
  4. 上游来源的连带风险:v0.27.0 的 tracker 和 downloader 代码中没有出现 MoviePilot、Jackett、Cardigann 等字样(已 grep 核实)。但无法排除 MC 的作者参考过 GPL 项目。选择器属于站点公开 HTML 结构这类事实数据,受版权保护的程度较低。
  5. 选择器的时效:MC 最后一次修改站点配置是 2026-09-05,其中憨憨的新版类名是 2026-08 实测的。所有站点都要用我们自己的账号核验。观众的 promo 和 H&R 配置在 MC 里也是空的,MC 并不比我们多知道这部分。
  6. 不要把许可切换之后的代码混进来:克隆目录固定在 v0.27.0(detached HEAD)。移植时只用 git show v0.27.0:<path> 取文件,不从 main 取。
  7. 第三方子组件:skill-creator(Apache-2.0)和 liquid-glass(MIT)有各自的许可证,不属于 MC 自己的 MIT 范围。

建议的执行顺序

  1. 用户确认第 2 条的政策修改。
  2. 先转换 audiences、chdbits、hhanclub 三个站点的 JSON,扩展 umt.detail 以支持 HHClub 的 div 结构。
  3. 馒头补齐 detail 和 profile。
  4. 批量转换其余 NexusPHP 站点(ttg、ourbits 需要自定义适配器)。
  5. 新增 Transmission 适配器。
  6. 前端移植 task-activity 和 job-attention 的逻辑。