package sync import ( "fmt" "path/filepath" "strings" "sub-cli/internal/format/lrc" "sub-cli/internal/model" ) // SyncLyrics synchronizes the timeline of a source lyrics file with a target lyrics file func SyncLyrics(sourceFile, targetFile string) error { sourceFmt := strings.TrimPrefix(filepath.Ext(sourceFile), ".") targetFmt := strings.TrimPrefix(filepath.Ext(targetFile), ".") // Currently only supports LRC files if sourceFmt != "lrc" || targetFmt != "lrc" { return fmt.Errorf("sync only supports LRC files currently") } source, err := lrc.Parse(sourceFile) if err != nil { return fmt.Errorf("error parsing source file: %w", err) } target, err := lrc.Parse(targetFile) if err != nil { return fmt.Errorf("error parsing target file: %w", err) } // Apply timeline from source to target syncedLyrics := syncTimeline(source, target) // Write the synced lyrics to the target file return lrc.Generate(syncedLyrics, targetFile) } // syncTimeline applies the timeline from the source lyrics to the target lyrics func syncTimeline(source, target model.Lyrics) model.Lyrics { result := model.Lyrics{ Metadata: target.Metadata, Content: target.Content, } // Use source timeline if available and lengths match if len(source.Timeline) > 0 && len(source.Timeline) == len(target.Content) { result.Timeline = source.Timeline } else if len(source.Timeline) > 0 { // If lengths don't match, scale timeline result.Timeline = scaleTimeline(source.Timeline, len(target.Content)) } return result } // scaleTimeline scales a timeline to match a different number of entries func scaleTimeline(timeline []model.Timestamp, targetCount int) []model.Timestamp { if targetCount <= 0 || len(timeline) == 0 { return []model.Timestamp{} } result := make([]model.Timestamp, targetCount) if targetCount == 1 { result[0] = timeline[0] return result } sourceLength := len(timeline) for i := 0; i < targetCount; i++ { // Scale index to match source timeline sourceIndex := i * (sourceLength - 1) / (targetCount - 1) result[i] = timeline[sourceIndex] } return result }