feat: vtt converting
This commit is contained in:
parent
ba2e477dc0
commit
ba66894e42
7 changed files with 693 additions and 107 deletions
|
@ -3,12 +3,13 @@ package converter
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sub-cli/internal/format/lrc"
|
||||
"sub-cli/internal/format/srt"
|
||||
"sub-cli/internal/format/txt"
|
||||
"sub-cli/internal/format/vtt"
|
||||
"sub-cli/internal/model"
|
||||
)
|
||||
|
||||
|
@ -20,118 +21,47 @@ func Convert(sourceFile, targetFile string) error {
|
|||
sourceFmt := strings.TrimPrefix(filepath.Ext(sourceFile), ".")
|
||||
targetFmt := strings.TrimPrefix(filepath.Ext(targetFile), ".")
|
||||
|
||||
switch sourceFmt {
|
||||
// TXT only supports being a target format
|
||||
if sourceFmt == "txt" {
|
||||
return fmt.Errorf("%w: txt is only supported as a target format", ErrUnsupportedFormat)
|
||||
}
|
||||
|
||||
// Convert source to intermediate representation
|
||||
subtitle, err := convertToIntermediate(sourceFile, sourceFmt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert from intermediate representation to target format
|
||||
return convertFromIntermediate(subtitle, targetFile, targetFmt)
|
||||
}
|
||||
|
||||
// convertToIntermediate converts a source file to our intermediate Subtitle representation
|
||||
func convertToIntermediate(sourceFile, sourceFormat string) (model.Subtitle, error) {
|
||||
switch sourceFormat {
|
||||
case "lrc":
|
||||
return convertFromLRC(sourceFile, targetFile, targetFmt)
|
||||
return lrc.ConvertToSubtitle(sourceFile)
|
||||
case "srt":
|
||||
return convertFromSRT(sourceFile, targetFile, targetFmt)
|
||||
return srt.ConvertToSubtitle(sourceFile)
|
||||
case "vtt":
|
||||
return vtt.ConvertToSubtitle(sourceFile)
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, sourceFmt)
|
||||
return model.Subtitle{}, fmt.Errorf("%w: %s", ErrUnsupportedFormat, sourceFormat)
|
||||
}
|
||||
}
|
||||
|
||||
// convertFromLRC converts an LRC file to another format
|
||||
func convertFromLRC(sourceFile, targetFile, targetFmt string) error {
|
||||
sourceLyrics, err := lrc.Parse(sourceFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing source LRC file: %w", err)
|
||||
}
|
||||
|
||||
switch targetFmt {
|
||||
// convertFromIntermediate converts our intermediate Subtitle representation to a target format
|
||||
func convertFromIntermediate(subtitle model.Subtitle, targetFile, targetFormat string) error {
|
||||
switch targetFormat {
|
||||
case "lrc":
|
||||
return lrc.ConvertFromSubtitle(subtitle, targetFile)
|
||||
case "srt":
|
||||
return srt.ConvertFromSubtitle(subtitle, targetFile)
|
||||
case "vtt":
|
||||
return vtt.ConvertFromSubtitle(subtitle, targetFile)
|
||||
case "txt":
|
||||
return lrcToTxt(sourceLyrics, targetFile)
|
||||
case "srt":
|
||||
return lrcToSRT(sourceLyrics, targetFile)
|
||||
case "lrc":
|
||||
return lrc.Generate(sourceLyrics, targetFile)
|
||||
return txt.GenerateFromSubtitle(subtitle, targetFile)
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, targetFmt)
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, targetFormat)
|
||||
}
|
||||
}
|
||||
|
||||
// convertFromSRT converts an SRT file to another format
|
||||
func convertFromSRT(sourceFile, targetFile, targetFmt string) error {
|
||||
entries, err := srt.Parse(sourceFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing source SRT file: %w", err)
|
||||
}
|
||||
|
||||
switch targetFmt {
|
||||
case "txt":
|
||||
return srtToTxt(entries, targetFile)
|
||||
case "lrc":
|
||||
lyrics := srt.ConvertToLyrics(entries)
|
||||
return lrc.Generate(lyrics, targetFile)
|
||||
case "srt":
|
||||
return srt.Generate(entries, targetFile)
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, targetFmt)
|
||||
}
|
||||
}
|
||||
|
||||
// lrcToTxt converts LRC lyrics to a plain text file
|
||||
func lrcToTxt(lyrics model.Lyrics, targetFile string) error {
|
||||
file, err := os.Create(targetFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating target file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
for _, content := range lyrics.Content {
|
||||
if _, err := fmt.Fprintln(file, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// lrcToSRT converts LRC lyrics to an SRT file
|
||||
func lrcToSRT(lyrics model.Lyrics, targetFile string) error {
|
||||
var entries []model.SRTEntry
|
||||
|
||||
for i, content := range lyrics.Content {
|
||||
if i >= len(lyrics.Timeline) {
|
||||
break
|
||||
}
|
||||
|
||||
startTime := lyrics.Timeline[i]
|
||||
endTime := startTime
|
||||
|
||||
// If there's a next timeline entry, use it for end time
|
||||
// Otherwise add a few seconds to the start time
|
||||
if i+1 < len(lyrics.Timeline) {
|
||||
endTime = lyrics.Timeline[i+1]
|
||||
} else {
|
||||
endTime.Seconds += 3
|
||||
}
|
||||
|
||||
entry := model.SRTEntry{
|
||||
Number: i + 1,
|
||||
StartTime: startTime,
|
||||
EndTime: endTime,
|
||||
Content: content,
|
||||
}
|
||||
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
|
||||
return srt.Generate(entries, targetFile)
|
||||
}
|
||||
|
||||
// srtToTxt converts SRT entries to a plain text file
|
||||
func srtToTxt(entries []model.SRTEntry, targetFile string) error {
|
||||
file, err := os.Create(targetFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating target file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
for _, entry := range entries {
|
||||
if _, err := fmt.Fprintln(file, entry.Content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue