From 3d98f78caa0a1e9513c8f4f7efed9e547dc48017 Mon Sep 17 00:00:00 2001 From: MasonDye Date: Fri, 29 Aug 2025 12:01:05 +0800 Subject: [PATCH 1/3] update reset thumbnail feature --- routers/controllers/file.go | 38 ++++++++ routers/router.go | 11 +++ service/explorer/thumb.go | 188 ++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 service/explorer/thumb.go diff --git a/routers/controllers/file.go b/routers/controllers/file.go index e09a95f1..d6940122 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -412,3 +412,41 @@ func PatchView(c *gin.Context) { c.JSON(200, serializer.Response{}) } + +// ResetThumb resets thumbnail generation for files +func ResetThumb(c *gin.Context) { + service := ParametersFromContext[*explorer.ResetThumbService](c, explorer.ResetThumbParamCtx{}) + resp, err := service.Reset(c) + if err != nil { + c.JSON(200, serializer.Err(c, err)) + c.Abort() + return + } + + if resp != nil && len(resp.Errors) > 0 { + // Return error response with detailed errors + c.JSON(200, serializer.Response{ + Code: -1, + Msg: "Reset thumbnail error", + Data: resp, + }) + return + } + + c.JSON(200, serializer.Response{Data: resp}) +} + +// ThumbExts gets supported thumbnail extensions +func ThumbExts(c *gin.Context) { + service := ParametersFromContext[*explorer.ThumbExtsService](c, explorer.ThumbExtsParamCtx{}) + resp, err := service.Get(c) + if err != nil { + c.JSON(200, serializer.Err(c, err)) + c.Abort() + return + } + + c.JSON(200, serializer.Response{ + Data: resp, + }) +} diff --git a/routers/router.go b/routers/router.go index a866d880..e974371e 100644 --- a/routers/router.go +++ b/routers/router.go @@ -620,6 +620,17 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.FromQuery[explorer.FileThumbService](explorer.FileThumbParameterCtx{}), controllers.Thumb, ) + // 重置缩略图 + file.POST("thumb/reset", + controllers.FromJSON[explorer.ResetThumbService](explorer.ResetThumbParamCtx{}), + middleware.ValidateBatchFileCount(dep, explorer.ResetThumbParamCtx{}), + controllers.ResetThumb, + ) + // 获取支持的缩略图扩展名 + file.GET("thumb/exts", + controllers.FromQuery[explorer.ThumbExtsService](explorer.ThumbExtsParamCtx{}), + controllers.ThumbExts, + ) // Delete files file.DELETE("", controllers.FromJSON[explorer.DeleteFileService](explorer.DeleteFileParameterCtx{}), diff --git a/service/explorer/thumb.go b/service/explorer/thumb.go new file mode 100644 index 00000000..8f75ef1c --- /dev/null +++ b/service/explorer/thumb.go @@ -0,0 +1,188 @@ +package explorer + +import ( + "context" + "errors" + "fmt" + "sort" + "strings" + + "github.com/cloudreve/Cloudreve/v4/application/dependency" + "github.com/cloudreve/Cloudreve/v4/inventory" + "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs" + "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs/dbfs" + "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager" + "github.com/cloudreve/Cloudreve/v4/pkg/serializer" + "github.com/cloudreve/Cloudreve/v4/pkg/thumb" +) + +type ( + // ResetThumbParamCtx defines context for ResetThumbService + ResetThumbParamCtx struct{} + + // ResetThumbService handles resetting thumbnail generation for files + ResetThumbService struct { + Uris []string `json:"uris" binding:"required,min=1"` + } + + // ResetThumbError represents an error for a specific URI + ResetThumbError struct { + URI string `json:"uri"` + Reason string `json:"reason"` + } + + // ResetThumbResponse represents the response for reset thumbnail operation + ResetThumbResponse struct { + Errors []ResetThumbError `json:"errors,omitempty"` + } +) + +func (s *ResetThumbService) GetUris() []string { + return s.Uris +} + +// Reset resets thumbnail generation for the specified files +func (s *ResetThumbService) Reset(c context.Context) (*ResetThumbResponse, error) { + dep := dependency.FromContext(c) + user := inventory.UserFromContext(c) + m := manager.NewFileManager(dep, user) + defer m.Recycle() + + uris, err := fs.NewUriFromStrings(s.Uris...) + if err != nil { + return nil, serializer.NewError(serializer.CodeParamErr, "unknown uri", err) + } + + var errs []ResetThumbError + + for _, uri := range uris { + // Get the file to check if it exists and get current metadata + file, err := m.Get(c, uri, dbfs.WithFilePublicMetadata()) + if err != nil { + errs = append(errs, ResetThumbError{ + URI: uri.String(), + Reason: fmt.Sprintf("Reset thumbnail error: File does not exist"), + }) + continue + } + + // Check if thumb:disabled metadata exists + metadata := file.Metadata() + if _, exists := metadata[dbfs.ThumbDisabledKey]; exists { + // Remove the disabled mark directly via FileClient to bypass metadata validation + fileClient := dep.FileClient() + if dbfsFile, ok := file.(*dbfs.File); ok { + if err := fileClient.RemoveMetadata(c, dbfsFile.Model, dbfs.ThumbDisabledKey); err != nil { + errs = append(errs, ResetThumbError{ + URI: uri.String(), + Reason: fmt.Sprintf("Reset thumbnail error: Failed to update metadata - %s", err.Error()), + }) + continue + } + } else { + errs = append(errs, ResetThumbError{ + URI: uri.String(), + Reason: "Reset thumbnail error: Failed to access file model", + }) + continue + } + } + + // Trigger thumbnail regeneration by accessing the thumbnail + _, err = m.Thumbnail(c, uri) + if err != nil { + // Unsupported or not available + if errors.Is(err, thumb.ErrNotAvailable) || errors.Is(err, fs.ErrEntityNotExist) { + errs = append(errs, ResetThumbError{ + URI: uri.String(), + Reason: "Reset thumbnail error: File does not support thumbnail generation", + }) + } else { + errs = append(errs, ResetThumbError{ + URI: uri.String(), + Reason: fmt.Sprintf("Reset thumbnail error: Failed to generate thumbnail - %s", err.Error()), + }) + } + } + } + + if len(errs) > 0 { + return &ResetThumbResponse{Errors: errs}, nil + } + + return &ResetThumbResponse{}, nil +} + +type ( + // ThumbExtsParamCtx defines context for ThumbExtsService + ThumbExtsParamCtx struct{} + + // ThumbExtsService handles getting supported thumbnail extensions + ThumbExtsService struct{} + + // ThumbExtsResponse represents the response for supported extensions + ThumbExtsResponse struct { + Exts []string `json:"exts"` + } +) + +// Get returns all supported thumbnail extensions from enabled generators +func (s *ThumbExtsService) Get(c context.Context) (*ThumbExtsResponse, error) { + dep := dependency.FromContext(c) + settings := dep.SettingProvider() + + extensions := make(map[string]bool) + + // Built-in generator (always supports these if enabled) + if settings.BuiltinThumbGeneratorEnabled(c) { + for _, ext := range []string{"jpg", "jpeg", "png", "gif"} { + extensions[ext] = true + } + } + + // FFMpeg generator + if settings.FFMpegThumbGeneratorEnabled(c) { + for _, ext := range settings.FFMpegThumbExts(c) { + extensions[strings.ToLower(ext)] = true + } + } + + // Vips generator + if settings.VipsThumbGeneratorEnabled(c) { + for _, ext := range settings.VipsThumbExts(c) { + extensions[strings.ToLower(ext)] = true + } + } + + // LibreOffice generator + if settings.LibreOfficeThumbGeneratorEnabled(c) { + for _, ext := range settings.LibreOfficeThumbExts(c) { + extensions[strings.ToLower(ext)] = true + } + } + + // Music cover generator + if settings.MusicCoverThumbGeneratorEnabled(c) { + for _, ext := range settings.MusicCoverThumbExts(c) { + extensions[strings.ToLower(ext)] = true + } + } + + // LibRaw generator + if settings.LibRawThumbGeneratorEnabled(c) { + for _, ext := range settings.LibRawThumbExts(c) { + extensions[strings.ToLower(ext)] = true + } + } + + // Convert map to sorted slice + result := make([]string, 0, len(extensions)) + for ext := range extensions { + result = append(result, ext) + } + + // Sort extensions alphabetically using Go's built-in sort + sort.Strings(result) + + return &ThumbExtsResponse{Exts: result}, nil +} From c663c12afb85b232e261a4c2ab8914b5abd2e854 Mon Sep 17 00:00:00 2001 From: MasonDye Date: Sat, 30 Aug 2025 00:10:03 +0800 Subject: [PATCH 2/3] consolidate supported thumbnail extensions into site config; remove dedicated API --- pkg/thumb/builtin.go | 4 ++ routers/controllers/file.go | 14 ------- routers/router.go | 17 +++----- service/basic/site.go | 82 +++++++++++++++++++++++++++++-------- service/explorer/thumb.go | 76 +--------------------------------- 5 files changed, 76 insertions(+), 117 deletions(-) diff --git a/pkg/thumb/builtin.go b/pkg/thumb/builtin.go index 3a9f2ff4..2081a9c2 100644 --- a/pkg/thumb/builtin.go +++ b/pkg/thumb/builtin.go @@ -19,6 +19,10 @@ import ( const thumbTempFolder = "thumb" +// BuiltinSupportedExts lists file extensions supported by the built-in +// thumbnail generator. Extensions are lowercased and do not include the dot. +var BuiltinSupportedExts = []string{"jpg", "jpeg", "png", "gif"} + // Thumb 缩略图 type Thumb struct { src image.Image diff --git a/routers/controllers/file.go b/routers/controllers/file.go index d6940122..948a92fe 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -436,17 +436,3 @@ func ResetThumb(c *gin.Context) { c.JSON(200, serializer.Response{Data: resp}) } -// ThumbExts gets supported thumbnail extensions -func ThumbExts(c *gin.Context) { - service := ParametersFromContext[*explorer.ThumbExtsService](c, explorer.ThumbExtsParamCtx{}) - resp, err := service.Get(c) - if err != nil { - c.JSON(200, serializer.Err(c, err)) - c.Abort() - return - } - - c.JSON(200, serializer.Response{ - Data: resp, - }) -} diff --git a/routers/router.go b/routers/router.go index e974371e..5f5002be 100644 --- a/routers/router.go +++ b/routers/router.go @@ -614,22 +614,17 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.ServeEntity, ) } - // 获取缩略图 + // get thumb file.GET("thumb", middleware.ContextHint(), controllers.FromQuery[explorer.FileThumbService](explorer.FileThumbParameterCtx{}), controllers.Thumb, ) - // 重置缩略图 - file.POST("thumb/reset", - controllers.FromJSON[explorer.ResetThumbService](explorer.ResetThumbParamCtx{}), - middleware.ValidateBatchFileCount(dep, explorer.ResetThumbParamCtx{}), - controllers.ResetThumb, - ) - // 获取支持的缩略图扩展名 - file.GET("thumb/exts", - controllers.FromQuery[explorer.ThumbExtsService](explorer.ThumbExtsParamCtx{}), - controllers.ThumbExts, + // reset thumb + file.POST("thumb/reset", + controllers.FromJSON[explorer.ResetThumbService](explorer.ResetThumbParamCtx{}), + middleware.ValidateBatchFileCount(dep, explorer.ResetThumbParamCtx{}), + controllers.ResetThumb, ) // Delete files file.DELETE("", diff --git a/service/basic/site.go b/service/basic/site.go index 287c0ed1..d9383bd6 100644 --- a/service/basic/site.go +++ b/service/basic/site.go @@ -1,13 +1,17 @@ package basic import ( - "github.com/cloudreve/Cloudreve/v4/application/dependency" - "github.com/cloudreve/Cloudreve/v4/inventory" - "github.com/cloudreve/Cloudreve/v4/inventory/types" - "github.com/cloudreve/Cloudreve/v4/pkg/setting" - "github.com/cloudreve/Cloudreve/v4/service/user" - "github.com/gin-gonic/gin" - "github.com/mojocn/base64Captcha" + "sort" + "strings" + + "github.com/cloudreve/Cloudreve/v4/application/dependency" + "github.com/cloudreve/Cloudreve/v4/inventory" + "github.com/cloudreve/Cloudreve/v4/inventory/types" + "github.com/cloudreve/Cloudreve/v4/pkg/setting" + "github.com/cloudreve/Cloudreve/v4/pkg/thumb" + "github.com/cloudreve/Cloudreve/v4/service/user" + "github.com/gin-gonic/gin" + "github.com/mojocn/base64Captcha" ) // SiteConfig 站点全局设置序列 @@ -47,7 +51,10 @@ type SiteConfig struct { MaxBatchSize int `json:"max_batch_size,omitempty"` ThumbnailWidth int `json:"thumbnail_width,omitempty"` ThumbnailHeight int `json:"thumbnail_height,omitempty"` - CustomProps []types.CustomProps `json:"custom_props,omitempty"` + CustomProps []types.CustomProps `json:"custom_props,omitempty"` + + // Thumbnail section + ThumbExts []string `json:"thumb_exts,omitempty"` // App settings AppPromotion bool `json:"app_promotion,omitempty"` @@ -71,10 +78,10 @@ type ( ) func (s *GetSettingService) GetSiteConfig(c *gin.Context) (*SiteConfig, error) { - dep := dependency.FromContext(c) - settings := dep.SettingProvider() + dep := dependency.FromContext(c) + settings := dep.SettingProvider() - switch s.Section { + switch s.Section { case "login": legalDocs := settings.LegalDocuments(c) return &SiteConfig{ @@ -115,12 +122,53 @@ func (s *GetSettingService) GetSiteConfig(c *gin.Context) (*SiteConfig, error) { }, nil case "app": appSetting := settings.AppSetting(c) - return &SiteConfig{ - AppPromotion: appSetting.Promotion, - }, nil - default: - break - } + return &SiteConfig{ + AppPromotion: appSetting.Promotion, + }, nil + case "thumb": + // Return supported thumbnail extensions from enabled generators. + exts := map[string]bool{} + if settings.BuiltinThumbGeneratorEnabled(c) { + for _, e := range thumb.BuiltinSupportedExts { + exts[e] = true + } + } + if settings.FFMpegThumbGeneratorEnabled(c) { + for _, e := range settings.FFMpegThumbExts(c) { + exts[strings.ToLower(e)] = true + } + } + if settings.VipsThumbGeneratorEnabled(c) { + for _, e := range settings.VipsThumbExts(c) { + exts[strings.ToLower(e)] = true + } + } + if settings.LibreOfficeThumbGeneratorEnabled(c) { + for _, e := range settings.LibreOfficeThumbExts(c) { + exts[strings.ToLower(e)] = true + } + } + if settings.MusicCoverThumbGeneratorEnabled(c) { + for _, e := range settings.MusicCoverThumbExts(c) { + exts[strings.ToLower(e)] = true + } + } + if settings.LibRawThumbGeneratorEnabled(c) { + for _, e := range settings.LibRawThumbExts(c) { + exts[strings.ToLower(e)] = true + } + } + + // map -> sorted slice + result := make([]string, 0, len(exts)) + for e := range exts { + result = append(result, e) + } + sort.Strings(result) + return &SiteConfig{ThumbExts: result}, nil + default: + break + } u := inventory.UserFromContext(c) siteBasic := settings.SiteBasic(c) diff --git a/service/explorer/thumb.go b/service/explorer/thumb.go index 8f75ef1c..ca3e15a6 100644 --- a/service/explorer/thumb.go +++ b/service/explorer/thumb.go @@ -4,8 +4,6 @@ import ( "context" "errors" "fmt" - "sort" - "strings" "github.com/cloudreve/Cloudreve/v4/application/dependency" "github.com/cloudreve/Cloudreve/v4/inventory" @@ -113,76 +111,4 @@ func (s *ResetThumbService) Reset(c context.Context) (*ResetThumbResponse, error return &ResetThumbResponse{}, nil } -type ( - // ThumbExtsParamCtx defines context for ThumbExtsService - ThumbExtsParamCtx struct{} - - // ThumbExtsService handles getting supported thumbnail extensions - ThumbExtsService struct{} - - // ThumbExtsResponse represents the response for supported extensions - ThumbExtsResponse struct { - Exts []string `json:"exts"` - } -) - -// Get returns all supported thumbnail extensions from enabled generators -func (s *ThumbExtsService) Get(c context.Context) (*ThumbExtsResponse, error) { - dep := dependency.FromContext(c) - settings := dep.SettingProvider() - - extensions := make(map[string]bool) - - // Built-in generator (always supports these if enabled) - if settings.BuiltinThumbGeneratorEnabled(c) { - for _, ext := range []string{"jpg", "jpeg", "png", "gif"} { - extensions[ext] = true - } - } - - // FFMpeg generator - if settings.FFMpegThumbGeneratorEnabled(c) { - for _, ext := range settings.FFMpegThumbExts(c) { - extensions[strings.ToLower(ext)] = true - } - } - - // Vips generator - if settings.VipsThumbGeneratorEnabled(c) { - for _, ext := range settings.VipsThumbExts(c) { - extensions[strings.ToLower(ext)] = true - } - } - - // LibreOffice generator - if settings.LibreOfficeThumbGeneratorEnabled(c) { - for _, ext := range settings.LibreOfficeThumbExts(c) { - extensions[strings.ToLower(ext)] = true - } - } - - // Music cover generator - if settings.MusicCoverThumbGeneratorEnabled(c) { - for _, ext := range settings.MusicCoverThumbExts(c) { - extensions[strings.ToLower(ext)] = true - } - } - - // LibRaw generator - if settings.LibRawThumbGeneratorEnabled(c) { - for _, ext := range settings.LibRawThumbExts(c) { - extensions[strings.ToLower(ext)] = true - } - } - - // Convert map to sorted slice - result := make([]string, 0, len(extensions)) - for ext := range extensions { - result = append(result, ext) - } - - // Sort extensions alphabetically using Go's built-in sort - sort.Strings(result) - - return &ThumbExtsResponse{Exts: result}, nil -} +// (Thumb ext list API removed; use site config section "thumb") From ef86b6b79a5ea6903efc2f73774c67f73b4238dc Mon Sep 17 00:00:00 2001 From: MasonDye Date: Sat, 30 Aug 2025 16:56:26 +0800 Subject: [PATCH 3/3] allow patching thumb ; remove Reset Thumbnail API --- pkg/filemanager/manager/metadata.go | 9 +++ routers/controllers/file.go | 24 ------ routers/router.go | 7 +- service/explorer/thumb.go | 114 ---------------------------- 4 files changed, 10 insertions(+), 144 deletions(-) delete mode 100644 service/explorer/thumb.go diff --git a/pkg/filemanager/manager/metadata.go b/pkg/filemanager/manager/metadata.go index 69797fbf..a5293c18 100644 --- a/pkg/filemanager/manager/metadata.go +++ b/pkg/filemanager/manager/metadata.go @@ -97,6 +97,15 @@ var ( }, }, "dav": {}, + // Allow manipulating thumbnail metadata via public PatchMetadata API + "thumb": { + // Only supported thumb metadata currently is thumb:disabled + dbfs.ThumbDisabledKey: func(ctx context.Context, m *manager, patch *fs.MetadataPatch) error { + // Presence of this key disables thumbnails; value is ignored. + // We allow both setting and removing this key. + return nil + }, + }, customizeMetadataSuffix: { iconColorMetadataKey: validateColor(false), emojiIconMetadataKey: func(ctx context.Context, m *manager, patch *fs.MetadataPatch) error { diff --git a/routers/controllers/file.go b/routers/controllers/file.go index 948a92fe..e09a95f1 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -412,27 +412,3 @@ func PatchView(c *gin.Context) { c.JSON(200, serializer.Response{}) } - -// ResetThumb resets thumbnail generation for files -func ResetThumb(c *gin.Context) { - service := ParametersFromContext[*explorer.ResetThumbService](c, explorer.ResetThumbParamCtx{}) - resp, err := service.Reset(c) - if err != nil { - c.JSON(200, serializer.Err(c, err)) - c.Abort() - return - } - - if resp != nil && len(resp.Errors) > 0 { - // Return error response with detailed errors - c.JSON(200, serializer.Response{ - Code: -1, - Msg: "Reset thumbnail error", - Data: resp, - }) - return - } - - c.JSON(200, serializer.Response{Data: resp}) -} - diff --git a/routers/router.go b/routers/router.go index 5f5002be..6a8ad629 100644 --- a/routers/router.go +++ b/routers/router.go @@ -620,12 +620,7 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.FromQuery[explorer.FileThumbService](explorer.FileThumbParameterCtx{}), controllers.Thumb, ) - // reset thumb - file.POST("thumb/reset", - controllers.FromJSON[explorer.ResetThumbService](explorer.ResetThumbParamCtx{}), - middleware.ValidateBatchFileCount(dep, explorer.ResetThumbParamCtx{}), - controllers.ResetThumb, - ) + // reset thumb removed; use metadata patch to re-enable thumbnails // Delete files file.DELETE("", controllers.FromJSON[explorer.DeleteFileService](explorer.DeleteFileParameterCtx{}), diff --git a/service/explorer/thumb.go b/service/explorer/thumb.go deleted file mode 100644 index ca3e15a6..00000000 --- a/service/explorer/thumb.go +++ /dev/null @@ -1,114 +0,0 @@ -package explorer - -import ( - "context" - "errors" - "fmt" - - "github.com/cloudreve/Cloudreve/v4/application/dependency" - "github.com/cloudreve/Cloudreve/v4/inventory" - "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs" - "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs/dbfs" - "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager" - "github.com/cloudreve/Cloudreve/v4/pkg/serializer" - "github.com/cloudreve/Cloudreve/v4/pkg/thumb" -) - -type ( - // ResetThumbParamCtx defines context for ResetThumbService - ResetThumbParamCtx struct{} - - // ResetThumbService handles resetting thumbnail generation for files - ResetThumbService struct { - Uris []string `json:"uris" binding:"required,min=1"` - } - - // ResetThumbError represents an error for a specific URI - ResetThumbError struct { - URI string `json:"uri"` - Reason string `json:"reason"` - } - - // ResetThumbResponse represents the response for reset thumbnail operation - ResetThumbResponse struct { - Errors []ResetThumbError `json:"errors,omitempty"` - } -) - -func (s *ResetThumbService) GetUris() []string { - return s.Uris -} - -// Reset resets thumbnail generation for the specified files -func (s *ResetThumbService) Reset(c context.Context) (*ResetThumbResponse, error) { - dep := dependency.FromContext(c) - user := inventory.UserFromContext(c) - m := manager.NewFileManager(dep, user) - defer m.Recycle() - - uris, err := fs.NewUriFromStrings(s.Uris...) - if err != nil { - return nil, serializer.NewError(serializer.CodeParamErr, "unknown uri", err) - } - - var errs []ResetThumbError - - for _, uri := range uris { - // Get the file to check if it exists and get current metadata - file, err := m.Get(c, uri, dbfs.WithFilePublicMetadata()) - if err != nil { - errs = append(errs, ResetThumbError{ - URI: uri.String(), - Reason: fmt.Sprintf("Reset thumbnail error: File does not exist"), - }) - continue - } - - // Check if thumb:disabled metadata exists - metadata := file.Metadata() - if _, exists := metadata[dbfs.ThumbDisabledKey]; exists { - // Remove the disabled mark directly via FileClient to bypass metadata validation - fileClient := dep.FileClient() - if dbfsFile, ok := file.(*dbfs.File); ok { - if err := fileClient.RemoveMetadata(c, dbfsFile.Model, dbfs.ThumbDisabledKey); err != nil { - errs = append(errs, ResetThumbError{ - URI: uri.String(), - Reason: fmt.Sprintf("Reset thumbnail error: Failed to update metadata - %s", err.Error()), - }) - continue - } - } else { - errs = append(errs, ResetThumbError{ - URI: uri.String(), - Reason: "Reset thumbnail error: Failed to access file model", - }) - continue - } - } - - // Trigger thumbnail regeneration by accessing the thumbnail - _, err = m.Thumbnail(c, uri) - if err != nil { - // Unsupported or not available - if errors.Is(err, thumb.ErrNotAvailable) || errors.Is(err, fs.ErrEntityNotExist) { - errs = append(errs, ResetThumbError{ - URI: uri.String(), - Reason: "Reset thumbnail error: File does not support thumbnail generation", - }) - } else { - errs = append(errs, ResetThumbError{ - URI: uri.String(), - Reason: fmt.Sprintf("Reset thumbnail error: Failed to generate thumbnail - %s", err.Error()), - }) - } - } - } - - if len(errs) > 0 { - return &ResetThumbResponse{Errors: errs}, nil - } - - return &ResetThumbResponse{}, nil -} - -// (Thumb ext list API removed; use site config section "thumb")