srt_to_yaml/main.go
Florian Maury ea2e600063 initial
2024-10-27 11:15:53 +01:00

113 lines
2.5 KiB
Go

package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"regexp"
"strings"
"gopkg.in/yaml.v3"
)
var (
IdentifierLine = regexp.MustCompile("^\ufeff?\\d+$")
TimeStampLine = regexp.MustCompile(`^((?:\d{2}:){2}\d{2},\d{3}) --> ((?:\d{2}:){2}\d{2},\d{3})$`)
)
type Entry struct {
Start string `yaml:"start"`
End string `yaml:"end"`
Speaker string `yaml:"speaker"`
Line1 string `yaml:"line"`
Line2 string `yaml:"line2"`
}
func parseSrt(r io.Reader) (entries []Entry, err error) {
srtScan := bufio.NewScanner(r)
for {
if !srtScan.Scan() {
break
}
firstLine := strings.TrimSpace(srtScan.Text())
if !IdentifierLine.MatchString(firstLine) {
err = fmt.Errorf("invalid identifier %q", string(firstLine))
return
}
if !srtScan.Scan() {
err = fmt.Errorf("unexpected end of file after identifier")
return
}
secondLine := strings.TrimSpace(srtScan.Text())
extractedValues := TimeStampLine.FindAllStringSubmatch(secondLine, -1)
if extractedValues == nil || len(extractedValues) != 1 {
err = fmt.Errorf("invalid timestamp line: %q", secondLine)
return
}
startTime := extractedValues[0][1]
endTime := extractedValues[0][2]
if !srtScan.Scan() {
err = fmt.Errorf("unexpected end of file after timestamps")
return
}
thirdLine := strings.TrimSpace(srtScan.Text())
if thirdLine == "" {
err = fmt.Errorf("unexpected empty line after timestamp")
return
}
fourthLine := ""
if srtScan.Scan() {
fourthLine = strings.TrimSpace(srtScan.Text())
if fourthLine != "" {
_ = srtScan.Scan()
if srtScan.Text() != "" {
err = fmt.Errorf("unexpected non empty line after the second line of text")
return
}
}
}
entry := Entry{
Start: startTime,
End: endTime,
Line1: thirdLine,
Line2: fourthLine,
}
entries = append(entries, entry)
}
return
}
func main() {
srtFile := flag.String("srt", "", "File path to the srt file to convert")
outFile := flag.String("out", "", "File path to the yaml file")
flag.Parse()
srtFd, err := os.Open(*srtFile)
if err != nil {
log.Fatalf("failed to open SRT file: %q", err.Error())
}
defer srtFd.Close()
entries, err := parseSrt(srtFd)
if err != nil {
log.Fatal(err)
}
yamlContent, err := yaml.Marshal(&entries)
if err != nil {
log.Fatalf("failed to marshal content, %q", err.Error())
}
outFd, err := os.OpenFile(*outFile, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
if err != nil {
log.Fatalf("failed to open YAML file: %q", err.Error())
}
defer outFd.Close()
outFd.Write(yamlContent)
}