diff --git a/internal/backends/deezer/deezer.go b/internal/backends/deezer/deezer.go index f3e3d37..c38f4e7 100644 --- a/internal/backends/deezer/deezer.go +++ b/internal/backends/deezer/deezer.go @@ -78,9 +78,7 @@ func (b *DeezerApiBackend) OAuth2Setup(token oauth2.TokenSource) error { return nil } -func (b *DeezerApiBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { - ctx := context.TODO() - +func (b *DeezerApiBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { // Choose a high offset, we attempt to search the loves backwards starting // at the oldest one. offset := math.MaxInt32 @@ -156,9 +154,7 @@ out: progress <- p } -func (b *DeezerApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { - ctx := context.TODO() - +func (b *DeezerApiBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { // Choose a high offset, we attempt to search the loves backwards starting // at the oldest one. offset := math.MaxInt32 diff --git a/internal/backends/export.go b/internal/backends/export.go index 0deebc6..29ae595 100644 --- a/internal/backends/export.go +++ b/internal/backends/export.go @@ -40,7 +40,7 @@ func (p ListensExportProcessor) Process(ctx context.Context, wg *sync.WaitGroup, wg.Add(1) defer wg.Done() defer close(results) - p.Backend.ExportListens(oldestTimestamp, results, progress) + p.Backend.ExportListens(ctx, oldestTimestamp, results, progress) } type LovesExportProcessor struct { @@ -55,5 +55,5 @@ func (p LovesExportProcessor) Process(ctx context.Context, wg *sync.WaitGroup, o wg.Add(1) defer wg.Done() defer close(results) - p.Backend.ExportLoves(oldestTimestamp, results, progress) + p.Backend.ExportLoves(ctx, oldestTimestamp, results, progress) } diff --git a/internal/backends/funkwhale/funkwhale.go b/internal/backends/funkwhale/funkwhale.go index 434716f..d9632a6 100644 --- a/internal/backends/funkwhale/funkwhale.go +++ b/internal/backends/funkwhale/funkwhale.go @@ -61,8 +61,7 @@ func (b *FunkwhaleApiBackend) InitConfig(config *config.ServiceConfig) error { return nil } -func (b *FunkwhaleApiBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *FunkwhaleApiBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { page := 1 perPage := MaxItemsPerGet @@ -119,8 +118,7 @@ out: results <- models.ListensResult{Items: listens} } -func (b *FunkwhaleApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *FunkwhaleApiBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { page := 1 perPage := MaxItemsPerGet diff --git a/internal/backends/jspf/jspf.go b/internal/backends/jspf/jspf.go index 0e200f2..77fed4b 100644 --- a/internal/backends/jspf/jspf.go +++ b/internal/backends/jspf/jspf.go @@ -18,6 +18,7 @@ Scotty. If not, see . package jspf import ( + "context" "errors" "os" "sort" @@ -93,7 +94,7 @@ func (b *JSPFBackend) FinishImport() error { return b.writeJSPF() } -func (b *JSPFBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { +func (b *JSPFBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { err := b.readJSPF() p := models.TransferProgress{ Export: &models.Progress{}, @@ -132,7 +133,7 @@ func (b *JSPFBackend) ImportListens(export models.ListensResult, importResult mo return importResult, nil } -func (b *JSPFBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { +func (b *JSPFBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { err := b.readJSPF() p := models.TransferProgress{ Export: &models.Progress{}, diff --git a/internal/backends/lastfm/lastfm.go b/internal/backends/lastfm/lastfm.go index d262ada..3de75d1 100644 --- a/internal/backends/lastfm/lastfm.go +++ b/internal/backends/lastfm/lastfm.go @@ -16,6 +16,7 @@ Scotty. If not, see . package lastfm import ( + "context" "fmt" "net/url" "sort" @@ -88,7 +89,7 @@ func (b *LastfmApiBackend) OAuth2Setup(token oauth2.TokenSource) error { return nil } -func (b *LastfmApiBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { +func (b *LastfmApiBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { page := MaxPage minTime := oldestTimestamp perPage := MaxItemsPerGet @@ -102,6 +103,15 @@ func (b *LastfmApiBackend) ExportListens(oldestTimestamp time.Time, results chan out: for page > 0 { + select { + case <-ctx.Done(): + results <- models.ListensResult{Error: ctx.Err()} + p.Export.Abort() + progress <- p + return + default: + } + args := lastfm.P{ "user": b.username, "limit": MaxListensPerGet, @@ -258,7 +268,7 @@ func (b *LastfmApiBackend) ImportListens(export models.ListensResult, importResu return importResult, nil } -func (b *LastfmApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { +func (b *LastfmApiBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { // Choose a high offset, we attempt to search the loves backwards starting // at the oldest one. page := 1 @@ -274,6 +284,15 @@ func (b *LastfmApiBackend) ExportLoves(oldestTimestamp time.Time, results chan m out: for { + select { + case <-ctx.Done(): + results <- models.LovesResult{Error: ctx.Err()} + p.Export.Abort() + progress <- p + return + default: + } + result, err := b.client.User.GetLovedTracks(lastfm.P{ "user": b.username, "limit": MaxItemsPerGet, diff --git a/internal/backends/listenbrainz/listenbrainz.go b/internal/backends/listenbrainz/listenbrainz.go index 9f269a2..ca1c0f0 100644 --- a/internal/backends/listenbrainz/listenbrainz.go +++ b/internal/backends/listenbrainz/listenbrainz.go @@ -73,8 +73,7 @@ func (b *ListenBrainzApiBackend) InitConfig(config *config.ServiceConfig) error func (b *ListenBrainzApiBackend) StartImport() error { return nil } func (b *ListenBrainzApiBackend) FinishImport() error { return nil } -func (b *ListenBrainzApiBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *ListenBrainzApiBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { startTime := time.Now() minTime := oldestTimestamp if minTime.Unix() < 1 { @@ -201,8 +200,7 @@ func (b *ListenBrainzApiBackend) ImportListens(export models.ListensResult, impo return importResult, nil } -func (b *ListenBrainzApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *ListenBrainzApiBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { exportChan := make(chan models.LovesResult) p := models.TransferProgress{ Export: &models.Progress{}, diff --git a/internal/backends/maloja/maloja.go b/internal/backends/maloja/maloja.go index 4a4965e..8642924 100644 --- a/internal/backends/maloja/maloja.go +++ b/internal/backends/maloja/maloja.go @@ -64,8 +64,7 @@ func (b *MalojaApiBackend) InitConfig(config *config.ServiceConfig) error { func (b *MalojaApiBackend) StartImport() error { return nil } func (b *MalojaApiBackend) FinishImport() error { return nil } -func (b *MalojaApiBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *MalojaApiBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { page := 0 perPage := MaxItemsPerGet diff --git a/internal/backends/scrobblerlog/scrobblerlog.go b/internal/backends/scrobblerlog/scrobblerlog.go index 6454b7b..c7eb636 100644 --- a/internal/backends/scrobblerlog/scrobblerlog.go +++ b/internal/backends/scrobblerlog/scrobblerlog.go @@ -17,6 +17,7 @@ Scotty. If not, see . package scrobblerlog import ( + "context" "fmt" "os" "sort" @@ -129,7 +130,7 @@ func (b *ScrobblerLogBackend) FinishImport() error { return b.file.Close() } -func (b *ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { +func (b *ScrobblerLogBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { file, err := os.Open(b.filePath) p := models.TransferProgress{ Export: &models.Progress{}, diff --git a/internal/backends/spotify/spotify.go b/internal/backends/spotify/spotify.go index 73434b3..b00ebba 100644 --- a/internal/backends/spotify/spotify.go +++ b/internal/backends/spotify/spotify.go @@ -96,8 +96,7 @@ func (b *SpotifyApiBackend) OAuth2Setup(token oauth2.TokenSource) error { return nil } -func (b *SpotifyApiBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *SpotifyApiBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { startTime := time.Now() minTime := oldestTimestamp @@ -164,8 +163,7 @@ func (b *SpotifyApiBackend) ExportListens(oldestTimestamp time.Time, results cha progress <- p } -func (b *SpotifyApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { - ctx := context.TODO() +func (b *SpotifyApiBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { // Choose a high offset, we attempt to search the loves backwards starting // at the oldest one. offset := math.MaxInt32 diff --git a/internal/backends/spotifyhistory/spotifyhistory.go b/internal/backends/spotifyhistory/spotifyhistory.go index d5c87bb..9a1ab2b 100644 --- a/internal/backends/spotifyhistory/spotifyhistory.go +++ b/internal/backends/spotifyhistory/spotifyhistory.go @@ -18,6 +18,7 @@ Scotty. If not, see . package spotifyhistory import ( + "context" "os" "path" "path/filepath" @@ -72,7 +73,7 @@ func (b *SpotifyHistoryBackend) InitConfig(config *config.ServiceConfig) error { return nil } -func (b *SpotifyHistoryBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { +func (b *SpotifyHistoryBackend) ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.TransferProgress) { files, err := filepath.Glob(path.Join(b.dirPath, historyFileGlob)) p := models.TransferProgress{ Export: &models.Progress{}, @@ -89,11 +90,20 @@ func (b *SpotifyHistoryBackend) ExportListens(oldestTimestamp time.Time, results fileCount := int64(len(files)) p.Export.Total = fileCount for i, filePath := range files { - history, err := readHistoryFile(filePath) - if err != nil { + select { + case <-ctx.Done(): + results <- models.ListensResult{Error: ctx.Err()} p.Export.Abort() progress <- p + return + default: + } + + history, err := readHistoryFile(filePath) + if err != nil { results <- models.ListensResult{Error: err} + p.Export.Abort() + progress <- p return } listens := history.AsListenList(ListenListOptions{ diff --git a/internal/backends/subsonic/subsonic.go b/internal/backends/subsonic/subsonic.go index 2098688..aa1b1e3 100644 --- a/internal/backends/subsonic/subsonic.go +++ b/internal/backends/subsonic/subsonic.go @@ -17,6 +17,7 @@ Scotty. If not, see . package subsonic import ( + "context" "net/http" "sort" "time" @@ -63,7 +64,7 @@ func (b *SubsonicApiBackend) InitConfig(config *config.ServiceConfig) error { return nil } -func (b *SubsonicApiBackend) ExportLoves(oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { +func (b *SubsonicApiBackend) ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan models.LovesResult, progress chan models.TransferProgress) { err := b.client.Authenticate(b.password) p := models.TransferProgress{ Export: &models.Progress{}, diff --git a/internal/models/interfaces.go b/internal/models/interfaces.go index bb97dac..2b45d18 100644 --- a/internal/models/interfaces.go +++ b/internal/models/interfaces.go @@ -17,6 +17,7 @@ Scotty. If not, see . package models import ( + "context" "time" // "go.uploadedlobster.com/scotty/internal/auth" @@ -55,7 +56,7 @@ type ListensExport interface { // Returns a list of all listens newer then oldestTimestamp. // The returned list of listens is supposed to be ordered by the // Listen.ListenedAt timestamp, with the oldest entry first. - ExportListens(oldestTimestamp time.Time, results chan ListensResult, progress chan TransferProgress) + ExportListens(ctx context.Context, oldestTimestamp time.Time, results chan ListensResult, progress chan TransferProgress) } // Must be implemented by services supporting the import of listens. @@ -73,7 +74,7 @@ type LovesExport interface { // Returns a list of all loves newer then oldestTimestamp. // The returned list of listens is supposed to be ordered by the // Love.Created timestamp, with the oldest entry first. - ExportLoves(oldestTimestamp time.Time, results chan LovesResult, progress chan TransferProgress) + ExportLoves(ctx context.Context, oldestTimestamp time.Time, results chan LovesResult, progress chan TransferProgress) } // Must be implemented by services supporting the import of loves.