模块
进阶
选出你的改动该放的模块,并弄清它可以调用哪些模块。
开始之前
开始之前 的链接- 先读架构,了解文件夹地图和规则。
- 每个模块在
app/backend/internal/<module>/里用同一个名字;如果它有页面或浏览器测试,在app/frontend/src/lib/<module>/和app/tests/<module>/里也是这个名字。
找到正确的模块
找到正确的模块 的链接| 模块 | 负责 |
|---|---|
requests |
提交请求、批准、请求规则、外部列表、问题报告 |
movies |
电影条目、剪辑版、合集、搜索和整理 |
shows |
剧集、季、集、搜索和整理 |
music |
艺人、专辑、曲目、搜索和整理 |
sources |
来源、Jackett 和 Prowlarr 桥接、资源搜索 |
downloads |
下载器、队列、已见过的文件、路径映射、标签、复制方式的选择 |
subtitles |
字幕语言、字幕站、匹配和保存 |
discover |
探索、热门、搜索、人物、日历、条目页面 |
suggest |
挑选并排列各行和各栏内容(仅后端) |
mediafiles |
目录记录、挑选规则、命名、数据包、媒体详情 |
importer |
文件导入:解压、标签、匹配(仅后端) |
library |
媒体库文件夹、接管和重命名(仅后端) |
metadata |
外部数据客户端、音乐查询、分级阶梯、预告片 |
mediaservers |
让 Plex、Jellyfin 和 Emby 重新扫描 |
accounts |
用户、登录、单点登录、AI 应用登录、儿童限制、观看偏好 |
alerts |
通知渠道和它们什么时候发消息 |
migrate |
把旧应用的数据搬过来 |
arrapi |
Sonarr 和 Radarr 风格的 API |
ai |
AI 应用连接(暂未开放) |
backups |
创建、保留和恢复备份 |
health |
健康检查、doctor、支持包 |
updates |
更新检查和签名的更新列表 |
setup |
首次运行的设置向导 |
分层顺序
分层顺序 的链接一个模块只能导入更低的层。没有任何模块导入 discover。以 tools/structurecheck/allow.go 为准。
| 层 | 模块 |
|---|---|
| 0 | core |
| 1 | metadata, suggest |
| 2 | accounts |
| 3 | mediafiles |
| 4 | importer |
| 5 | library |
| 6 | sources |
| 7 | downloads |
| 8 | subtitles, mediaservers, alerts |
| 9 | movies, shows |
| 10 | requests, health |
| 11 | music, arrapi, migrate, ai, backups, updates, setup |
| 13 | discover |
如果你的模块需要更高层的东西,不要导入它。让高层模块把普通数据传下来,或者在低层模块里定义一个小接口,交给 wiring.go 填上。
添加路由或模块
添加路由或模块 的链接新路由
新路由 的链接在模块的 routes.go 里注册它,并带上权限。openapi.json 由路由生成,一旦对不上就有测试失败。已发布的路径和字段名保持不变。只加字段,绝不改名。然后用 go run ./app/backend/tools/apidoc 重新生成 API 路由。
新模块
新模块 的链接先试着把你的改动放进这 23 个模块里;要加新模块,先开一个 issue。一个新模块需要它的后端文件夹(有页面的话再加 lib/<module>/ 和 app/tests/<module>/)、在 tools/structurecheck 的分层顺序里占一个位置,以及 wiring.go 里的一行。
如果不成功
如果不成功 的链接现象。 TestModuleEdges 失败。
原因。 某个模块导入了同层或更高层的模块。
解决办法。 由高层模块把普通数据传下来,或者加一个在 wiring.go 里接好的小接口。
现象。 TestSQLOnlyInStore 或 TestTableOwnership 失败。
原因。 SQL 写在了 store*.go 文件之外,或者碰了别的模块的表。
解决办法。 把查询挪进表所属模块的 store,再按 ID 调用那个模块的服务。
进阶
进阶 的链接更多规则
- 一个模块只能导入另一个模块的根包。
- store 函数接收一个
database.Querier。读别的模块的行,要按 ID 通过它的服务来读;很长的 ID 列表用json_each(?)作为一个 JSON 数组传入。 settings、schedules、secrets、jobs和events归 core。每组设置只有一个所属模块。要改别的模块的那一组,就调用它的所属模块。- 每个对外调用都走
core/outbound。 - core 包按行排列,从上到下是:
parts,webserver和startup,logs,jobs和model,outbound和secrets,然后是database、files和releasename。一个 core 包只能导入同一行或更低的行。 - 命名:Go 文件用小写加下划线,Svelte 组件用 PascalCase,TypeScript、文档、测试和部署文件用 kebab-case。Python 文件用下划线,这样才能被导入。
app/里的文件夹用小写,只用一个词。 - 代码可以随意改名,但凡是存下来或发出去的东西都保留原名:表和列、设置键、JSON 字段、后台任务名和开关名。
- 注释里不带路线图编号、日期、人名或破折号。
记录归谁
| 所属 | 记录 |
|---|---|
mediafiles |
Title, Item, Version, Slot, Part, File, LibraryFolder, Quality, PickRules |
downloads |
Download, Downloader, SeenFile, PathMap |
sources |
Source, Release |
requests |
Ask, Report |
accounts |
User |
core/jobs |
Job, Schedule, JobError |
core/database |
Event 和共享的行字段 |
各项检查
这些检查放在 app/backend/tools/structurecheck 里。大多数需要 -tags structure。
| 检查 | 把关内容 |
|---|---|
TestTopLayout |
仓库顶层文件夹 |
TestModuleSet, TestCoreSet, TestPackageMap |
internal/ 和 internal/core/ 里允许有哪些文件夹 |
TestModuleEdges |
分层顺序 |
TestModuleImportsRootOnly |
只能导入根包 |
TestCoreImportsNoModule, TestCoreRowOrder, TestCoreNamesNoModuleTable |
core 的导入、行的顺序和命名 |
TestSQLOnlyInStore, TestTableOwnership, TestSQLAllowlistShrinks, TestSeedSQLAllowlist |
SQL 放在哪里、表归谁 |
TestGoFileNames, TestNoBannedPackageNames |
文件名和包名 |
TestFileSizeCap, TestCorePackageSize |
文件和 core 包的大小 |
TestCommentHygiene |
上面的注释规则 |
TestRouteTableUnchanged, TestMigrationsUnchanged, TestHeaderAndJSONLiteralsUnchanged |
挪动代码不会改变任何路由、迁移、HTTP 头名称或 JSON 键 |
TestNoOldPageAddresses, TestNoOldPagesInTestsOrDocs |
旧的页面地址不会再出现在代码、测试和文档里 |
TestNoDependencyBotConfig |
.github 里没有依赖机器人的文件 |
相关页面
相关页面 的链接HolyArrs 是免费的。如果它帮你省了时间,欢迎在 GitHub 上点个 Star、赞助它或请我喝杯咖啡。