Git Repository

Mini Video Library

Mini Video Library scannt lokale Medienordner, verwaltet Metadaten und Vorschaubilder und streamt kompatible Videos direkt per HTTP an den Browser.

Projektseite ↗
HTTPShttps://zanvex.de/git/mini-video-library.git

internal/thumbnail/thumbnail.go

Zum Verzeichnis
package thumbnail

import (
	"context"
	"fmt"
	"log/slog"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
)

type Generator struct {
	binary, dir string
	width       int
	count       int
	log         *slog.Logger
	mu          sync.RWMutex
}

func New(binary, dir string, width, count int, log *slog.Logger) *Generator {
	if count < 1 {
		count = 1
	}
	return &Generator{binary: binary, dir: dir, width: width, count: count, log: log}
}
func (g *Generator) SetBinary(path string) { g.mu.Lock(); g.binary = path; g.mu.Unlock() }
func (g *Generator) Generate(ctx context.Context, id int64, path string, duration float64) (string, error) {
	g.mu.RLock()
	binary := g.binary
	g.mu.RUnlock()
	if err := os.MkdirAll(g.dir, 0755); err != nil {
		return "", err
	}
	primary := ""
	for i := 1; i <= g.count; i++ {
		out := g.Path(id, i)
		if i == 1 {
			primary = out
		}
		if _, e := os.Stat(out); e == nil {
			continue
		}
		at := duration * float64(i) / float64(g.count+1)
		if at < 1 {
			at = 1
		}
		cmd := exec.CommandContext(ctx, binary, "-hide_banner", "-loglevel", "error", "-ss", fmt.Sprintf("%.2f", at), "-i", path, "-frames:v", "1", "-vf", fmt.Sprintf("scale=%d:-2", g.width), "-q:v", "3", "-y", out)
		if b, e := cmd.CombinedOutput(); e != nil {
			return "", fmt.Errorf("ffmpeg: %w (%s)", e, b)
		}
	}
	return primary, nil
}
func (g *Generator) Path(id int64, index int) string {
	g.mu.RLock()
	dir := g.dir
	g.mu.RUnlock()
	if index <= 1 {
		return filepath.Join(dir, fmt.Sprintf("%d.jpg", id))
	}
	return filepath.Join(dir, fmt.Sprintf("%d-%d.jpg", id, index))
}
func (g *Generator) Regenerate(ctx context.Context, id int64, path string, duration float64) (string, error) {
	g.mu.RLock()
	dir := g.dir
	g.mu.RUnlock()
	matches, _ := filepath.Glob(filepath.Join(dir, fmt.Sprintf("%d*.jpg", id)))
	for _, p := range matches {
		_ = os.Remove(p)
	}
	return g.Generate(ctx, id, path, duration)
}