From 0b4bbb18087fe7e280a302f031e19852ef741a48 Mon Sep 17 00:00:00 2001 From: SayaAndy Date: Tue, 19 Aug 2025 00:14:30 +0700 Subject: feat: allow multiple converters for processing --- config/config-b2.sample.json | 126 ++++++++++++++++++++++++++++++----- config/config-local-unix.sample.json | 20 +++--- config/config.go | 98 ++++++++++++++------------- 3 files changed, 168 insertions(+), 76 deletions(-) (limited to 'config') diff --git a/config/config-b2.sample.json b/config/config-b2.sample.json index c48b1b2..043c1a6 100644 --- a/config/config-b2.sample.json +++ b/config/config-b2.sample.json @@ -20,26 +20,116 @@ "png" ] }, - "Converter": { - "Type": "webp", - "Config": { - "Quality": 80, - "Size": { - "MaxWidth": 800, - "MaxHeight": 0 + "Converters": [ + { + "Type": "webp", + "Config": { + "Quality": 80, + "Size": { + "MaxWidth": 320, + "MaxHeight": 0 + } + }, + "Output": { + "Storage": { + "Type": "b2", + "Config": { + "BucketName": "sayana-photos", + "Region": "eu-central-003", + "Prefix": "webp-320p/", + "KeyID": "${B2_KEY_ID}", + "ApplicationKey": "${B2_APPLICATION_KEY}" + } + } } - } - }, - "Output": { - "Storage": { - "Type": "b2", + }, + { + "Type": "webp", "Config": { - "BucketName": "sayana-photos", - "Region": "eu-central-003", - "Prefix": "thumbnails/", - "KeyID": "${B2_KEY_ID}", - "ApplicationKey": "${B2_APPLICATION_KEY}" + "Quality": 80, + "Size": { + "MaxWidth": 560, + "MaxHeight": 0 + } + }, + "Output": { + "Storage": { + "Type": "b2", + "Config": { + "BucketName": "sayana-photos", + "Region": "eu-central-003", + "Prefix": "webp-560p/", + "KeyID": "${B2_KEY_ID}", + "ApplicationKey": "${B2_APPLICATION_KEY}" + } + } + } + }, + { + "Type": "webp", + "Config": { + "Quality": 80, + "Size": { + "MaxWidth": 800, + "MaxHeight": 0 + } + }, + "Output": { + "Storage": { + "Type": "b2", + "Config": { + "BucketName": "sayana-photos", + "Region": "eu-central-003", + "Prefix": "webp-800p/", + "KeyID": "${B2_KEY_ID}", + "ApplicationKey": "${B2_APPLICATION_KEY}" + } + } + } + }, + { + "Type": "webp", + "Config": { + "Quality": 80, + "Size": { + "MaxWidth": 1200, + "MaxHeight": 0 + } + }, + "Output": { + "Storage": { + "Type": "b2", + "Config": { + "BucketName": "sayana-photos", + "Region": "eu-central-003", + "Prefix": "webp-1200p/", + "KeyID": "${B2_KEY_ID}", + "ApplicationKey": "${B2_APPLICATION_KEY}" + } + } + } + }, + { + "Type": "webp", + "Config": { + "Quality": 80, + "Size": { + "MaxWidth": 1600, + "MaxHeight": 0 + } + }, + "Output": { + "Storage": { + "Type": "b2", + "Config": { + "BucketName": "sayana-photos", + "Region": "eu-central-003", + "Prefix": "webp-1600p/", + "KeyID": "${B2_KEY_ID}", + "ApplicationKey": "${B2_APPLICATION_KEY}" + } + } } } - } + ] } \ No newline at end of file diff --git a/config/config-local-unix.sample.json b/config/config-local-unix.sample.json index 36d8114..97f69f1 100644 --- a/config/config-local-unix.sample.json +++ b/config/config-local-unix.sample.json @@ -25,16 +25,16 @@ "MaxWidth": 800, "MaxHeight": 0 } - } - }, - "Output": { - "Storage": { - "Type": "local-unix", - "Config": { - "Path": "/tmp/thumbnailing/thumbnails/", - "DirPermissionMode": "0755", - "FilePermissionMode": "0644", - "AttributesImplementation": "xattr" + }, + "Output": { + "Storage": { + "Type": "local-unix", + "Config": { + "Path": "/tmp/thumbnailing/thumbnails/", + "DirPermissionMode": "0755", + "FilePermissionMode": "0644", + "AttributesImplementation": "xattr" + } } } } diff --git a/config/config.go b/config/config.go index 5b05ce9..ab051b2 100644 --- a/config/config.go +++ b/config/config.go @@ -10,13 +10,12 @@ import ( ) type Config struct { - Input InputConfig `json:"Input" validate:"required"` - Converter ConverterConfig `json:"Converter" validate:"required"` - Output OutputConfig `json:"Output" validate:"required"` - MaxProcessThreads int `json:"MaxProcessThreads" validate:"required,min=1"` - MaxPreProcessThreads int `json:"MaxPreProcessThreads" validate:"min=1;gtefield=MaxProcessThreads"` - ForceRewrite bool `json:"ForceRewrite" validate:"required"` - LogLevel slog.Level `json:"LogLevel" validate:"required"` + Input InputConfig `json:"Input" validate:"required"` + Converters []ConverterConfig `json:"Converters" validate:"required"` + MaxProcessThreads int `json:"MaxProcessThreads" validate:"required,min=1"` + MaxPreProcessThreads int `json:"MaxPreProcessThreads" validate:"min=1;gtefield=MaxProcessThreads"` + ForceRewrite bool `json:"ForceRewrite" validate:"required"` + LogLevel slog.Level `json:"LogLevel" validate:"required"` } type InputConfig struct { @@ -61,6 +60,50 @@ func (sc *InputStorageConfig) UnmarshalJSON(data []byte) error { return nil } +type ConverterConfig struct { + Type string `json:"Type" validate:"required,oneof=webp"` + Config any `json:"Config" validate:"required"` + Output OutputConfig `json:"Output" validate:"required"` +} + +func (pc *ConverterConfig) UnmarshalJSON(data []byte) error { + var tmp struct { + Type string `json:"Type"` + Config json.RawMessage `json:"Config"` + Output OutputConfig `json:"Output"` + } + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + pc.Type = tmp.Type + pc.Output = tmp.Output + + switch tmp.Type { + case "webp": + var webpConfig WebpConfig + if err := json.Unmarshal(tmp.Config, &webpConfig); err != nil { + return fmt.Errorf("unmarshal WebpConfig: %w", err) + } + pc.Config = &webpConfig + default: + return fmt.Errorf("unsupported storage type: %s", tmp.Type) + } + + return nil +} + +type WebpConfig struct { + Quality int `json:"Quality" validate:"required,min=1,max=100"` + Size SizeConfig `json:"Size" validate:"required"` +} + +type SizeConfig struct { + MaxWidth int `json:"MaxWidth" validate:"required,min=0"` + MaxHeight int `json:"MaxHeight" validate:"required,min=0"` +} + type OutputStorageConfig struct { Type string `json:"Type" validate:"required,oneof=b2 local-unix"` Config any `json:"Config" validate:"required"` @@ -122,47 +165,6 @@ type OutputLocalUnixConfig struct { AttributesImplementation string `json:"AttributesImplementation" validate:"required,oneof=xattr none"` } -type ConverterConfig struct { - Type string `json:"Type" validate:"required,oneof=webp"` - Config any `json:"Config" validate:"required"` -} - -func (pc *ConverterConfig) UnmarshalJSON(data []byte) error { - var tmp struct { - Type string `json:"Type"` - Config json.RawMessage `json:"Config"` - } - - if err := json.Unmarshal(data, &tmp); err != nil { - return err - } - - pc.Type = tmp.Type - - switch tmp.Type { - case "webp": - var webpConfig WebpConfig - if err := json.Unmarshal(tmp.Config, &webpConfig); err != nil { - return fmt.Errorf("unmarshal WebpConfig: %w", err) - } - pc.Config = &webpConfig - default: - return fmt.Errorf("unsupported storage type: %s", tmp.Type) - } - - return nil -} - -type WebpConfig struct { - Quality int `json:"Quality" validate:"required,min=1,max=100"` - Size SizeConfig `json:"Size" validate:"required"` -} - -type SizeConfig struct { - MaxWidth int `json:"MaxWidth" validate:"required,min=0"` - MaxHeight int `json:"MaxHeight" validate:"required,min=0"` -} - func LoadConfig(path string, config *Config) error { fileBytes, err := os.ReadFile(path) if err != nil { -- cgit v1.3.1+13