github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/thumb/pipeline.go (about)

     1  package thumb
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	model "github.com/cloudreve/Cloudreve/v3/models"
     8  	"github.com/cloudreve/Cloudreve/v3/pkg/util"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"sort"
    14  	"strconv"
    15  )
    16  
    17  // Generator generates a thumbnail for a given reader.
    18  type Generator interface {
    19  	// Generate generates a thumbnail for a given reader. Src is the original file path, only provided
    20  	// for local policy files.
    21  	Generate(ctx context.Context, file io.Reader, src string, name string, options map[string]string) (*Result, error)
    22  
    23  	// Priority of execution order, smaller value means higher priority.
    24  	Priority() int
    25  
    26  	// EnableFlag returns the setting name to enable this generator.
    27  	EnableFlag() string
    28  }
    29  
    30  type Result struct {
    31  	Path     string
    32  	Continue bool
    33  	Cleanup  []func()
    34  }
    35  
    36  type (
    37  	GeneratorType string
    38  	GeneratorList []Generator
    39  )
    40  
    41  var (
    42  	Generators = GeneratorList{}
    43  
    44  	ErrPassThrough  = errors.New("pass through")
    45  	ErrNotAvailable = fmt.Errorf("thumbnail not available: %w", ErrPassThrough)
    46  )
    47  
    48  func (g GeneratorList) Len() int {
    49  	return len(g)
    50  }
    51  
    52  func (g GeneratorList) Less(i, j int) bool {
    53  	return g[i].Priority() < g[j].Priority()
    54  }
    55  
    56  func (g GeneratorList) Swap(i, j int) {
    57  	g[i], g[j] = g[j], g[i]
    58  }
    59  
    60  // RegisterGenerator registers a thumbnail generator.
    61  func RegisterGenerator(generator Generator) {
    62  	Generators = append(Generators, generator)
    63  	sort.Sort(Generators)
    64  }
    65  
    66  func (p GeneratorList) Generate(ctx context.Context, file io.Reader, src, name string, options map[string]string) (*Result, error) {
    67  	inputFile, inputSrc, inputName := file, src, name
    68  	for _, generator := range p {
    69  		if model.IsTrueVal(options[generator.EnableFlag()]) {
    70  			res, err := generator.Generate(ctx, inputFile, inputSrc, inputName, options)
    71  			if errors.Is(err, ErrPassThrough) {
    72  				util.Log().Debug("Failed to generate thumbnail using %s for %s: %s, passing through to next generator.", reflect.TypeOf(generator).String(), name, err)
    73  				continue
    74  			}
    75  
    76  			if res != nil && res.Continue {
    77  				util.Log().Debug("Generator %s for %s returned continue, passing through to next generator.", reflect.TypeOf(generator).String(), name)
    78  
    79  				// defer cleanup funcs
    80  				for _, cleanup := range res.Cleanup {
    81  					defer cleanup()
    82  				}
    83  
    84  				// prepare file reader for next generator
    85  				intermediate, err := os.Open(res.Path)
    86  				if err != nil {
    87  					return nil, fmt.Errorf("failed to open intermediate thumb file: %w", err)
    88  				}
    89  
    90  				defer intermediate.Close()
    91  				inputFile = intermediate
    92  				inputSrc = res.Path
    93  				inputName = filepath.Base(res.Path)
    94  				continue
    95  			}
    96  
    97  			return res, err
    98  		}
    99  	}
   100  	return nil, ErrNotAvailable
   101  }
   102  
   103  func (p GeneratorList) Priority() int {
   104  	return 0
   105  }
   106  
   107  func (p GeneratorList) EnableFlag() string {
   108  	return ""
   109  }
   110  
   111  func thumbSize(options map[string]string) (uint, uint) {
   112  	w, h := uint(400), uint(300)
   113  	if wParsed, err := strconv.Atoi(options["thumb_width"]); err == nil {
   114  		w = uint(wParsed)
   115  	}
   116  
   117  	if hParsed, err := strconv.Atoi(options["thumb_height"]); err == nil {
   118  		h = uint(hParsed)
   119  	}
   120  
   121  	return w, h
   122  }