跳转到内容

模块

进阶

选出你的改动该放的模块,并弄清它可以调用哪些模块。

  • 先读架构,了解文件夹地图和规则。
  • 每个模块在 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、赞助它或请我喝杯咖啡。