20 KiB
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 行,以中文版为准)
- 结构:以 Apache-2.0 全文为基础,另加附加条件。两者冲突时,附加条件优先。适用中华人民共和国法律。
- 免费使用范围:只限非商业用途,并且可以为这些用途修改。非商业用途包括:(1) 个人或家庭自用,包括部署在自己的设备或自己租用的服务器上;(2) 在家庭成员和亲友范围内非营利地共享;(3) 学习、研究和教学。
- 需要书面授权的商业用途:(1) 以 SaaS、托管、多租户等形式向第三方提供,不论是否收费;(2) 出售、出租,或者预装、捆绑到收费的硬件(包括 NAS)或服务中;(3) 收费部署、代运维,或者作为付费会员、收费社群的权益;(4) 公司或营利组织在经营活动中使用,包括内部使用;(5) 其他以直接或间接获取经济利益为目的的使用。
- 再分发:只允许非商业分发。分发时要附上许可全文并保留各项声明,修改版本要显著注明修改内容。衍生作品必须继续适用本许可,不得改用其他许可,也不得削弱附加条件。
- 历史版本:v0.27.0 及之前发布的版本仍适用 MIT。
- 贡献:贡献者同意版权人可以更改许可,也可以把贡献用于商业授权。
"内部使用"是否受限,取决于使用主体:个人或家庭自托管明确免费;公司或营利组织的内部使用明确需要授权。
保守建议:本项目的使用主体是谁(个人、家庭,还是公司或营利组织),应由用户自己确认。在确认之前,对 v0.27.0 之后的内容一律只读设计思路。按目前的核对结果,本项目需要的资产都已在 v0.27.0 中,没有必要触碰新许可下的内容。
6. 风险与建议
- ledger 需要改锚点:
license-and-provenance.md中 CL-009 和 CL-010 锚定的fc9eb72在许可切换之后。建议追加新行,锚定到v0.27.0(c79bb1b0)、许可 MIT,旧行按 §3.3 的规则标记为retired,不删除。这两个文件在两个提交里的内容完全相同,已用 diff 核实。 - 现有政策禁止
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:<路径>。这份文档的写作范围不包括修改政策文件。 - MIT 已经足够宽松:它允许商业使用、修改和再分发,只要求保留版权和许可声明。MIT 授权不能被追溯撤回,这是通行理解,但不作法律结论。
- 上游来源的连带风险:v0.27.0 的 tracker 和 downloader 代码中没有出现 MoviePilot、Jackett、Cardigann 等字样(已 grep 核实)。但无法排除 MC 的作者参考过 GPL 项目。选择器属于站点公开 HTML 结构这类事实数据,受版权保护的程度较低。
- 选择器的时效:MC 最后一次修改站点配置是 2026-09-05,其中憨憨的新版类名是 2026-08 实测的。所有站点都要用我们自己的账号核验。观众的 promo 和 H&R 配置在 MC 里也是空的,MC 并不比我们多知道这部分。
- 不要把许可切换之后的代码混进来:克隆目录固定在
v0.27.0(detached HEAD)。移植时只用git show v0.27.0:<path>取文件,不从 main 取。 - 第三方子组件:
skill-creator(Apache-2.0)和liquid-glass(MIT)有各自的许可证,不属于 MC 自己的 MIT 范围。
建议的执行顺序
- 用户确认第 2 条的政策修改。
- 先转换 audiences、chdbits、hhanclub 三个站点的 JSON,扩展
umt.detail以支持 HHClub 的 div 结构。 - 馒头补齐 detail 和 profile。
- 批量转换其余 NexusPHP 站点(ttg、ourbits 需要自定义适配器)。
- 新增 Transmission 适配器。
- 前端移植 task-activity 和 job-attention 的逻辑。