diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 3dff2c1..68ae5c5 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -164,3 +164,5 @@ func sseHandler(svc *service.Container) gin.HandlerFunc { } + + diff --git a/internal/handler/routes_authenticated.go b/internal/handler/routes_authenticated.go index 7fd2d28..31dd39e 100644 --- a/internal/handler/routes_authenticated.go +++ b/internal/handler/routes_authenticated.go @@ -112,8 +112,7 @@ func registerAuthenticatedRoutes(api *gin.RouterGroup, cfg *config.Config, svc * authed.DELETE("/files", middleware.AdminRequired(), deleteFileHandler(svc)) authed.POST("/files/transfer", middleware.AdminRequired(), transferFileHandler(svc)) - // Disk usage breakdown. - authed.GET("/storage", middleware.AdminRequired(), storageHandler(svc)) +// // Disk usage breakdown. // DLNA discovery + cast. authed.GET("/dlna/devices", dlnaListHandler(svc)) diff --git a/internal/handler/storage.go b/internal/handler/storage.go deleted file mode 100644 index b9a6e12..0000000 --- a/internal/handler/storage.go +++ /dev/null @@ -1,21 +0,0 @@ -// Package handler — disk usage breakdown for the Storage tab. -package handler - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/ShukeBta/MediaStationGo/internal/service" -) - -func storageHandler(svc *service.Container) gin.HandlerFunc { - return func(c *gin.Context) { - bd, err := svc.Storage.Compute(c.Request.Context()) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - c.JSON(http.StatusOK, bd) - } -} diff --git a/internal/repository/storage_config_repo.go b/internal/repository/storage_config_repo.go index fd2d1af..173af9f 100644 --- a/internal/repository/storage_config_repo.go +++ b/internal/repository/storage_config_repo.go @@ -65,3 +65,19 @@ func (r *StorageConfigRepository) Upsert(ctx context.Context, c *model.StorageCo "updated_at": time.Now(), }).Error } + + +// Delete removes a storage config by ID. +func (r *StorageConfigRepository) Delete(ctx context.Context, id string) error { + return r.db.WithContext(ctx).Where("id = ?", id).Delete(&model.StorageConfig{}).Error +} + +// FindByID returns a storage config by ID. +func (r *StorageConfigRepository) FindByID(ctx context.Context, id string) (*model.StorageConfig, error) { + var c model.StorageConfig + err := r.db.WithContext(ctx).Where("id = ?", id).First(&c).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } + return &c, err +} diff --git a/internal/service/scanner.go b/internal/service/scanner.go index 9b49cde..351b8ff 100644 --- a/internal/service/scanner.go +++ b/internal/service/scanner.go @@ -697,6 +697,15 @@ func (s *ScannerService) scanCloudLibrary(ctx context.Context, lib *model.Librar if s.storage == nil { return res, fmt.Errorf("cloud storage service unavailable") } + + // 验证存储配置是否存在且已启用 + cfg, err := s.repo.StorageConfig.FindByID(ctx, mount.Provider) + if err != nil || cfg == nil { + return res, fmt.Errorf("storage config not found: %s", mount.Provider) + } + if !cfg.Enabled { + return res, fmt.Errorf("storage %s is disabled", mount.Provider) + } typ := mount.Provider rootDir := mount.ScanDir rootDisplayDir := mount.DisplayDir @@ -1428,3 +1437,5 @@ func (s *ScannerService) maybeGenerateSTRMAfterScan(libraryID string) { } }() } + + diff --git a/internal/service/service.go b/internal/service/service.go index 8ed96ee..72ae270 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -340,3 +340,6 @@ var _ = time.Now + + + diff --git a/internal/service/storage_config.go b/internal/service/storage_config.go index 2e9f230..17ec640 100644 --- a/internal/service/storage_config.go +++ b/internal/service/storage_config.go @@ -495,3 +495,52 @@ func strr(v any) string { } return strings.TrimSpace(fmt.Sprint(v)) } + + +// DeleteStorage 删除存储配置并清理关联数据 +func (s *StorageConfigService) DeleteStorage(ctx context.Context, storageType string) error { + // 查找配置 + cfg, err := s.repo.StorageConfig.Get(ctx, storageType) + if err != nil || cfg == nil { + return fmt.Errorf("storage config not found: %s", storageType) + } + + // 查找使用该存储的云盘库 + libs, err := s.repo.Library.List(ctx) + if err != nil { + return fmt.Errorf("list libraries: %w", err) + } + + var affectedLibs []string + for _, lib := range libs { + // 检查是否是云盘库且Provider匹配 + if mount, ok := ParseCloudLibraryMount(lib.Path); ok && mount.Provider == storageType { + affectedLibs = append(affectedLibs, lib.ID) + } + } + + // 删除关联媒体 + for _, libID := range affectedLibs { + if err := s.repo.Media.PurgeByLibrary(ctx, libID); err != nil { + s.log.Warn("purge media by library failed", zap.String("library_id", libID), zap.Error(err)) + } + } + + // 删除关联库 + for _, libID := range affectedLibs { + if err := s.repo.Library.Delete(ctx, libID); err != nil { + s.log.Warn("delete library failed", zap.String("library_id", libID), zap.Error(err)) + } + } + + // 删除存储配置 + if err := s.repo.StorageConfig.Delete(ctx, cfg.ID); err != nil { + return fmt.Errorf("delete storage config: %w", err) + } + + s.log.Info("storage deleted", + zap.String("storage_type", storageType), + zap.Int("libraries_deleted", len(affectedLibs))) + + return nil +}