From 873a1b88afc6195e871d3ab6de6fb4c3e3fd9066 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sun, 4 May 2025 10:31:36 +0200 Subject: [PATCH 1/3] Call "FinishImport" even on error This gives the importer the chance to close connections and free resources to ensure already imported items are properly handled. --- internal/backends/import.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/backends/import.go b/internal/backends/import.go index 9938c10..0db5547 100644 --- a/internal/backends/import.go +++ b/internal/backends/import.go @@ -90,8 +90,7 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( defer close(progress) result := models.ImportResult{} - err := processor.ImportBackend().StartImport() - if err != nil { + if err := processor.ImportBackend().StartImport(); err != nil { out <- handleError(result, err, progress) return } @@ -99,6 +98,7 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( for exportResult := range results { importResult, err := processor.Import(exportResult, result, out, progress) if err != nil { + processor.ImportBackend().FinishImport() out <- handleError(result, err, progress) return } @@ -106,8 +106,7 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( progress <- models.Progress{}.FromImportResult(result) } - err = processor.ImportBackend().FinishImport() - if err != nil { + if err := processor.ImportBackend().FinishImport(); err != nil { out <- handleError(result, err, progress) return } From 45aeeb70877cb1ac49c69b56a08925cc3a9d174f Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sun, 4 May 2025 11:43:26 +0200 Subject: [PATCH 2/3] jspf: add MB extension, if it does not exist --- internal/backends/jspf/jspf.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/internal/backends/jspf/jspf.go b/internal/backends/jspf/jspf.go index c0d9c5c..826ea1b 100644 --- a/internal/backends/jspf/jspf.go +++ b/internal/backends/jspf/jspf.go @@ -77,14 +77,11 @@ func (b *JSPFBackend) InitConfig(config *config.ServiceConfig) error { Title: config.GetString("title"), Creator: config.GetString("username"), Identifier: config.GetString("identifier"), + Date: time.Now(), Tracks: make([]jspf.Track, 0), - Extension: jspf.ExtensionMap{ - jspf.MusicBrainzPlaylistExtensionID: jspf.MusicBrainzPlaylistExtension{ - LastModifiedAt: time.Now(), - Public: true, - }, - }, } + + b.addMusicBrainzPlaylistExtension() return nil } @@ -327,6 +324,7 @@ func (b *JSPFBackend) readJSPF() error { return err } b.playlist = playlist.Playlist + b.addMusicBrainzPlaylistExtension() } } @@ -346,3 +344,13 @@ func (b *JSPFBackend) writeJSPF() error { defer file.Close() return playlist.Write(file) } + +func (b *JSPFBackend) addMusicBrainzPlaylistExtension() { + if b.playlist.Extension == nil { + b.playlist.Extension = make(jspf.ExtensionMap, 1) + } + extension := jspf.MusicBrainzPlaylistExtension{Public: true} + b.playlist.Extension.Get(jspf.MusicBrainzPlaylistExtensionID, &extension) + extension.LastModifiedAt = time.Now() + b.playlist.Extension[jspf.MusicBrainzPlaylistExtensionID] = extension +} From 1a9f9bb36cb797714e5ac78e8695b41d77a24be6 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sun, 4 May 2025 11:52:12 +0200 Subject: [PATCH 3/3] If import fails still save the last reported timestamp This allows continuing a partially failed import run. --- internal/backends/import.go | 11 ++++++----- internal/backends/maloja/maloja.go | 3 ++- internal/cli/transfer.go | 16 +++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/backends/import.go b/internal/backends/import.go index 0db5547..c0d78bc 100644 --- a/internal/backends/import.go +++ b/internal/backends/import.go @@ -51,7 +51,7 @@ func (p ListensImportProcessor) Import(export models.ListensResult, result model } importResult, err := p.Backend.ImportListens(export, result, progress) if err != nil { - return result, err + return importResult, err } return importResult, nil } @@ -80,7 +80,7 @@ func (p LovesImportProcessor) Import(export models.LovesResult, result models.Im } importResult, err := p.Backend.ImportLoves(export, result, progress) if err != nil { - return result, err + return importResult, err } return importResult, nil } @@ -89,6 +89,7 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( defer close(out) defer close(progress) result := models.ImportResult{} + p := models.Progress{} if err := processor.ImportBackend().StartImport(); err != nil { out <- handleError(result, err, progress) @@ -97,13 +98,13 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( for exportResult := range results { importResult, err := processor.Import(exportResult, result, out, progress) + result.Update(importResult) if err != nil { processor.ImportBackend().FinishImport() out <- handleError(result, err, progress) return } - result.Update(importResult) - progress <- models.Progress{}.FromImportResult(result) + progress <- p.FromImportResult(result) } if err := processor.ImportBackend().FinishImport(); err != nil { @@ -111,7 +112,7 @@ func process[R models.LovesResult | models.ListensResult, P ImportProcessor[R]]( return } - progress <- models.Progress{}.FromImportResult(result).Complete() + progress <- p.FromImportResult(result).Complete() out <- result } diff --git a/internal/backends/maloja/maloja.go b/internal/backends/maloja/maloja.go index 6bcdcc2..a22393b 100644 --- a/internal/backends/maloja/maloja.go +++ b/internal/backends/maloja/maloja.go @@ -105,6 +105,7 @@ out: } func (b *MalojaApiBackend) ImportListens(export models.ListensResult, importResult models.ImportResult, progress chan models.Progress) (models.ImportResult, error) { + p := models.Progress{}.FromImportResult(importResult) for _, listen := range export.Items { scrobble := NewScrobble{ Title: listen.TrackName, @@ -125,7 +126,7 @@ func (b *MalojaApiBackend) ImportListens(export models.ListensResult, importResu importResult.UpdateTimestamp(listen.ListenedAt) importResult.ImportCount += 1 - progress <- models.Progress{}.FromImportResult(importResult) + progress <- p.FromImportResult(importResult) } return importResult, nil diff --git a/internal/cli/transfer.go b/internal/cli/transfer.go index 4777042..83bad2a 100644 --- a/internal/cli/transfer.go +++ b/internal/cli/transfer.go @@ -121,16 +121,7 @@ func (c *TransferCmd[E, I, R]) Transfer(exp backends.ExportProcessor[R], imp bac resultChan := make(chan models.ImportResult) go imp.Process(exportChan, resultChan, importProgress) result := <-resultChan - if timestamp.After(result.LastTimestamp) { - result.LastTimestamp = timestamp - } progress.Wait() - if result.Error != nil { - printTimestamp("Import failed, last reported timestamp was %v (%s)", result.LastTimestamp) - return result.Error - } - fmt.Println(i18n.Tr("Imported %v of %v %s into %v.", - result.ImportCount, result.TotalCount, c.entity, c.targetName)) // Update timestamp err = c.updateTimestamp(result, timestamp) @@ -138,6 +129,13 @@ func (c *TransferCmd[E, I, R]) Transfer(exp backends.ExportProcessor[R], imp bac return err } + fmt.Println(i18n.Tr("Imported %v of %v %s into %v.", + result.ImportCount, result.TotalCount, c.entity, c.targetName)) + if result.Error != nil { + printTimestamp("Import failed, last reported timestamp was %v (%s)", result.LastTimestamp) + return result.Error + } + // Print errors if len(result.ImportLog) > 0 { fmt.Println()