Files
UHD_Media_Tool/docs/porting/license-and-provenance.md
rootandClaude Opus 5.5 b343dddbf6 docs: 清理过程文档,CHANGELOG 补齐 0.3.8–0.3.14
- 删除 docs/plan 下 00–18 的计划、评审、验收、发布记录与升级证据,docs/spikes 与 spikes 验证代码
  (保留 spikes/movieclaw-src 本地克隆),以及 4 份一次性审查 / 调研;全部可在 ceb66f8 查到
- MP 对照移到 docs/porting/moviepilot-v3-comparison.md;经验教训改为 docs/plan/lessons.md(补第 25 条)
- docs/plan/README.md:文档放哪、当前状态、待办
- 引用改写:代码注释指向在维护的文档,其余注明已删除与 git 位置;清掉原有 6 个失效链接
- README 开头改为当前状态与入口;CHANGELOG 补齐 0.3.8–0.3.14 与工程变更

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-02 16:08:09 +08:00

111 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 许可证核对与来源登记(MoviePilot / MovieClaw)
> 本文依据 REQ §14.2 和任务书 §1"参考源码"一栏,属于工程合规边界的说明,**不是法律意见**。在对外分发或商业化之前,必须针对具体要发行的产品另行做法律审查(REQ §14.2 末段)。
## 1. 核对结论
| 项 | MoviePilot | MovieClaw |
| --- | --- | --- |
| 仓库 | `https://github.com/jxxghp/MoviePilot`(分支 `v3`) | `https://github.com/movieclaw/movieclaw`(`main`) |
| 本次核对的提交 | `e6820a83ab05e8a00eb0e14adf0f357faa965c7e`(2026-08-30,`version.py = v3.0.0`)。本地路径 `/opt/moviepilot-plus/upstream/MoviePilot`,是单提交浅克隆 | `fc9eb7248dd9c4f7cd8f3fbd704a357b0b766b90`(REQ 附录 [S16])。**本机没有源码**(`find /opt -maxdepth 3 -iname "*claw*"` 没有结果),是通过 GitHub API 和 raw 取到该提交的 `LICENSE`、`pyproject.toml` 以及站点配置原文(见 `moviepilot-downloader-and-sites.md` §0) |
| REQ 附录快照 | `33da9ce65d5020a8e087584a3321c1ff353c1921`:本地仓库里没有这个对象,无法逐行比对。**以本表提交为准**,引用行号时必须写明提交 | 与附录一致 |
| 仓库许可 | 根目录 `LICENSE` 是 **GNU GPL v3** 全文(674 行,md5 `1ebbd3e34237af26da5dc08a4e440464`) | 该提交的 `LICENSE` 是 **修改版 Apache-2.0,附加非商业条件**;LICENSE 第 44-45 行写明"v0.27.0 及之前发布的版本以 MIT 许可证发布……本许可证适用于 v0.27.0 之后发布的版本" |
| 包元数据 | `pyproject.toml` 没有 license 字段 | `pyproject.toml` 第 7 行 `version = "0.27.0"`,第 11 行 `license = { text = "MovieClaw License (Apache-2.0 with non-commercial conditions)" }` |
| MovieClaw 附加条件要点 | — | 两者冲突时附加条件优先;免费使用仅限非商业(个人/家庭自用、亲友间非营利共享、学习研究教学);**公司内部使用也算商业使用**,需要书面授权;再分发要附许可全文,衍生版本继续适用本许可。本项目给用户个人和家庭的媒体设施使用,是否落在"非商业"范围内要由用户确认;在确认之前,对 MovieClaw 一律只参考字段结构(`data-ref`) |
| 附加声明 | `README.md` 第 17 行写"仅用于学习交流使用,请勿在任何国内平台宣传该项目",第 79-80 行免责申明写"不得用于商业用途……不建议对用户认证机制进行规避或修改并公开发布"。这些是 README 里的声明,**不是 LICENSE 的附加条款**。GPLv3 §7 不允许附加"进一步限制",但按 REQ §14.2 的要求,本项目**仍然尊重这些声明**,不把它们解读成可以忽略的内容 | 附加条件写在 LICENSE 正文里,有约束力:商业使用需要书面授权,衍生版本继续适用同样的条款 |
| 版本字段陷阱 | — | main 的 `pyproject` 版本号仍是 0.27.0,但 LICENSE 已经是附条件版本。**不能根据版本号推定 main 是 MIT**(REQ §14.2 原话)。要按 MIT 使用,只能引用已经核实过的 `v0.27.0` 及更早的 **tag**,而且要逐个文件核对那个 tag 附带的许可 |
### 1.1 MP 中的非源码或闭源部分(不得作为参考源)
| 组件 | 位置 | 状态 | 处理 |
| --- | --- | --- | --- |
| `SitesHelper`(站点认证、流控、站点索引定义) | `app/application/site/sites.cpython-314-x86_64-linux-gnu.so`,已被 `.gitignore:4` 忽略;仓库只有 `sites.pyi` 类型存根 | 闭源二进制,由 `docker/Dockerfile:261-262` 从 `jxxghp/MoviePilot-Resources` 下载 | **不反编译,不参考。** 站点选择器改以 MovieClaw 配置和我们自己抓取的页面为准 |
| 站点样例配置 | `tests/test_rust_accel.py` 里有少量站点 indexer 样例(公开测试数据) | GPL-3.0 | 只用来理解字段语义,不作为选择器的来源 |
| 站点定义数据 | `app/application/site/user.sites.v3.bin`,已被 `.gitignore:12` 忽略,内容加密 | 同上 | 不解密,不使用 |
| Rust 加速 `moviepilot_rust` 0.3.3 | 以 wheel 形式安装在 `.venv`,源码仓库是 `jxxghp/MoviePilot-Rust` | wheel 附带的 LICENSE 是 GPLv3 | 只对照 Python 参考路径(见 `moviepilot-metadata-recognition.md` §0.1) |
| 内嵌的 `tmdbv3api` | `app/modules/themoviedb/tmdbv3api/*`,**文件头没有许可说明**,仓库里也没有单独的 LICENSE/NOTICE | 来源推测是 AnthonyBloomer/tmdbv3api(MIT),但未核实 | 不使用;本项目直接调 TMDB REST v3 |
| 第三方运行依赖 | `anitopy~=2.1.1`、`cn2an~=0.5.24`、`pinyin2hanzi~=0.1.1`、`regex`、`zhconv` 等(`pyproject.toml`) | 各有各的许可 | 本项目如需等价的 npm 库,另行选型并单独登记,不因为 MP 用过就默认可用 |
---
## 2. 本项目的迁移边界
任务书 `00-first-version-plan`(已删除,见 git `ceb66f8`) §1 规定:"MoviePilot:GPLv3,**只做行为对照与 TS 重写,不复制文件**"。REQ §14.1 允许"以具体实现为参考迁移业务逻辑"。两条放在一起执行时,按下表办。
| 允许 | 不允许 |
| --- | --- |
| 阅读上游源码,理解调用链、条件分支、状态机和数据结构,用我们自己的语言写成**行为对照记录**(也就是 `docs/porting/*.md`) | 把 `.py`、`.yaml` 文件或者大段代码原样放进仓库,包括放进注释或测试 fixture |
| 用本机上游解释器**运行**上游代码,只为得到行为输出,作为 parity 期望值(脚本放在仓库外,或放在 `packages/testkit/scripts/` 并标注"可选、需要本机 MP") | 让 CI 依赖上游代码;把上游模块作为运行时依赖;通过子进程调用 MP |
| 按对照记录**独立**编写 TS 实现,命名、结构和类型遵循本项目约定 | 逐行机械翻译(包括让 AI 逐行改写)后当作原创。REQ §14.2:跨语言翻译或 AI 改写不会自动让移植成为没有来源的独立原创 |
| 引用事实性常量:协议字段名(qB WebUI API、M-Team API、TMDB API)、站点公开的 HTML 结构、行业通用词表(`WEB-DL`、`REMUX`、`DDP5.1`) | 照搬上游**整理过的数据表**:`RELEASE_GROUPS` 站点到组名的正则表(`app/domain/meta/releasegroup.py:26`)、`StreamingPlatforms` 平台码表(`app/domain/meta/streamingplatform.py`,约 270 条)、`_name_nostring_re` 干扰词表。这类表要**自行编制**,并在 ledger 里写明来源(例如公开的 scene/P2P 命名规范、站点官方规则页) |
| 上游测试里的**标题字符串**(事实数据)可以作为输入语料 | 整份拷贝 `tests/cases/meta.py` 这类测试文件;期望值必须由我们自己按 REQ 判定,不是照抄上游的 target |
| MovieClaw:阅读 YAML 的**字段结构**,参考其字段设计 | 在没有书面授权时拷贝 MovieClaw main 的配置或代码(附条件许可);把 main 的内容当作 MIT 使用 |
| MovieClaw **tag `v0.27.0`(`c79bb1b0`,MIT)** 的资产可以原样复制或转换(`kind=copied-mit`),前提是保留 MIT 全文与 `Copyright (c) 2026 MovieClaw`(`packages/adapters/src/sites/definitions/NOTICE-MovieClaw.md`),每个产物写明来源提交与路径(站点定义 JSON 的 `provenance` 字段),且只经 `git show v0.27.0:<path>` 读取(用户 2026-09-27 确认,依据 `movieclaw-assessment.md` §1) | 复制 `v0.27.0` 之后(`251f1988` 起附条件许可)的任何内容;复制 MC 仓库内自带独立许可的第三方子组件(`skill-creator` Apache-2.0、`liquid-glass`)而不遵守其各自许可 |
**对每个 PR 的要求**:只要实现参考了上游,PR 描述里就必须写"参考:`docs/porting/<文件>#<节>`",并在 §3 ledger 里补一行,登记状态为 `behavior-ref`。只有真的复制了代码或数据时,才登记为 `copied`;按目前的边界,**不应出现 `copied`**。例外是 `copied-mit`:复制 MIT 许可的资产(目前仅 MovieClaw v0.27.0),必须 `notice_required=是` 并附 NOTICE。
### 2.1 分发时的注意事项(首期不分发,先写在这里)
- 本项目用于内部部署(REQ §1.1.1)。内部使用不是忽略上游条款的理由(REQ §14.2)。
- 如果以后出现 `copied` 条目:MP 来源的部分会让整个分发物受 GPLv3 约束(需要同许可、提供源码、保留声明);MovieClaw main 来源的部分需要书面授权。发现这种情况要**先移除,再讨论**。
- Docker 镜像不得包含 MP 或 MovieClaw 的任何文件,也不得在构建时下载 `MoviePilot-Resources`。
---
## 3. Component ledger
### 3.1 字段模板
| 字段 | 说明 |
| --- | --- |
| `id` | `CL-<序号>` |
| `our_module` | 本项目的文件或函数,例如 `packages/domain/src/title/parse.ts#parseReleaseTitle` |
| `kind` | `behavior-ref`(只参考行为)/ `data-ref`(参考了数据结构,内容自行编制)/ `copied`(复制,原则上禁止)/ `copied-mit`(复制 MIT 资产,须保留 NOTICE,见 §2)/ `dependency`(npm 依赖) |
| `upstream` | 仓库 URL |
| `commit_or_version` | 精确提交或 tag,不能写 `main` |
| `upstream_paths` | 文件:函数:行号 |
| `license` | 上游在该提交下的许可 |
| `porting_doc` | `docs/porting/*.md#节` |
| `modifications` | 和上游行为的差异摘要,要引用对照文档里的"调整项" |
| `notice_required` | 是 / 否(`copied` 或 MIT/Apache 依赖要保留版权声明) |
| `distribution` | internal-only / image / source |
| `reviewer`、`date` | 登记人和日期 |
### 3.2 初始登记(W0-C)
| id | our_module(建议) | kind | upstream | commit | upstream_paths | license | porting_doc | modifications | notice | distribution |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| CL-001 | `packages/domain/src/title/parse.ts` | behavior-ref | MoviePilot | e6820a8 | `app/domain/metainfo.py:495,533`;`app/domain/meta/metavideo.py:163-874`;`app/domain/meta/metabase.py:244-431,719` | GPL-3.0 | metadata-recognition §2-§3 | 新增 airDate、issue、cut、packHint、未知发布组兜底;调整了 merge 条件 | 否 | internal-only |
| CL-002 | `packages/domain/src/title/custom-words.ts`、`episode-format.ts` | behavior-ref | MoviePilot | e6820a8 | `app/domain/meta/words.py:54-221`;`app/application/formatting.py:84-230` | GPL-3.0 | metadata-recognition §4 | 禁用 eval,规则版本化,偏移范围收窄 | 否 | internal-only |
| CL-003 | `packages/domain/src/title/release-groups.ts` | data-ref | MoviePilot | e6820a8 | `app/domain/meta/releasegroup.py:26,117,127` | GPL-3.0 | metadata-recognition §5 | 只参考"站点到组名"的结构和界定符语义,组名表自行编制 | 否 | internal-only |
| CL-004 | `packages/domain/src/identity/tmdb-match.ts`、`packages/adapters/src/tmdb/*` | behavior-ref | MoviePilot | e6820a8 | `app/modules/themoviedb/__init__.py:190-930`;`app/modules/themoviedb/tmdbapi.py:130-770,961-1045`;`cache.py:143-265` | GPL-3.0 | metadata-recognition §7-§8 | 候选打分,人工锁定,缓存放 PG | 否 | internal-only |
| CL-005 | `packages/adapters/src/nfo/writer.ts`、`packages/tasks/src/refresh-metadata.ts` | behavior-ref | MoviePilot | e6820a8 | `app/chain/scraping.py:148-395`;`app/modules/themoviedb/scraper.py:35-420` | GPL-3.0 | metadata-recognition §10 | 刮削改为独立任务;uniqueid 里写本地 UUID | 否 | internal-only |
| CL-006 | `packages/domain/src/organize/*`、`packages/adapters/src/fs/*`、`packages/tasks/src/verify-and-import.ts` | behavior-ref | MoviePilot | e6820a8 | 见 `moviepilot-transfer.md` §2 各表 | GPL-3.0 | transfer §2-§4 | 见 transfer §3 的必须偏离表 | 否 | internal-only |
| CL-007 | `packages/adapters/src/qbittorrent/*` | behavior-ref | MoviePilot | e6820a8 | `app/modules/qbittorrent/__init__.py`、`qbittorrent.py`(行号见 downloader-and-sites 文档) | GPL-3.0 | downloader-and-sites §qB | 标签接管,删数据前做引用检查 | 否 | internal-only |
| CL-008 | `packages/adapters/src/sites/nexusphp/*` | behavior-ref | MoviePilot | e6820a8 | `app/modules/indexer/spider/*`、`app/modules/indexer/parser/nexus_php.py`、`nexus_audiences.py` | GPL-3.0 | downloader-and-sites §站点 | 站点定义自行编制;不使用闭源 SitesHelper | 否 | internal-only |
| CL-009(retired → CL-012) | `packages/adapters/src/sites/nexusphp/configs/audiences.ts` | data-ref | MovieClaw | fc9eb72 | `src/movieclaw_tracker/sites/configs/audiences.yaml` | MovieClaw License(Apache-2.0 加非商业条件) | downloader-and-sites §MovieClaw | **只参考字段结构**;选择器值以我们自己抓取的观众页面为准重新编写 | 否(未复制) | internal-only |
| CL-010(retired → CL-013) | `packages/adapters/src/sites/mteam/*` | behavior-ref + data-ref | MovieClaw + MoviePilot | fc9eb72 / e6820a8 | MC:`sites/configs/mteam.yaml`、`sites/custom/mteam.py`;MP:`app/modules/indexer/parser/mtorrent.py` | MC 附条件 / GPL-3.0 | downloader-and-sites §M-Team | API 字段以 M-Team 公开 API 为准,按 API Key 模式实现 | 否 | internal-only |
| CL-011 | `packages/testkit/fixtures/title-parity.json` | data-ref | MoviePilot | e6820a8 | 输入语料参考 `tests/cases/meta.py`;**期望值自行判定** | GPL-3.0(原测试文件) | metadata-recognition §9 | 只取标题字符串,必要时脱敏 | 否 | internal-only |
| CL-012 | `packages/adapters/src/sites/definitions/*.json`(23 站)、`definitions/manifest.generated.ts`、`spider/mc-selector.ts`、`scripts/mp-sync/movieclaw-import.mjs` | copied-mit | MovieClaw | **v0.27.0**(`c79bb1b0`) | `src/movieclaw_tracker/sites/configs/*.yaml`;`selectors.py` `NexusPHPSelectors` 默认值;`frameworks/nexusphp.py` `_css_text` | MIT | downloader-and-sites §W1-3c | YAML 转为 MP indexer schema + `umt`;观众/馒头/HHClub/CHD 由 `scripts/mp-sync/movieclaw-overrides/*.json` 覆盖;除 4 主力站外 `enabled:false` | 是(`definitions/NOTICE-MovieClaw.md`) | internal-only |
| CL-013 | `packages/adapters/src/sites/mteam/*` | behavior-ref + copied-mit | MovieClaw + MoviePilot | **v0.27.0**(`c79bb1b0`)/ e6820a8 | MC:`sites/configs/mteam.yaml`(→ `definitions/mteam.json`)、`sites/custom/mteam.py`(字段对照);MP:`app/modules/indexer/spider/mtorrent.py`、`parser/mtorrent.py` | MIT / GPL-3.0 | downloader-and-sites §M-Team | 定义由 MC 转换 + W1-3b 值覆盖;API 行为按 MP | 是(MC 部分) | internal-only |
> 新增 npm 依赖(例如 anitopy 的等价实现、`re2`、`fast-xml-parser`)按 `kind=dependency` 登记,填锁定版本和 SPDX。
### 3.3 ledger 的维护规则
1. ledger 以本文件 §3.2 为唯一登记处,按 id 追加,不删除旧行;撤销时把行标记为 `retired`。
2. 上游提交升级时,**新增一行**,写新的提交号,不覆盖旧行。对照文档里的行号也要按新提交重新核对。
3. `copied` 行出现时,CI 必须失败。建议在 `scripts/` 里加一个检查:ledger 中 `kind=copied` 的行数必须为 0。`copied-mit` 不在此列,但必须有 NOTICE 文件且 `notice=是`。
4. 审核人检查三件事:PR 里有没有"参考:"链接;ledger 有没有对应行;diff 中有没有大段和上游高度相似的代码(可以用 `jscpd` 这类工具,把上游目录作为外部语料做一次抽样检查)。
---
## 4. 待办与未决
| 项 | 状态 |
| --- | --- |
| REQ 附录快照 `33da9ce` 和本地 `e6820a8` 的差异 | 未比对,本地没有该对象。需要时 `git fetch --depth=1 origin 33da9ce...` 再比对(需要网络) |
| MovieClaw 是否有可用的 `≤v0.27.0` MIT tag,以及 tag 内的文件许可 | 未核对。只有在决定复用 MovieClaw 历史代码时才需要做 |
| `tmdbv3api` 内嵌副本的来源和许可 | 未核实;本项目不使用它 |
| 对外分发 | 首期不做;如果要做,先完成法律审查 |