Files
SaveAny-Bot/.github/copilot-instructions.md
krau 9ed2c425be feat(i18n): Enhance internationalization support and error handling messages
- Added i18n keys for various error and info messages related to task management, user handling, and storage operations.
- Updated error messages in the watch and task handling commands to use i18n for better localization.
- Refactored error handling in the database initialization and user synchronization processes to provide clearer messages.
- Improved logging messages for better clarity and consistency across the application.
- Added comprehensive documentation for AI collaboration and project structure in the repository.
2025-12-19 16:01:36 +08:00

7.1 KiB
Raw Blame History

SaveAny-Bot AI 协作说明

本项目是一个将 Telegram 文件/消息转存到多种存储端的 Bot主要用 Go 实现CLI 入口在 cmd/,核心逻辑分布在 client/core/config/database/storage/ 等目录。下面是针对本仓库的专用约定,供 AI 编码助手参考。

总体架构与入口

  • CLI 入口
    • 二进制入口:main.go 调用 cmd.Execute(ctx)
    • 根命令:cmd/root.go 使用 cobra 定义 saveany-botRun 实现在 cmd/run.go
  • 应用启动流程(非常重要)
    • cmd/run.go::Run 中按顺序完成:读取配置 config.Init → 初始化缓存 common/cache → 初始化 i18n common/i18n → 初始化数据库 database.Init → 加载存储 storage.LoadStorages → 加载解析器插件 parsers.LoadPlugins可选Userbot 登录 → 启动 Telegram Bot client/bot.Init → 启动核心任务队列消费 core.Run
    • 添加新的初始化步骤时,请遵循该顺序并放在 initAll 中,而不是分散在各处。

配置与约定

  • 配置系统
    • 使用 viper 读取 config.toml,核心结构体定义在 config/viper.go::Config
    • 默认值在 config.Init 中通过 viper.SetDefault 定义,如 workersretrytelegram.*db.* 等。
    • Config.C() 返回的是全局配置副本(值类型),不要在返回值上修改字段;如果需要修改配置流程,应在 config.Init 内或通过 viper 进行。
    • 存储配置通过 config/storage/factory.go::LoadStorageConfigs 加载并校验,新增存储类型需:
      • pkg/enums/storage 中增加枚举。
      • config/storage/ 下新增具体 StorageConfig 实现并实现 Validate
      • storageFactories 映射中注册工厂方法。
  • 环境变量
    • 所有配置键会被 SAVEANY_ 前缀的环境变量覆盖,. 会被 _ 替换(SAVEANY_TELEGRAM_APP_ID 等)。

Telegram 客户端与中间件

  • Bot 客户端
    • 入口在 client/bot/bot.go::Init,使用 gotgproto.NewClient 创建Session 使用 database.GetDialect(config.C().DB.Session),错误处理通过 ErrorHandler 回调完成。
    • Handlers 注册集中在 client/bot/handlers 目录,handlers.Register 负责统一挂载;新增命令/消息处理逻辑时优先在该目录按功能拆分文件,实现后在 handlers.Register 中注册。
    • Bot 命令列表依赖 handlers.CommandHandlers 来自动注册到 Telegram新增命令时务必更新该切片以保持 /help 与 Bot 命令列表一致。
  • 中间件
    • 通用中间件位于 client/middleware/,包含 floodwait、防崩溃、重试等middleware.NewDefaultMiddlewaresclient/bot/bot.go 中统一挂载。
    • 新增跨所有更新生效的行为(如日志、统计)时,应优先实现为中间件。

