Cloudreve/pkg/mediameta/extractor.go

107 lines
2.5 KiB
Go

package mediameta
import (
"context"
"encoding/gob"
"errors"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager/entitysource"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
"github.com/cloudreve/Cloudreve/v4/pkg/setting"
"github.com/samber/lo"
"io"
)
type (
Extractor interface {
// Exts returns the supported file extensions.
Exts() []string
// Extract extracts the media meta from the given source.
Extract(ctx context.Context, ext string, source entitysource.EntitySource) ([]driver.MediaMeta, error)
}
)
var (
ErrFileTooLarge = errors.New("file too large")
)
func init() {
gob.Register([]driver.MediaMeta{})
}
func NewExtractorManager(ctx context.Context, settings setting.Provider, l logging.Logger) Extractor {
e := &extractorManager{
settings: settings,
extMap: make(map[string][]Extractor),
}
extractors := []Extractor{}
if e.settings.MediaMetaExifEnabled(ctx) {
exifE := newExifExtractor(settings, l)
extractors = append(extractors, exifE)
}
if e.settings.MediaMetaMusicEnabled(ctx) {
musicE := newMusicExtractor(settings, l)
extractors = append(extractors, musicE)
}
if e.settings.MediaMetaFFProbeEnabled(ctx) {
ffprobeE := newFFProbeExtractor(settings, l)
extractors = append(extractors, ffprobeE)
}
for _, extractor := range extractors {
for _, ext := range extractor.Exts() {
if e.extMap[ext] == nil {
e.extMap[ext] = []Extractor{}
}
e.extMap[ext] = append(e.extMap[ext], extractor)
}
}
return e
}
type extractorManager struct {
settings setting.Provider
extMap map[string][]Extractor
}
func (e *extractorManager) Exts() []string {
return lo.Keys(e.extMap)
}
func (e *extractorManager) Extract(ctx context.Context, ext string, source entitysource.EntitySource) ([]driver.MediaMeta, error) {
if extractor, ok := e.extMap[ext]; ok {
res := []driver.MediaMeta{}
for _, e := range extractor {
_, _ = source.Seek(0, io.SeekStart)
data, err := e.Extract(ctx, ext, source)
if err != nil {
return nil, err
}
res = append(res, data...)
}
return res, nil
} else {
return nil, nil
}
}
// checkFileSize checks if the file size exceeds the limit.
func checkFileSize(localLimit, remoteLimit int64, source entitysource.EntitySource) error {
if source.IsLocal() && localLimit > 0 && source.Entity().Size() > localLimit {
return ErrFileTooLarge
}
if !source.IsLocal() && remoteLimit > 0 && source.Entity().Size() > remoteLimit {
return ErrFileTooLarge
}
return nil
}