171 lines
20 KiB
Markdown
171 lines
20 KiB
Markdown
# 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 的逻辑。
|