A music player that connects to your cloud/distributed storage.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve performance of Queue.Fill

+84 -117
+84 -117
src/Applications/UI/Queue/Fill.elm
··· 3 3 {-| These functions will return a new list for the `future` property. 4 4 -} 5 5 6 + import Array 6 7 import List.Extra as List 7 8 import Maybe.Ext as Maybe 8 9 import Maybe.Extra as Maybe ··· 39 40 40 41 41 42 ordered : Time.Posix -> List IdentifiedTrack -> State -> List Item 42 - ordered _ rawTracks state = 43 + ordered _ unfilteredTracks state = 43 44 let 44 45 tracks = 45 - purifyTracksList state.ignored rawTracks 46 + state.ignored 47 + |> List.map itemTrackId 48 + |> Tuple.pair [] 49 + |> purifier unfilteredTracks 50 + |> Tuple.first 46 51 47 52 manualEntries = 48 53 List.filter (.manualEntry >> (==) True) state.future ··· 55 60 in 56 61 case focus of 57 62 Just item -> 58 - tracks 59 - |> List.findIndex (indexFinder item.identifiedTrack) 63 + let 64 + maybeNowPlayingIndex = 65 + List.findIndex 66 + (Tracks.isNowPlaying item.identifiedTrack) 67 + tracks 68 + in 69 + maybeNowPlayingIndex 60 70 |> Maybe.map (\idx -> List.drop (idx + 1) tracks) 61 71 |> Maybe.withDefault tracks 62 72 |> List.take remaining ··· 66 76 remaining - List.length a 67 77 68 78 n = 69 - tracks 70 - |> List.findIndex (indexFinder item.identifiedTrack) 71 - |> Maybe.withDefault (List.length tracks) 79 + Maybe.withDefault (List.length tracks) maybeNowPlayingIndex 72 80 in 73 81 a ++ List.take (min n actualRemaining) tracks 74 82 ) ··· 87 95 88 96 89 97 shuffled : Time.Posix -> List IdentifiedTrack -> State -> List Item 90 - shuffled timestamp rawTracks state = 91 - -- TODO: Improve performance 98 + shuffled timestamp unfilteredTracks state = 92 99 let 100 + idsToIgnore = 101 + [ state.ignored 102 + , state.past 103 + , state.future 104 + , Maybe.unwrap [] List.singleton state.activeItem 105 + ] 106 + |> List.map (List.map itemTrackId) 107 + |> List.concat 108 + |> List.unique 109 + 93 110 tracks = 94 - purifyTracksList state.ignored rawTracks 111 + ( [], idsToIgnore ) 112 + |> purifier unfilteredTracks 113 + |> Tuple.first 114 + |> Array.fromList 95 115 96 116 amountOfTracks = 97 - List.length tracks 117 + Array.length tracks 98 118 99 119 generator = 100 120 Random.int 0 (amountOfTracks - 1) 101 121 102 - ( pastIds, futureIds, activeId ) = 103 - ( List.map itemTrackId state.past 104 - , List.map itemTrackId state.future 105 - , Maybe.map itemTrackId state.activeItem 106 - ) 107 - 108 - usedIndexes = 109 - collectIndexes 110 - tracks 111 - [ \( _, t ) -> List.member t.id pastIds 112 - , \( _, t ) -> List.member t.id futureIds 113 - , \( _, t ) -> Just t.id == activeId 114 - ] 115 - 116 - usedIndexes_ = 117 - let 118 - isUsedUp = 119 - List.length usedIndexes >= amountOfTracks 120 - 121 - hasNoFuture = 122 - List.isEmpty state.future 123 - in 124 - if isUsedUp && hasNoFuture && amountOfTracks > 1 then 125 - case amountOfTracks > 1 of 126 - True -> 127 - collectIndexes tracks [ \( _, t ) -> Just t.id == activeId ] 128 - 129 - False -> 130 - [] 131 - 132 - else 133 - usedIndexes 134 - 135 - ( toAmount, maxAmount ) = 136 - ( max (queueLength - List.length state.future) 0 137 - , max (amountOfTracks - List.length usedIndexes_) 0 138 - ) 122 + toAmount = 123 + max (queueLength - List.length state.future) 0 139 124 140 125 howMany = 141 - min toAmount maxAmount 126 + min toAmount amountOfTracks 142 127 in 143 128 if howMany > 0 then 144 129 timestamp 145 130 |> Time.posixToMillis 146 131 |> Random.initialSeed 147 - |> generateIndexes generator howMany usedIndexes_ [] 148 - |> List.map (\idx -> List.getAt idx tracks) 149 - |> Maybe.values 150 - |> List.map (makeItem False) 132 + |> generateIndexes generator howMany [] 133 + |> List.foldl 134 + (\idx acc -> 135 + case Array.get idx tracks of 136 + Just track -> 137 + makeItem False track :: acc 138 + 139 + Nothing -> 140 + acc 141 + ) 142 + [] 151 143 |> List.append state.future 152 144 153 145 else ··· 174 166 -- ㊙️ 175 167 176 168 177 - collectIndexes : List IdentifiedTrack -> List (IdentifiedTrack -> Bool) -> List Int 178 - collectIndexes tracks audits = 179 - List.indexedFoldl (collector audits) [] tracks 180 - 181 - 182 - collector : List (IdentifiedTrack -> Bool) -> Int -> IdentifiedTrack -> List Int -> List Int 183 - collector audits idx track acc = 184 - case List.foldl (auditor track) False audits of 185 - True -> 186 - idx :: acc 187 - 188 - False -> 189 - acc 190 - 191 - 192 - auditor : IdentifiedTrack -> (IdentifiedTrack -> Bool) -> Bool -> Bool 193 - auditor track audit acc = 194 - if acc == True then 195 - acc 196 - 197 - else 198 - audit track 199 - 200 - 201 169 {-| Generated random indexes. 202 170 203 171 `squirrel` = accumulator, ie. collected indexes 204 172 205 173 -} 206 - generateIndexes : Generator Int -> Int -> List Int -> List Int -> Seed -> List Int 207 - generateIndexes generator howMany usedIndexes squirrel seed = 174 + generateIndexes : Generator Int -> Int -> List Int -> Seed -> List Int 175 + generateIndexes generator howMany squirrel seed = 208 176 let 209 177 ( index, newSeed ) = 210 178 Random.step generator seed 211 179 212 180 newSquirrel = 213 - if List.member index usedIndexes then 214 - squirrel 215 - 216 - else if List.member index squirrel then 217 - squirrel 218 - 219 - else 220 - index :: squirrel 181 + -- We could check if the generated index is already one we have, 182 + -- but I don't think that ever happens (because of the use of `Random.step`) 183 + index :: squirrel 221 184 in 222 - if List.length newSquirrel < howMany then 223 - generateIndexes generator howMany usedIndexes newSquirrel newSeed 185 + if howMany - 1 > 0 then 186 + generateIndexes generator (howMany - 1) newSquirrel newSeed 224 187 225 188 else 226 189 newSquirrel ··· 230 193 -- PURIFY 231 194 232 195 233 - purifyTracksList : List Item -> List IdentifiedTrack -> List IdentifiedTrack 234 - purifyTracksList ignored tracks = 235 - let 236 - ignoredTrackIds = 237 - List.map itemTrackId ignored 238 - in 239 - tracks 240 - |> List.foldr purifyTracksListReducer ( [], ignoredTrackIds ) 241 - |> Tuple.first 242 - 196 + purifier : List IdentifiedTrack -> ( List IdentifiedTrack, List String ) -> ( List IdentifiedTrack, List String ) 197 + purifier tracks ( acc, idsToIgnore ) = 198 + case idsToIgnore of 199 + [] -> 200 + -- Nothing more to ignore, 201 + -- stop here. 202 + case acc of 203 + [] -> 204 + ( tracks, idsToIgnore ) 243 205 244 - purifyTracksListReducer : 245 - IdentifiedTrack 246 - -> ( List IdentifiedTrack, List String ) 247 - -> ( List IdentifiedTrack, List String ) 248 - purifyTracksListReducer identifiedTrack ( collection, ignored ) = 249 - let 250 - trackId = 251 - (Tuple.second >> .id) identifiedTrack 252 - in 253 - case List.findIndex ((==) trackId) ignored of 254 - Just idx -> 255 - ( collection, List.removeAt idx ignored ) 206 + _ -> 207 + ( acc, idsToIgnore ) 256 208 257 - Nothing -> 258 - ( identifiedTrack :: collection, ignored ) 209 + _ -> 210 + case tracks of 211 + [] -> 212 + -- No more tracks left, 213 + -- end of the road. 214 + ( acc, idsToIgnore ) 259 215 216 + (( _, track ) as identifiedTrack) :: rest -> 217 + case List.elemIndex track.id idsToIgnore of 218 + Just ignoreIdx -> 219 + -- It's a track to ignore, 220 + -- remove it from the ignore list and carry on. 221 + purifier 222 + rest 223 + ( acc, List.removeAt ignoreIdx idsToIgnore ) 260 224 225 + Nothing -> 226 + -- It's not a track to ignore, 227 + -- add it to the to-keep list and carry on. 228 + purifier 229 + rest 230 + ( identifiedTrack :: acc, idsToIgnore ) 261 231 262 - -- COMMON 263 232 264 233 265 - indexFinder : IdentifiedTrack -> IdentifiedTrack -> Bool 266 - indexFinder = 267 - Tracks.isNowPlaying 234 + -- COMMON 268 235 269 236 270 237 itemTrackId : Item -> String