From 28551c78834f6917d9545f3a4f97ae6976c953c6 Mon Sep 17 00:00:00 2001 From: truewhile <62226914+truewhile@users.noreply.github.com> Date: Sat, 5 Sep 2026 18:08:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=85=E7=90=86qBittorrent=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E6=AE=8B=E7=95=99=EF=BC=9A=E5=88=A0=E9=99=A4=E6=AD=BBschema?= =?UTF-8?q?=E5=88=86=E7=BB=84=E4=B8=8E=E5=89=8D=E7=AB=AF=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=EF=BC=8C=E4=B8=8B=E8=BD=BD=E5=99=A8=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E7=9B=AE=E5=BD=95=E9=94=AE=E6=94=B9=E4=B8=BAdownloade?= =?UTF-8?q?r.savepath=E5=B9=B6=E5=85=BC=E5=AE=B9=E6=97=A7=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.search.yml | 2 +- docker-compose.simple.yml | 2 +- docker-compose.standard.yml | 2 +- docker-compose.yml | 2 +- internal/handler/system_extra.go | 10 ---- internal/service/crypto.go | 2 +- internal/service/filemanager_roots.go | 6 +- internal/service/filemanager_test.go | 7 ++- internal/service/media_test.go | 2 +- .../service/organizer_directory_sources.go | 15 ++++- internal/service/organizer_settings.go | 2 +- internal/service/path_translation.go | 2 +- internal/service/proxy.go | 2 +- internal/service/transfer.go | 2 +- web/src/types/downloads.ts | 60 ------------------- web/src/types/index.ts | 1 - 16 files changed, 31 insertions(+), 88 deletions(-) delete mode 100644 web/src/types/downloads.ts diff --git a/docker-compose.search.yml b/docker-compose.search.yml index 0453233..7aa8e4d 100644 --- a/docker-compose.search.yml +++ b/docker-compose.search.yml @@ -55,7 +55,7 @@ services: bind: create_host_path: false - # 下载目录。需要和 qBittorrent 保存路径保持一致。 + # 下载目录。需要和下载器保存路径保持一致。 # NAS 示例:source: /vol1/1000/Downloads # Windows Docker Desktop 示例:source: D:/Downloads - type: bind diff --git a/docker-compose.simple.yml b/docker-compose.simple.yml index 47d675d..9f9cad9 100644 --- a/docker-compose.simple.yml +++ b/docker-compose.simple.yml @@ -69,7 +69,7 @@ services: MEBOX_LOGGING_MAX_AGE_DAYS: "30" extra_hosts: - # 容器访问宿主机服务用,例如 qBittorrent: http://host.docker.internal:8085 + # 容器访问宿主机服务(如下载器等)用: http://host.docker.internal:8085 - "host.docker.internal:host-gateway" healthcheck: diff --git a/docker-compose.standard.yml b/docker-compose.standard.yml index 0eba48f..e699393 100644 --- a/docker-compose.standard.yml +++ b/docker-compose.standard.yml @@ -50,7 +50,7 @@ services: bind: create_host_path: false - # 下载目录。需要和 qBittorrent 保存路径保持一致。 + # 下载目录。需要和下载器保存路径保持一致。 # NAS 示例:source: /vol1/1000/Downloads # Windows Docker Desktop 示例:source: D:/Downloads - type: bind diff --git a/docker-compose.yml b/docker-compose.yml index b2d0c83..ae0b029 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,7 +29,7 @@ services: ports: - "18080:8080" - # 让容器可以访问宿主机上的 qBittorrent。 + # 让容器可以访问宿主机上的服务(如下载器)。 # qB 地址通常可填:http://host.docker.internal:8085 extra_hosts: - "host.docker.internal:host-gateway" diff --git a/internal/handler/system_extra.go b/internal/handler/system_extra.go index aac77f1..e2ed66d 100644 --- a/internal/handler/system_extra.go +++ b/internal/handler/system_extra.go @@ -116,16 +116,6 @@ func schemaHandler(_ *service.Container) gin.HandlerFunc { {"key": "adult.pin", "type": "text"}, }, }, - { - "key": "qbittorrent", - "label": "qBittorrent", - "items": []gin.H{ - {"key": "qbittorrent.url", "type": "text"}, - {"key": "qbittorrent.username", "type": "text"}, - {"key": "qbittorrent.password", "type": "text"}, - {"key": "qbittorrent.savepath", "type": "text"}, - }, - }, { "key": "system-update", "label": "系统更新", diff --git a/internal/service/crypto.go b/internal/service/crypto.go index 1269186..c03fc7a 100644 --- a/internal/service/crypto.go +++ b/internal/service/crypto.go @@ -1,6 +1,6 @@ // Package service — AES-GCM crypto helper for at-rest secrets. // -// Sensitive fields (third-party API keys, qBittorrent passwords, …) are +// Sensitive fields (third-party API keys, service passwords, …) are // stored in SQLite. We encrypt them with AES-256-GCM keyed off the JWT // secret so a stolen DB file alone is not enough to recover the // plaintext credentials. diff --git a/internal/service/filemanager_roots.go b/internal/service/filemanager_roots.go index 8573892..eedc553 100644 --- a/internal/service/filemanager_roots.go +++ b/internal/service/filemanager_roots.go @@ -77,7 +77,11 @@ func (s *FileManagerService) allowedRoots() (map[string]string, error) { } addSetting("organize-source", "organize.source_dir") addSetting("organize-target", "organize.target_dir") - addSetting("qb-savepath", "qbittorrent.savepath") + addSetting("downloader-savepath", "downloader.savepath") + // 兼容历史键名 qbittorrent.savepath:旧版本把下载器保存目录存在该键下 + if value, err := s.repo.Setting.Get(context.Background(), "downloader.savepath"); err != nil || strings.TrimSpace(value) == "" { + addSetting("downloader-savepath", "qbittorrent.savepath") + } } if s.repo != nil && s.repo.Library != nil { libs, err := s.repo.Library.List(context.Background()) diff --git a/internal/service/filemanager_test.go b/internal/service/filemanager_test.go index 0963532..471ddb6 100644 --- a/internal/service/filemanager_test.go +++ b/internal/service/filemanager_test.go @@ -196,9 +196,10 @@ func TestFileManagerIncludesConfiguredOrganizeRoots(t *testing.T) { got[root.Label] = root.Path } for label, want := range map[string]string{ - "organize-source": filepath.Clean(sourceDir), - "organize-target": filepath.Clean(targetDir), - "qb-savepath": filepath.Clean(qbDir), + "organize-source": filepath.Clean(sourceDir), + "organize-target": filepath.Clean(targetDir), + // 旧键 qbittorrent.savepath 写入应经兼容回退落在 downloader-savepath 下 + "downloader-savepath": filepath.Clean(qbDir), } { if got[label] != want { t.Fatalf("root %s = %q, want %q; roots=%#v", label, got[label], want, listing.Roots) diff --git a/internal/service/media_test.go b/internal/service/media_test.go index e504591..d240d30 100644 --- a/internal/service/media_test.go +++ b/internal/service/media_test.go @@ -136,7 +136,7 @@ func TestResolveAccessibleMappedPathMapsEmbeddedHostDownloadMarker(t *testing.T) } t.Setenv("MEBOX_DOWNLOAD_CONTAINER_DIR", containerDownloads) - got, _, err := resolveAccessibleMappedPath("/vol1/1000/Docker/qbittorrent/downloads/国产剧") + got, _, err := resolveAccessibleMappedPath("/vol1/1000/nas/downloads/国产剧") if err != nil { t.Fatalf("resolveAccessibleMappedPath() error = %v", err) } diff --git a/internal/service/organizer_directory_sources.go b/internal/service/organizer_directory_sources.go index cbbd596..77a167a 100644 --- a/internal/service/organizer_directory_sources.go +++ b/internal/service/organizer_directory_sources.go @@ -40,7 +40,7 @@ func (o *OrganizerService) OrganizeSourceCandidates(ctx context.Context) []Organ out = append(out, OrganizeSourceCandidate{Label: label, Path: clean, Kind: kind}) } add("默认整理源", o.settingValue(ctx, "organize.source_dir"), "source") - add("下载器保存目录", o.settingValue(ctx, "qbittorrent.savepath"), "download") + add("下载器保存目录", o.downloaderSavepath(ctx), "download") add("下载目录", envOrDefault("MEBOX_DOWNLOAD_CONTAINER_DIR", "/downloads"), "download") add("媒体目录", envOrDefault("MEBOX_MEDIA_CONTAINER_DIR", "/media"), "media") return out @@ -56,8 +56,17 @@ func (o *OrganizerService) settingValue(ctx context.Context, key string) string return "" } +// downloaderSavepath 返回下载器保存目录,优先新键 downloader.savepath, +// 兼容历史键名 qbittorrent.savepath(旧版本部署已写入的配置不丢失)。 +func (o *OrganizerService) downloaderSavepath(ctx context.Context) string { + if v := o.settingValue(ctx, "downloader.savepath"); v != "" { + return v + } + return o.settingValue(ctx, "qbittorrent.savepath") +} + // defaultSourceRoot resolves the source root for a directory organize: -// explicit override → organize.source_dir setting → qB default save path → +// explicit override → organize.source_dir setting → downloader save path → // download container dir. func (o *OrganizerService) defaultSourceRoot(ctx context.Context, override string) string { if r := strings.TrimSpace(override); r != "" { @@ -66,7 +75,7 @@ func (o *OrganizerService) defaultSourceRoot(ctx context.Context, override strin if v := o.settingValue(ctx, "organize.source_dir"); v != "" { return v } - if v := o.settingValue(ctx, "qbittorrent.savepath"); v != "" { + if v := o.downloaderSavepath(ctx); v != "" { return v } return envOrDefault("MEBOX_DOWNLOAD_CONTAINER_DIR", "/downloads") diff --git a/internal/service/organizer_settings.go b/internal/service/organizer_settings.go index e576494..1031239 100644 --- a/internal/service/organizer_settings.go +++ b/internal/service/organizer_settings.go @@ -54,7 +54,7 @@ func (o *OrganizerService) resolveTransferMode(ctx context.Context, override Tra } } if mode == TransferMove && o.keepSeedingEnabled(ctx) { - // 移动会删除源文件导致 qBittorrent 停止做种;保种开启时改用硬链接 + // 移动会删除源文件导致下载器停止做种;保种开启时改用硬链接 // 既规范命名又保留源文件继续做种上传。硬链接失败时会报错,避免静默 // 退化复制后占用双份磁盘空间。 return TransferHardlink diff --git a/internal/service/path_translation.go b/internal/service/path_translation.go index 60d35c3..86a24ab 100644 --- a/internal/service/path_translation.go +++ b/internal/service/path_translation.go @@ -7,7 +7,7 @@ import ( ) // translateClientPath 将下载客户端报告的路径转换为容器内可访问的路径。 -// 常见场景:qBittorrent在另一个容器,报告的路径是其容器内路径,需要映射到当前容器。 +// 常见场景:下载器在另一个容器,报告的路径是其容器内路径,需要映射到当前容器。 func translateClientPath(clientPath string, mappings map[string]string) string { if clientPath == "" { return "" diff --git a/internal/service/proxy.go b/internal/service/proxy.go index 15e45f9..866ecc7 100644 --- a/internal/service/proxy.go +++ b/internal/service/proxy.go @@ -27,7 +27,7 @@ func NewExternalHTTPClient(timeout time.Duration) *http.Client { } // NewInternalHTTPClient builds an HTTP client for LAN / Docker-internal -// services such as qBittorrent, Transmission and Aria2. These endpoints are +// services such as downloaders and other local tools. These endpoints are // usually 127.0.0.1, host.docker.internal, 172.17.0.1 or a NAS LAN IP; sending // them through HTTP_PROXY/SOCKS proxies makes local WebUI logins hang or fail. func NewInternalHTTPClient(timeout time.Duration) *http.Client { diff --git a/internal/service/transfer.go b/internal/service/transfer.go index a89bbf4..fddd3a0 100644 --- a/internal/service/transfer.go +++ b/internal/service/transfer.go @@ -7,7 +7,7 @@ // hardlink 硬链接(同盘零额外占用,保留源文件;做种不受影响) // symlink 软链接(保留源文件,指向源) // -// 除 move 外,其余方式都保留源文件,因此 qBittorrent 等下载器仍能在原 +// 除 move 外,其余方式都保留源文件,因此下载器仍能在原 // 路径找到数据继续做种上传。 package service diff --git a/web/src/types/downloads.ts b/web/src/types/downloads.ts deleted file mode 100644 index 974447d..0000000 --- a/web/src/types/downloads.ts +++ /dev/null @@ -1,60 +0,0 @@ -export interface DownloadTask { - id: string - source: string - download_client_id?: string - external_id?: string - title: string - poster_url?: string - backdrop_url?: string - overview?: string - save_path: string - status: string - progress: number - state?: string - dlspeed?: number - upspeed?: number - num_seeds?: number - num_leechs?: number - size?: number - downloaded?: number - created_at: string - updated_at: string -} - -export interface QBitTorrent { - hash: string - client_id: string - source: 'qbittorrent' | 'transmission' | 'aria2' - name: string - title: string - poster_url?: string - backdrop_url?: string - overview?: string - state: string - progress: number - dlspeed: number - upspeed: number - num_seeds: number - num_leechs: number - size: number - downloaded: number - save_path: string -} - -export interface DownloadClient { - id: string - name: string - type: 'qbittorrent' | 'transmission' | 'aria2' - host: string - username: string - is_default: boolean - enabled: boolean - created_at: string - updated_at: string -} - -export interface DownloadClientTypeInfo { - type: string - name: string - description: string -} diff --git a/web/src/types/index.ts b/web/src/types/index.ts index d6b1d9f..abf1dab 100644 --- a/web/src/types/index.ts +++ b/web/src/types/index.ts @@ -2,7 +2,6 @@ export * from './api' export * from './auth' -export * from './downloads' export * from './events' export * from './history' export * from './library'