From aae5123c3d1ab54de3b784d998ea11bd144039d6 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sun, 4 May 2025 12:59:40 +0200 Subject: [PATCH] Show progress bars as aborted on export / import error --- CHANGES.md | 1 + internal/backends/deezer/deezer.go | 4 ++-- internal/backends/import.go | 2 +- internal/backends/jspf/jspf.go | 4 ++-- internal/backends/lastfm/lastfm.go | 8 ++++---- internal/backends/listenbrainz/listenbrainz.go | 5 +++-- internal/backends/scrobblerlog/scrobblerlog.go | 2 +- internal/backends/spotify/spotify.go | 6 +++--- internal/backends/spotifyhistory/spotifyhistory.go | 4 ++-- internal/backends/subsonic/subsonic.go | 4 ++-- internal/cli/progress.go | 10 ++++++++-- internal/models/models.go | 6 ++++++ 12 files changed, 35 insertions(+), 21 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ba2685b..a0a60f2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ## 0.6.0 - WIP - Fix program hanging endlessly if import fails (#11) - If import fails still store the last successfully imported timestamp +- Show progress bars as aborted on export / import error - JSPF: implemented export as loves and listens - JSPF: write track duration - JSPF: read username and recording MSID diff --git a/internal/backends/deezer/deezer.go b/internal/backends/deezer/deezer.go index 1a5cb30..4ba367d 100644 --- a/internal/backends/deezer/deezer.go +++ b/internal/backends/deezer/deezer.go @@ -94,7 +94,7 @@ out: for { result, err := b.client.UserHistory(offset, perPage) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.ListensResult{Error: err} return } @@ -160,7 +160,7 @@ out: for { result, err := b.client.UserTracks(offset, perPage) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.LovesResult{Error: err} return } diff --git a/internal/backends/import.go b/internal/backends/import.go index c0d78bc..407082c 100644 --- a/internal/backends/import.go +++ b/internal/backends/import.go @@ -118,6 +118,6 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( func handleError(result models.ImportResult, err error, progress chan models.Progress) models.ImportResult { result.Error = err - progress <- models.Progress{}.FromImportResult(result).Complete() + progress <- models.Progress{}.FromImportResult(result).Abort() return result } diff --git a/internal/backends/jspf/jspf.go b/internal/backends/jspf/jspf.go index 826ea1b..e981741 100644 --- a/internal/backends/jspf/jspf.go +++ b/internal/backends/jspf/jspf.go @@ -96,7 +96,7 @@ func (b *JSPFBackend) FinishImport() error { func (b *JSPFBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.Progress) { err := b.readJSPF() if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.ListensResult{Error: err} return } @@ -128,7 +128,7 @@ func (b *JSPFBackend) ImportListens(export models.ListensResult, importResult mo func (b *JSPFBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.Progress) { err := b.readJSPF() if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.LovesResult{Error: err} return } diff --git a/internal/backends/lastfm/lastfm.go b/internal/backends/lastfm/lastfm.go index 444e5b0..d45f793 100644 --- a/internal/backends/lastfm/lastfm.go +++ b/internal/backends/lastfm/lastfm.go @@ -108,7 +108,7 @@ out: result, err := b.client.User.GetRecentTracks(args) if err != nil { results <- models.ListensResult{Error: err} - progress <- p.Complete() + progress <- p.Abort() return } @@ -127,7 +127,7 @@ out: timestamp, err := strconv.ParseInt(scrobble.Date.Uts, 10, 64) if err != nil { results <- models.ListensResult{Error: err} - progress <- p.Complete() + progress <- p.Abort() break out } if timestamp > oldestTimestamp.Unix() { @@ -268,7 +268,7 @@ out: "page": page, }) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.LovesResult{Error: err} return } @@ -282,7 +282,7 @@ out: for _, track := range result.Tracks { timestamp, err := strconv.ParseInt(track.Date.Uts, 10, 64) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.LovesResult{Error: err} return } diff --git a/internal/backends/listenbrainz/listenbrainz.go b/internal/backends/listenbrainz/listenbrainz.go index e1ea53d..fffe0f0 100644 --- a/internal/backends/listenbrainz/listenbrainz.go +++ b/internal/backends/listenbrainz/listenbrainz.go @@ -86,7 +86,7 @@ func (b *ListenBrainzApiBackend) ExportListens(oldestTimestamp time.Time, result for { result, err := b.client.GetListens(b.username, time.Now(), minTime) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.ListensResult{Error: err} return } @@ -199,8 +199,9 @@ func (b *ListenBrainzApiBackend) ExportLoves(oldestTimestamp time.Time, results go b.exportLoves(oldestTimestamp, exportChan) for existingLoves := range exportChan { if existingLoves.Error != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.LovesResult{Error: existingLoves.Error} + return } p.Total = int64(existingLoves.Total) diff --git a/internal/backends/scrobblerlog/scrobblerlog.go b/internal/backends/scrobblerlog/scrobblerlog.go index a355e3e..7890971 100644 --- a/internal/backends/scrobblerlog/scrobblerlog.go +++ b/internal/backends/scrobblerlog/scrobblerlog.go @@ -134,7 +134,7 @@ func (b *ScrobblerLogBackend) FinishImport() error { func (b *ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.Progress) { file, err := os.Open(b.filePath) if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.ListensResult{Error: err} return } diff --git a/internal/backends/spotify/spotify.go b/internal/backends/spotify/spotify.go index 8b6d9da..be48dfe 100644 --- a/internal/backends/spotify/spotify.go +++ b/internal/backends/spotify/spotify.go @@ -106,7 +106,7 @@ func (b *SpotifyApiBackend) ExportListens(oldestTimestamp time.Time, results cha for { result, err := b.client.RecentlyPlayedAfter(minTime, MaxItemsPerGet) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.ListensResult{Error: err} return } @@ -118,7 +118,7 @@ func (b *SpotifyApiBackend) ExportListens(oldestTimestamp time.Time, results cha // Set minTime to the newest returned listen after, err := strconv.ParseInt(result.Cursors.After, 10, 64) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.ListensResult{Error: err} return } else if after <= minTime.Unix() { @@ -169,7 +169,7 @@ out: for { result, err := b.client.UserTracks(offset, perPage) if err != nil { - progress <- p.Complete() + progress <- p.Abort() results <- models.LovesResult{Error: err} return } diff --git a/internal/backends/spotifyhistory/spotifyhistory.go b/internal/backends/spotifyhistory/spotifyhistory.go index c150d3b..23309f3 100644 --- a/internal/backends/spotifyhistory/spotifyhistory.go +++ b/internal/backends/spotifyhistory/spotifyhistory.go @@ -75,7 +75,7 @@ func (b *SpotifyHistoryBackend) InitConfig(config *config.ServiceConfig) error { func (b *SpotifyHistoryBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.Progress) { files, err := filepath.Glob(path.Join(b.dirPath, historyFileGlob)) if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.ListensResult{Error: err} return } @@ -86,7 +86,7 @@ func (b *SpotifyHistoryBackend) ExportListens(oldestTimestamp time.Time, results for i, filePath := range files { history, err := readHistoryFile(filePath) if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.ListensResult{Error: err} return } diff --git a/internal/backends/subsonic/subsonic.go b/internal/backends/subsonic/subsonic.go index a966c68..370765e 100644 --- a/internal/backends/subsonic/subsonic.go +++ b/internal/backends/subsonic/subsonic.go @@ -66,14 +66,14 @@ func (b *SubsonicApiBackend) InitConfig(config *config.ServiceConfig) error { func (b *SubsonicApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.Progress) { err := b.client.Authenticate(b.password) if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.LovesResult{Error: err} return } starred, err := b.client.GetStarred2(map[string]string{}) if err != nil { - progress <- models.Progress{}.Complete() + progress <- models.Progress{}.Abort() results <- models.LovesResult{Error: err} return } diff --git a/internal/cli/progress.go b/internal/cli/progress.go index 54ee4a8..6b60697 100644 --- a/internal/cli/progress.go +++ b/internal/cli/progress.go @@ -59,10 +59,12 @@ func setupProgressBar(p *mpb.Progress, name string) *mpb.Bar { ), mpb.AppendDecorators( decor.OnComplete( - decor.EwmaETA(decor.ET_STYLE_GO, 0, decor.WC{C: decor.DSyncWidth}), + decor.OnAbort( + decor.EwmaETA(decor.ET_STYLE_GO, 0, decor.WC{C: decor.DSyncWidth}), + i18n.Tr("error"), + ), i18n.Tr("done"), ), - // decor.OnComplete(decor.Percentage(decor.WC{W: 5, C: decor.DSyncWidthR}), "done"), decor.Name(" "), ), ) @@ -73,6 +75,10 @@ func updateProgressBar(bar *mpb.Bar, wg *sync.WaitGroup, progressChan chan model defer wg.Done() lastIterTime := time.Now() for progress := range progressChan { + if progress.Aborted { + bar.Abort(false) + return + } oldIterTime := lastIterTime lastIterTime = time.Now() bar.EwmaSetCurrent(progress.Elapsed, lastIterTime.Sub(oldIterTime)) diff --git a/internal/models/models.go b/internal/models/models.go index f2dd71d..b8f9121 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -213,6 +213,7 @@ type Progress struct { Total int64 Elapsed int64 Completed bool + Aborted bool } func (p Progress) FromImportResult(result ImportResult) Progress { @@ -226,3 +227,8 @@ func (p Progress) Complete() Progress { p.Completed = true return p } + +func (p Progress) Abort() Progress { + p.Aborted = true + return p +}