117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
package importmedia
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var langSuffixRe = regexp.MustCompile(`(?i)\.(nl|nld|dut|dutch|en|eng|english|forced|sdh|hi)(?:\.(forced|sdh|hi))?$`)
|
|
|
|
var subtitleExt = map[string]string{
|
|
".srt": "srt",
|
|
".vtt": "vtt",
|
|
".ass": "ass",
|
|
".ssa": "ass",
|
|
}
|
|
|
|
const maxSidecarBytes = 2 * 1024 * 1024
|
|
|
|
type SidecarHit struct {
|
|
FileName string
|
|
Language string
|
|
Format string
|
|
Content []byte
|
|
}
|
|
|
|
// FindSidecarsBesideVideo returns subtitle files in the same folder that match the video stem.
|
|
func FindSidecarsBesideVideo(videoPath string) ([]SidecarHit, error) {
|
|
videoPath = filepath.Clean(strings.TrimSpace(videoPath))
|
|
if videoPath == "" {
|
|
return nil, nil
|
|
}
|
|
info, err := os.Stat(videoPath)
|
|
if err != nil || info.IsDir() {
|
|
return nil, err
|
|
}
|
|
|
|
dir := filepath.Dir(videoPath)
|
|
stem := strings.TrimSuffix(filepath.Base(videoPath), filepath.Ext(videoPath))
|
|
stemLower := strings.ToLower(stem)
|
|
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out []SidecarHit
|
|
for _, ent := range entries {
|
|
if ent.IsDir() {
|
|
continue
|
|
}
|
|
name := ent.Name()
|
|
ext := strings.ToLower(filepath.Ext(name))
|
|
format, ok := subtitleExt[ext]
|
|
if !ok {
|
|
continue
|
|
}
|
|
base := strings.TrimSuffix(name, filepath.Ext(name))
|
|
baseLower := strings.ToLower(base)
|
|
if !sidecarMatchesStem(stemLower, baseLower) {
|
|
continue
|
|
}
|
|
full := filepath.Join(dir, name)
|
|
fi, err := ent.Info()
|
|
if err != nil || fi.Size() <= 0 || fi.Size() > maxSidecarBytes {
|
|
continue
|
|
}
|
|
raw, err := os.ReadFile(full)
|
|
if err != nil || len(raw) == 0 {
|
|
continue
|
|
}
|
|
out = append(out, SidecarHit{
|
|
FileName: name,
|
|
Language: guessLangFromName(baseLower, stemLower),
|
|
Format: format,
|
|
Content: raw,
|
|
})
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func sidecarMatchesStem(stemLower, subBaseLower string) bool {
|
|
if subBaseLower == stemLower {
|
|
return true
|
|
}
|
|
if strings.HasPrefix(subBaseLower, stemLower+".") {
|
|
return true
|
|
}
|
|
// Strip known lang tags and compare
|
|
stripped := langSuffixRe.ReplaceAllString(subBaseLower, "")
|
|
return stripped == stemLower
|
|
}
|
|
|
|
func guessLangFromName(subBaseLower, stemLower string) string {
|
|
rest := strings.TrimPrefix(subBaseLower, stemLower)
|
|
rest = strings.TrimPrefix(rest, ".")
|
|
if rest == "" {
|
|
return "nl"
|
|
}
|
|
parts := strings.Split(rest, ".")
|
|
for _, p := range parts {
|
|
switch p {
|
|
case "nl", "nld", "dut", "dutch":
|
|
return "nl"
|
|
case "en", "eng", "english":
|
|
return "en"
|
|
}
|
|
}
|
|
return "nl"
|
|
}
|
|
|
|
// EncodeSidecarBase64 helper for control payloads.
|
|
func EncodeSidecarBase64(b []byte) string {
|
|
return base64.StdEncoding.EncodeToString(b)
|
|
}
|