@@ -6,8 +6,11 @@ import (
66 "github.com/47-11/spotifete/database/model"
77 . "github.com/47-11/spotifete/shared"
88 "github.com/47-11/spotifete/users"
9+ "github.com/google/logger"
910 "github.com/zmb3/spotify"
11+ "math/rand"
1012 "net/http"
13+ "time"
1114)
1215
1316func ChangeFallbackPlaylist (session model.SimpleListeningSession , user model.SimpleUser , playlistId string ) * SpotifeteError {
@@ -38,6 +41,22 @@ func RemoveFallbackPlaylist(session model.SimpleListeningSession, user model.Sim
3841 return nil
3942}
4043
44+ func SetFallbackPlaylistShuffle (session model.SimpleListeningSession , user model.SimpleUser , shuffle bool ) * SpotifeteError {
45+ if user .ID != session .OwnerId {
46+ return NewUserError ("Only the session owner can change the shuffle mode." )
47+ }
48+
49+ if shuffle == session .FallbackPlaylistShuffle {
50+ return nil
51+ }
52+
53+ session .FallbackPlaylistShuffle = shuffle
54+
55+ database .GetConnection ().Model (& session ).Update ("fallback_playlist_shuffle" , shuffle )
56+
57+ return nil
58+ }
59+
4160func addFallbackTrackIfNecessary (session model.FullListeningSession , upNextRequest * model.SongRequest ) (trackAdded bool , error * SpotifeteError ) {
4261 if session .FallbackPlaylistId == nil {
4362 return false , nil
@@ -70,51 +89,29 @@ func addFallbackTrack(session model.FullListeningSession) (error *SpotifeteError
7089}
7190
7291func findNextFallbackTrack (session model.FullListeningSession ) (nextFallbackTrackId string , spotifeteError * SpotifeteError ) {
73-
74- client := Client (session )
75- currentUser , err := client .CurrentUser ()
76- if err != nil {
77- return "" , NewError ("Could not get user information on session owner from Spotify." , err , http .StatusInternalServerError )
92+ playableTracks , spotifeteError := getPlayablePlaylistTracks (* session .FallbackPlaylistId , session .Owner )
93+ if spotifeteError != nil {
94+ return "" , spotifeteError
7895 }
79- country := currentUser .Country
80-
81- currentlyPlayingRequest := GetCurrentlyPlayingRequest (session .SimpleListeningSession )
82-
83- var playableTracks []spotify.FullTrack
84- offset := 0
85- allTracksLoaded := false
86- for ! allTracksLoaded {
87- newPage , err := client .GetPlaylistTracksOpt (spotify .ID (* session .FallbackPlaylistId ), & spotify.Options {Country : & country , Offset : & offset }, "" )
88- if err != nil {
89- return "" , NewError ("Could not get tracks in fallback playlist from Spotify." , err , http .StatusInternalServerError )
90- }
9196
92- newPlayableTracks := filterPlayableTracksFromPlaylistTracks (newPage .Tracks )
93- fallbackTrack := findPossibleFallbackTrackFromPlayableTracks (newPlayableTracks , session .SimpleListeningSession , currentlyPlayingRequest , 0 )
94- if fallbackTrack != nil {
95- return * fallbackTrack , nil
96- }
97-
98- playableTracks = append (playableTracks , newPlayableTracks ... )
99- offset += newPage .Limit
100- allTracksLoaded = offset == newPage .Total
97+ if len (* playableTracks ) >= 0 {
98+ return doFindNextFallbackTrack (playableTracks , session )
10199 }
102100
103- return doFindNextFallbackTrack (playableTracks , session , currentlyPlayingRequest )
104- }
105-
106- func doFindNextFallbackTrack (playableTracks []spotify.FullTrack , session model.FullListeningSession , currentlyPlayingRequest * model.SongRequest ) (nextFallbackTrackId string , spotifeteError * SpotifeteError ) {
107- if len (playableTracks ) == 0 {
108- fallbackPlaylistId := * session .FallbackPlaylistId
101+ session .FallbackPlaylistId = nil
102+ database .GetConnection ().Save (session )
109103
110- session .FallbackPlaylistId = nil
111- database .GetConnection ().Save (session )
104+ logger .Info (fmt .Sprintf ("Fallback playlist (%s) for session %d does not contain any playable tracks. Removing fallback playlist." ,
105+ * session .FallbackPlaylistId ,
106+ session .ID ))
107+ return "" , NewUserError ("Fallback playlist does not contain any playable tracks." )
108+ }
112109
113- return "" , NewInternalError ( fmt . Sprintf ( "Fallback playlist (%s) for session %d does not contain any playable tracks. Removing fallback playlist." , fallbackPlaylistId , session . ID ), nil )
114- }
110+ func doFindNextFallbackTrack ( playableTracks * []spotify. FullTrack , session model. FullListeningSession ) ( nextFallbackTrackId string , spotifeteError * SpotifeteError ) {
111+ currentlyPlayingRequest := GetCurrentlyPlayingRequest ( session . SimpleListeningSession )
115112
116113 for i := 0 ; i < 10_000 ; i ++ {
117- fallbackTrack := findPossibleFallbackTrackFromPlayableTracks (playableTracks , session .SimpleListeningSession , currentlyPlayingRequest , 0 )
114+ fallbackTrack := findPossibleFallbackTrackFromPlayableTracks (* playableTracks , session .SimpleListeningSession , currentlyPlayingRequest , 0 )
118115 if fallbackTrack != nil {
119116 return * fallbackTrack , nil
120117 }
@@ -126,21 +123,18 @@ func doFindNextFallbackTrack(playableTracks []spotify.FullTrack, session model.F
126123 return "" , NewInternalError (fmt .Sprintf ("No track found in fallback playlist for session %d that has been played less than 10,000 times. Aborting and removing fallback playlist." , session .ID ), nil )
127124}
128125
129- func filterPlayableTracksFromPlaylistTracks (playlistTracks []spotify.PlaylistTrack ) (playableTracks []spotify.FullTrack ) {
130- for _ , playlistTrack := range playlistTracks {
131- track := playlistTrack .Track
132- if track .IsPlayable != nil && * track .IsPlayable {
133- playableTracks = append (playableTracks , track )
134- }
126+ func findPossibleFallbackTrackFromPlayableTracks (playableTracks []spotify.FullTrack , session model.SimpleListeningSession , currentlyPlayingRequest * model.SongRequest , maximumPlays int64 ) (possibleFallbackTrackId * string ) {
127+ if session .FallbackPlaylistShuffle {
128+ rand .Seed (time .Now ().UnixNano ())
129+ rand .Shuffle (
130+ len (playableTracks ),
131+ func (i , j int ) {
132+ playableTracks [i ], playableTracks [j ] = playableTracks [j ], playableTracks [i ]
133+ })
135134 }
136135
137- return playableTracks
138- }
139-
140- func findPossibleFallbackTrackFromPlayableTracks (playableTracks []spotify.FullTrack , session model.SimpleListeningSession , currentlyPlayingRequest * model.SongRequest , maximumPlays int64 ) (possibleFallbackTrackId * string ) {
141- // TODO: Maybe we could choose a random track? To do that we could just filter all tracks in the current page first and then choose a random one
142- for _ , playableTrack := range playableTracks {
143- trackId := playableTrack .ID .String ()
136+ for _ , track := range playableTracks {
137+ trackId := track .ID .String ()
144138 if currentlyPlayingRequest == nil || currentlyPlayingRequest .SpotifyTrackId != trackId {
145139 playCount := getTrackPlayCount (session , trackId )
146140
0 commit comments