核心任务与队列

  • 任务接口与队列
    • 核心接口:core/core.go::Executable,包含 Type() TaskTypeTitle()TaskID()Execute(ctx)
    • 任务队列:pkg/queue.TaskQueue[Executable],由 core.Run 使用;Workers 数量来自配置 config.C().Workers
    • 任务类型与实现示例位于 core/tasks/**例如文件任务、Telegraph 任务等;新增任务类型应放在对应子目录并实现 Executable 接口,然后通过 core.AddTask 入队。
  • 生命周期 Hook
    • core.worker 在执行任务前后会根据 config.C().Hook.Exec 调用外部命令(TaskBeforeStart / TaskSuccess / TaskFail / TaskCancel)。
    • 修改任务执行流程时需保留这些 Hook 调用,以免破坏用户已有集成。

数据库与持久化

  • 数据库初始化
    • database.Init 使用配置 config.C().DB.Path 创建并连接 SQLite使用 GetDialect 抽象驱动(见 database/driver_*.go)。
    • Migration 通过 db.AutoMigrate(&User{}, &Dir{}, &Rule{}, &WatchChat{}) 完成,模型定义在 database/*.go 中。
  • 用户同步约定
    • database.syncUsers 会根据 config.C().Users 同步数据库用户表:在配置中新增/删除用户会自动在 DB 中创建/删除对应记录。
    • 开发涉及用户表逻辑时,请考虑该同步行为,避免在其他地方直接创建/删除用户记录而与配置冲突。

存储后端

  • 存储抽象
    • 抽象接口在 config/storage/types.gostorage/ 顶层(以及子目录)中;config/storage/*.go 处理配置解析,storage/* 处理真正的上传/下载实现。
    • 现有实现包括 localalists3/miniowebdavtelegram 等,每个后端都有对应子目录和配置结构体。
  • 新增存储实现的推荐路径
    • config/storage/ 下添加配置结构体 + Validate
    • storage/ 下添加具体实现(例如 storage/foo/)。
    • pkg/enums/storagestorageFactories 中注册,并确保 storages 配置示例被更新(config.example.toml / 文档)。

解析器插件JS

  • 插件运行时
    • 解析器接口和插件文档在 plugins/README.mdGo 端入口为 parsers/ 目录,使用 gojaplaywright-go
    • 插件通过 registerParser({ metadata, canHandle, parse }) 注册,使用 ghttp/playwright 进行 HTTP/浏览器请求。
  • 与核心交互约定
    • 插件 parse 返回的 Item/Resource 会被转化为内部任务(通常是下载/转存任务)并进入 core 队列。
    • 修改 Item/Resource 结构或解析逻辑时,要确保保持向后兼容,或在 plugins/README.md 中同步更新字段说明和示例。

i18n 与日志

  • 国际化
    • 所有用户可见字符串(尤其是错误与提示)应使用 common/i18ni18n.T(i18nk.SomeKey, map[string]any{"Name": name})
    • 语言文件位于 common/i18n/locale/go:generate 指令在 main.go 中生成 i18nk/keys.go;新增文案时需:添加到 YAML、运行 go generate ./...、再在代码中引用新 key。
  • 日志
    • 使用 github.com/charmbracelet/log,在 cmd/run.go::Run 中通过 log.WithContext 将 logger 注入 context.Context;后续代码优先通过 log.FromContext(ctx) 获取 logger。
    • 编写新代码时,如已有 ctx,请使用 log.FromContext(ctx) 而不是全局 logger。

开发与运行

  • 本地运行
    • 直接运行:go run ./cmdcmd/root.go + cmd/run.go)。
    • 或通过 Docker参见根目录 README.md 中的 docker run ... 示例及 docker-compose.yml
  • 代码生成与文档
    • i18n key 生成:go generate ./... 会执行 main.go 顶部的 //go:generate,使用 cmd/geni18n/main.go 生成 common/i18n/i18nk/keys.go
    • 文档站点在 docs/Hugo通常不需要在核心代码改动时同步修改除非涉及文档内容。

如果你在实现某个功能时发现以上规则不够具体(例如某类任务在 core/tasks 中到底如何落地,或某个存储/解析器的边界不清晰),请在对应章节下扩展更精确的说明,并在 PR 描述中标注。也欢迎你告诉我有哪些部分需要补充或澄清,我可以进一步细化。