Files
MeBox/internal/service/organizer_reclassify_cloud.go
T

187 lines
5.5 KiB
Go

package service
import (
"context"
"strings"
"go.uber.org/zap"
"github.com/ShukeBta/MediaStationGo/internal/model"
)
func (o *OrganizerService) reclassifyCloudScannedMedia(ctx context.Context, media model.Media, lib model.Library, mount CloudMountInfo, mediaTypeHint string, dryRun bool, res *OrganizeResult) (bool, error) {
mediaType := normalizeOrganizeMediaType(lib.Type)
if mediaTypeHint != "" {
mediaType = mediaTypeHint
}
metadataMatch := organizeMatchFromMedia(&media)
if metadataMatch != nil && mediaTypeHint != "" {
metadataMatch.MediaType = mediaTypeHint
}
if !mediaHasReliableCategoryMetadata(media) {
metadataMatch = o.lookupReclassifyMetadata(ctx, media, lib, mediaType)
if metadataMatch == nil {
return false, nil
}
media = mediaWithReclassifyMatch(media, metadataMatch)
}
if matchType := normalizeOrganizeMediaType(metadataMatchMediaType(metadataMatch)); matchType != "" {
mediaType = matchType
}
category := o.classifyMedia(ctx, &media, mediaType)
if category == "" {
return false, nil
}
if impliedType, normalizedCategory := o.mediaTypeForDirectoryCategory(category); impliedType != "" {
mediaType = reconcileOrganizeCategoryMediaType(mediaType, impliedType)
category = normalizedCategory
}
if mediaType == "" {
mediaType = normalizeOrganizeMediaType(lib.Type)
}
displayDir := o.cloudReclassifyCategoryDisplayDir(mediaType, category)
if displayDir == "" {
return false, nil
}
if normalizeCloudMountDir(mount.Provider, mount.DisplayDir) == normalizeCloudMountDir(mount.Provider, displayDir) {
return false, nil
}
targetLibrary, ok, err := o.ensureCloudReclassifyLibrary(ctx, mount.Provider, displayDir, mediaType, dryRun)
if err != nil || !ok {
return false, err
}
if strings.TrimSpace(targetLibrary.ID) != "" && targetLibrary.ID == lib.ID {
return false, nil
}
title := sanitizeFilename(strings.TrimSpace(media.Title))
if title == "" {
title = "Unknown"
}
res.Items = append(res.Items, OrganizePreviewItem{
Source: media.Path,
Target: targetLibrary.Path,
Action: "reclassify",
Reason: "cloud metadata category library changed",
MediaType: mediaType,
Category: category,
Title: title,
})
if dryRun {
res.Reclassified++
return true, nil
}
updates := map[string]any{
"library_id": targetLibrary.ID,
"series_id": "",
}
if normalizeOrganizeMediaType(mediaType) == "movie" {
updates["season_num"] = 0
updates["episode_num"] = 0
updates["episode_title"] = ""
}
applyReclassifyMatchUpdates(updates, metadataMatch)
if err := o.repo.DB.WithContext(ctx).Model(&model.Media{}).Where("id = ?", media.ID).Updates(updates).Error; err != nil {
return false, err
}
if o.log != nil {
o.log.Info("cloud media library reclassified by metadata",
zap.String("media", media.ID),
zap.String("path", media.Path),
zap.String("from_library", lib.ID),
zap.String("to_library", targetLibrary.ID),
zap.String("category", category),
zap.String("media_type", mediaType),
zap.String("display_dir", displayDir))
}
res.Reclassified++
return true, nil
}
func (o *OrganizerService) cloudReclassifyCategoryDisplayDir(mediaType, category string) string {
category = sanitizeFilename(strings.TrimSpace(category))
if category == "" {
return ""
}
root := o.mediaTypeRootDirForCategory(mediaType, category)
if root == "" {
return ""
}
return strings.Join([]string{root, category}, "/")
}
func (o *OrganizerService) ensureCloudReclassifyLibrary(ctx context.Context, provider, displayDir, mediaType string, dryRun bool) (model.Library, bool, error) {
if o == nil || o.repo == nil || o.repo.Library == nil {
return model.Library{}, false, nil
}
provider = strings.TrimSpace(provider)
displayDir = normalizeCloudMountDir(provider, displayDir)
if provider == "" || displayDir == "" {
return model.Library{}, false, nil
}
if existing := o.findCloudReclassifyLibrary(ctx, provider, displayDir); existing != nil {
return *existing, true, nil
}
path := BuildCloudAutoCategoryLibraryPath(provider, displayDir)
if path == "" {
return model.Library{}, false, nil
}
name := cloudMountDirBase(displayDir)
if name == "" {
name = displayDir
}
libType := InferCloudMountMediaType(displayDir, name)
if normalizeOrganizeMediaType(libType) == "" {
libType = organizeLibraryModelType(mediaType)
}
lib := model.Library{
Name: name,
Path: path,
Type: libType,
Enabled: true,
}
if dryRun {
return lib, true, nil
}
if err := o.repo.Library.Create(ctx, &lib); err != nil {
if existing := o.findCloudReclassifyLibrary(ctx, provider, displayDir); existing != nil {
return *existing, true, nil
}
return model.Library{}, false, err
}
if o.log != nil {
o.log.Info("created cloud metadata reclassify library",
zap.String("library_id", lib.ID),
zap.String("provider", provider),
zap.String("display_dir", displayDir),
zap.String("type", lib.Type))
}
return lib, true, nil
}
func (o *OrganizerService) findCloudReclassifyLibrary(ctx context.Context, provider, displayDir string) *model.Library {
if o == nil || o.repo == nil || o.repo.Library == nil {
return nil
}
libs, err := o.repo.Library.List(ctx)
if err != nil {
if o.log != nil {
o.log.Warn("list cloud libraries for metadata reclassify failed", zap.Error(err))
}
return nil
}
displayDir = normalizeCloudMountDir(provider, displayDir)
for _, lib := range libs {
if !lib.Enabled {
continue
}
info, ok := ParseCloudLibraryMount(lib.Path)
if !ok || info.Provider != provider {
continue
}
if normalizeCloudMountDir(provider, info.DisplayDir) == displayDir {
return &lib
}
}
return nil
}