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/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/router.go b/routers/router.go index d474ccf3..213a05b4 100644 --- a/routers/router.go +++ b/routers/router.go @@ -618,12 +618,13 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.ServeEntity, ) } - // 获取缩略图 + // get thumb file.GET("thumb", middleware.ContextHint(), controllers.FromQuery[explorer.FileThumbService](explorer.FileThumbParameterCtx{}), controllers.Thumb, ) + // reset thumb removed; use metadata patch to re-enable thumbnails // Delete files file.DELETE("", controllers.FromJSON[explorer.DeleteFileService](explorer.DeleteFileParameterCtx{}), 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)