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/sidecar/subtitles.go

Zum Verzeichnis
package sidecar

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
)

type Subtitle struct {
	Path, Name, Language, Format string
	Playable                     bool
}

var supported = map[string]bool{".srt": true, ".vtt": true, ".ass": true, ".ssa": true}
var languageAliases = map[string]string{"de": "de", "deu": "de", "ger": "de", "en": "en", "eng": "en", "ja": "ja", "jpn": "ja", "fr": "fr", "fra": "fr", "fre": "fr", "es": "es", "spa": "es"}
var timestamp = regexp.MustCompile(`(\d{2}:\d{2}:\d{2}),(\d{3})`)

func Find(videoPath string) ([]Subtitle, error) {
	dir := filepath.Dir(videoPath)
	base := strings.TrimSuffix(filepath.Base(videoPath), filepath.Ext(videoPath))
	entries, err := os.ReadDir(dir)
	if err != nil {
		return nil, err
	}
	var result []Subtitle
	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		ext := strings.ToLower(filepath.Ext(entry.Name()))
		if !supported[ext] {
			continue
		}
		stem := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name()))
		if stem != base && !strings.HasPrefix(stem, base+".") && !strings.HasPrefix(stem, base+"_") {
			continue
		}
		language := "und"
		parts := strings.FieldsFunc(strings.TrimPrefix(stem, base), func(r rune) bool { return r == '.' || r == '_' || r == '-' })
		for _, part := range parts {
			if value := languageAliases[strings.ToLower(part)]; value != "" {
				language = value
				break
			}
		}
		result = append(result, Subtitle{Path: filepath.Join(dir, entry.Name()), Name: entry.Name(), Language: language, Format: strings.TrimPrefix(ext, "."), Playable: ext == ".srt" || ext == ".vtt"})
	}
	sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
	return result, nil
}

func WebVTT(subtitle Subtitle) ([]byte, error) {
	data, err := os.ReadFile(subtitle.Path)
	if err != nil {
		return nil, err
	}
	if strings.EqualFold(subtitle.Format, "vtt") {
		return data, nil
	}
	if !strings.EqualFold(subtitle.Format, "srt") {
		return nil, fmt.Errorf("subtitle format %s is not browser-playable", subtitle.Format)
	}
	var output bytes.Buffer
	output.WriteString("WEBVTT\n\n")
	scanner := bufio.NewScanner(bytes.NewReader(data))
	for scanner.Scan() {
		output.WriteString(timestamp.ReplaceAllString(scanner.Text(), "$1.$2"))
		output.WriteByte('\n')
	}
	return output.Bytes(), scanner.Err()
}