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.
HTTPS
https://zanvex.de/git/mini-video-library.gitinternal/thumbnail/thumbnail.go
Zum Verzeichnispackage 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)
}