From 46895a5c50b0bf43ea15aee2b990424cc68d100d Mon Sep 17 00:00:00 2001 From: streambinder Date: Fri, 6 Sep 2024 17:52:37 +0200 Subject: [PATCH] feat: introduce --library-limit flag --- cmd/lookup.go | 4 +++- cmd/lookup_test.go | 12 ++++++------ cmd/sync.go | 8 +++++--- cmd/sync_test.go | 20 ++++++++++---------- spotify/library.go | 6 +++++- spotify/library_test.go | 8 ++++---- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/cmd/lookup.go b/cmd/lookup.go index e5f6908..ef0944f 100644 --- a/cmd/lookup.go +++ b/cmd/lookup.go @@ -33,6 +33,7 @@ func cmdLookup() *cobra.Command { library, _ := cmd.Flags().GetBool("library") random, _ := cmd.Flags().GetBool("random") randomSize, _ := cmd.Flags().GetInt("random-size") + libraryLimit, _ := cmd.Flags().GetInt("library-limit") if !library && !random && len(args) == 0 { return errors.New("no track has been issued") } @@ -56,7 +57,7 @@ func cmdLookup() *cobra.Command { return } } else if library { - if err := client.Library(providerChannel, lyricsChannel); err != nil { + if err := client.Library(libraryLimit, providerChannel, lyricsChannel); err != nil { ch <- err return } @@ -103,5 +104,6 @@ func cmdLookup() *cobra.Command { cmd.Flags().BoolP("library", "l", false, "Lookup personal library tracks") cmd.Flags().BoolP("random", "r", false, "Lookup random tracks") cmd.Flags().Int("random-size", defaultRandomSize, "Number of random tracks to load") + cmd.Flags().Int("library-limit", 0, "Number of tracks to fetch from library (unlimited if 0)") return cmd } diff --git a/cmd/lookup_test.go b/cmd/lookup_test.go index b3ed019..701fdb5 100644 --- a/cmd/lookup_test.go +++ b/cmd/lookup_test.go @@ -27,7 +27,7 @@ func TestCmdLookup(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track ch[1] <- _track return nil @@ -110,7 +110,7 @@ func TestCmdLookupLibraryFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { return errors.New("ko") }). Reset() @@ -155,7 +155,7 @@ func TestCmdLookupSearchFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track ch[1] <- _track return nil @@ -180,7 +180,7 @@ func TestCmdLookupSearchNotFound(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track ch[1] <- _track return nil @@ -205,7 +205,7 @@ func TestCmdLookupLyricsFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track ch[1] <- _track return nil @@ -230,7 +230,7 @@ func TestCmdLookupLyricsNotFound(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track ch[1] <- _track return nil diff --git a/cmd/sync.go b/cmd/sync.go index cd02ae6..7c8118d 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -65,6 +65,7 @@ func cmdSync() *cobra.Command { albums, _ = cmd.Flags().GetStringArray("album") tracks, _ = cmd.Flags().GetStringArray("track") fixes, _ = cmd.Flags().GetStringArray("fix") + libraryLimit, _ = cmd.Flags().GetInt("library-limit") ) for index, path := range fixes { @@ -80,7 +81,7 @@ func cmdSync() *cobra.Command { return nursery.RunConcurrently( routineIndex, routineAuth, - routineFetch(library, playlists, playlistsTracks, albums, tracks, fixes), + routineFetch(library, playlists, playlistsTracks, albums, tracks, fixes, libraryLimit), routineDecide(manual), routineCollect, routineProcess, @@ -127,6 +128,7 @@ func cmdSync() *cobra.Command { cmd.Flags().StringArrayP("album", "a", []string{}, "Synchronize album") cmd.Flags().StringArrayP("track", "t", []string{}, "Synchronize track") cmd.Flags().StringArrayP("fix", "f", []string{}, "Fix local track") + cmd.Flags().Int("library-limit", 0, "Number of tracks to fetch from library (unlimited if 0)") return cmd } @@ -170,7 +172,7 @@ func routineAuth(ctx context.Context, ch chan error) { // fetcher pulls data from the upstream // provider, i.e. Spotify -func routineFetch(library bool, playlists, playlistsTracks, albums, tracks, fixes []string) func(ctx context.Context, ch chan error) { +func routineFetch(library bool, playlists, playlistsTracks, albums, tracks, fixes []string, libraryLimit int) func(ctx context.Context, ch chan error) { return func(ctx context.Context, ch chan error) { // remember to stop passing data to decider and mixer defer close(routineQueues[routineTypeDecide]) @@ -197,7 +199,7 @@ func routineFetch(library bool, playlists, playlistsTracks, albums, tracks, fixe if library { tui.Lot("fetch").Printf("library") - if err := spotifyClient.Library(routineQueues[routineTypeDecide], fetched); err != nil { + if err := spotifyClient.Library(libraryLimit, routineQueues[routineTypeDecide], fetched); err != nil { ch <- err return } diff --git a/cmd/sync_test.go b/cmd/sync_test.go index 35a2ef6..eea1696 100644 --- a/cmd/sync_test.go +++ b/cmd/sync_test.go @@ -52,7 +52,7 @@ func TestCmdSync(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { for _, c := range ch { c <- _track c <- _track // to trigger duplicate check @@ -132,7 +132,7 @@ func TestCmdSyncOfflineIndex(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -409,7 +409,7 @@ func TestCmdSyncDecideManual(t *testing.T) { return &spotify.Client{}, nil }). ApplyMethod(&spotify.Client{}, "Library", - func(_ *spotify.Client, ch ...chan interface{}) error { + func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -437,7 +437,7 @@ func TestCmdSyncDecideFailure(t *testing.T) { return &spotify.Client{}, nil }). ApplyMethod(&spotify.Client{}, "Library", - func(_ *spotify.Client, ch ...chan interface{}) error { + func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -468,7 +468,7 @@ func TestCmdSyncDecideNotFound(t *testing.T) { return &spotify.Client{}, nil }). ApplyMethod(&spotify.Client{}, "Library", - func(_ *spotify.Client, ch ...chan interface{}) error { + func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -499,7 +499,7 @@ func TestCmdSyncCollectFailure(t *testing.T) { return &spotify.Client{}, nil }). ApplyMethod(&spotify.Client{}, "Library", - func(_ *spotify.Client, ch ...chan interface{}) error { + func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -541,7 +541,7 @@ func TestCmdSyncDownloadFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -580,7 +580,7 @@ func TestCmdSyncLyricsFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -619,7 +619,7 @@ func TestCmdSyncProcessorFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). @@ -661,7 +661,7 @@ func TestCmdSyncInstallerFailure(t *testing.T) { ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) { return &spotify.Client{}, nil }). - ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, ch ...chan interface{}) error { + ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error { ch[0] <- _track return nil }). diff --git a/spotify/library.go b/spotify/library.go index 70d1ba5..7d33ec9 100644 --- a/spotify/library.go +++ b/spotify/library.go @@ -7,7 +7,7 @@ import ( "github.com/zmb3/spotify/v2" ) -func (client *Client) Library(channels ...chan interface{}) error { +func (client *Client) Library(limit int, channels ...chan interface{}) error { var ( ctx = context.Background() library, err = client.CurrentUsersTracks(ctx) @@ -16,12 +16,16 @@ func (client *Client) Library(channels ...chan interface{}) error { return err } + ctr := 0 for { for _, libraryTrack := range library.Tracks { track := trackEntity(&libraryTrack.FullTrack) for _, ch := range channels { ch <- track } + if ctr++; limit > 0 && ctr >= limit { + return nil + } } if err := client.NextPage(ctx, library); errors.Is(err, spotify.ErrNoMorePages) { diff --git a/spotify/library_test.go b/spotify/library_test.go index 9f13020..5b1bb57 100644 --- a/spotify/library_test.go +++ b/spotify/library_test.go @@ -35,7 +35,7 @@ func TestLibrary(t *testing.T) { Reset() // testing - assert.Nil(t, testClient().Library()) + assert.Nil(t, testClient().Library(0)) } func TestLibraryChannel(t *testing.T) { @@ -50,7 +50,7 @@ func TestLibraryChannel(t *testing.T) { // testing channel := make(chan interface{}, 1) defer close(channel) - err := testClient().Library(channel) + err := testClient().Library(1, channel) assert.Nil(t, err) assert.Equal(t, library.Tracks[0].Name, ((<-channel).(*entity.Track)).Title) } @@ -65,7 +65,7 @@ func TestLibraryFailure(t *testing.T) { Reset() // testing - assert.EqualError(t, util.ErrOnly(testClient().Library()), "ko") + assert.EqualError(t, util.ErrOnly(testClient().Library(0)), "ko") } func TestLibraryNextPageFailure(t *testing.T) { @@ -84,5 +84,5 @@ func TestLibraryNextPageFailure(t *testing.T) { Reset() // testing - assert.True(t, errors.Is(util.ErrOnly(client.Library()), syscall.ECONNREFUSED)) + assert.True(t, errors.Is(util.ErrOnly(client.Library(0)), syscall.ECONNREFUSED)) }