This commit is contained in:
CDN 2025-04-23 08:01:13 +08:00
parent aedc4a4518
commit 9b0e2ed6dc
Signed by: CDN
GPG key ID: 0C656827F9F80080
15 changed files with 693 additions and 540 deletions

View file

@ -0,0 +1,137 @@
package converter
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"sub-cli/internal/format/lrc"
"sub-cli/internal/format/srt"
"sub-cli/internal/model"
)
// ErrUnsupportedFormat is returned when trying to convert to/from an unsupported format
var ErrUnsupportedFormat = errors.New("unsupported format")
// Convert converts a file from one format to another
func Convert(sourceFile, targetFile string) error {
sourceFmt := strings.TrimPrefix(filepath.Ext(sourceFile), ".")
targetFmt := strings.TrimPrefix(filepath.Ext(targetFile), ".")
switch sourceFmt {
case "lrc":
return convertFromLRC(sourceFile, targetFile, targetFmt)
case "srt":
return convertFromSRT(sourceFile, targetFile, targetFmt)
default:
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, sourceFmt)
}
}
// 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 {
case "txt":
return lrcToTxt(sourceLyrics, targetFile)
case "srt":
return lrcToSRT(sourceLyrics, targetFile)
case "lrc":
return lrc.Generate(sourceLyrics, targetFile)
default:
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, targetFmt)
}
}
// 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
}