A music player that connects to your cloud/distributed storage.
at main 6.5 kB view raw
1module UI.Queue.Fill exposing (State, cleanAutoGenerated, ordered, queueLength, shuffled) 2 3{-| These functions will return a new list for the `future` property. 4-} 5 6import Array 7import List.Extra as List 8import Maybe.Ext as Maybe 9import Maybe.Extra as Maybe 10import Queue exposing (Item, makeItem) 11import Random exposing (Generator, Seed) 12import Time 13import Tracks exposing (IdentifiedTrack) 14 15 16 17-- ⛩ 18 19 20queueLength : Int 21queueLength = 22 30 23 24 25 26-- 🌳 27 28 29type alias State = 30 { activeItem : Maybe Item 31 , future : List Item 32 , ignored : List Item 33 , past : List Item 34 } 35 36 37 38-- 🔱 ░░ ORDERED 39 40 41ordered : Time.Posix -> List IdentifiedTrack -> State -> List Item 42ordered _ unfilteredTracks state = 43 let 44 tracks = 45 state.ignored 46 |> List.map itemTrackId 47 |> Tuple.pair [] 48 |> purifier unfilteredTracks 49 |> Tuple.first 50 51 manualEntries = 52 List.filter (.manualEntry >> (==) True) state.future 53 54 remaining = 55 max (queueLength - List.length manualEntries) 0 56 57 focus = 58 Maybe.preferFirst (List.last manualEntries) state.activeItem 59 in 60 case focus of 61 Just item -> 62 let 63 maybeNowPlayingIndex = 64 List.findIndex 65 (Tracks.isNowPlaying item.identifiedTrack) 66 tracks 67 in 68 maybeNowPlayingIndex 69 |> Maybe.map (\idx -> List.drop (idx + 1) tracks) 70 |> Maybe.withDefault tracks 71 |> List.take remaining 72 |> (\a -> 73 let 74 actualRemaining = 75 remaining - List.length a 76 77 n = 78 Maybe.withDefault (List.length tracks) maybeNowPlayingIndex 79 in 80 a ++ List.take (min n actualRemaining) tracks 81 ) 82 |> List.map (makeItem False) 83 |> List.append manualEntries 84 85 Nothing -> 86 tracks 87 |> List.take remaining 88 |> List.map (makeItem False) 89 |> List.append manualEntries 90 91 92 93-- 🔱 ░░ SHUFFLED 94 95 96shuffled : Time.Posix -> List IdentifiedTrack -> State -> List Item 97shuffled timestamp unfilteredTracks state = 98 let 99 idsToIgnoreWithoutPast = 100 [ state.ignored 101 , Maybe.unwrap [] List.singleton state.activeItem 102 ] 103 |> List.map (List.map itemTrackId) 104 |> List.concat 105 |> List.unique 106 107 ( tracksWithPast, idsToIgnoreWithoutPastAfterFilter ) = 108 purifier unfilteredTracks ( [], idsToIgnoreWithoutPast ) 109 110 idsToIgnoreWithPast = 111 List.unique (idsToIgnoreWithoutPastAfterFilter ++ List.map itemTrackId state.past) 112 113 ( tracksWithoutPast, idsToIgnoreWithPastAfterFilter ) = 114 purifier tracksWithPast ( [], idsToIgnoreWithPast ) 115 116 idsToIgnoreWithFuture = 117 List.unique (idsToIgnoreWithoutPastAfterFilter ++ List.map itemTrackId state.future) 118 119 ( tracksList, _ ) = 120 purifier 121 (case tracksWithoutPast of 122 [] -> 123 tracksWithPast 124 125 t -> 126 t 127 ) 128 ( [], idsToIgnoreWithFuture ) 129 130 tracks = 131 Array.fromList tracksList 132 133 amountOfTracks = 134 Array.length tracks 135 136 generator = 137 Random.int 0 (amountOfTracks - 1) 138 139 toAmount = 140 max (queueLength - List.length state.future) 0 141 142 howMany = 143 min toAmount amountOfTracks 144 in 145 if howMany > 0 then 146 timestamp 147 |> Time.posixToMillis 148 |> Random.initialSeed 149 |> generateIndexes generator howMany [] 150 |> List.foldl 151 (\idx acc -> 152 case Array.get idx tracks of 153 Just track -> 154 makeItem False track :: acc 155 156 Nothing -> 157 acc 158 ) 159 [] 160 |> List.append state.future 161 162 else 163 state.future 164 165 166 167-- 🔱 168 169 170cleanAutoGenerated : Bool -> String -> List Item -> List Item 171cleanAutoGenerated shuffle trackId future = 172 if shuffle then 173 List.filterNot 174 (\i -> i.manualEntry == False && itemTrackId i == trackId) 175 future 176 177 else 178 future 179 180 181 182-- ㊙️ 183 184 185{-| Generated random indexes. 186 187 `squirrel` = accumulator, ie. collected indexes 188 189-} 190generateIndexes : Generator Int -> Int -> List Int -> Seed -> List Int 191generateIndexes generator howMany squirrel seed = 192 let 193 ( index, newSeed ) = 194 Random.step generator seed 195 in 196 if List.member index squirrel then 197 generateIndexes generator howMany squirrel newSeed 198 199 else if howMany - 1 > 0 then 200 generateIndexes generator (howMany - 1) (index :: squirrel) newSeed 201 202 else 203 index :: squirrel 204 205 206 207-- PURIFY 208 209 210purifier : 211 List IdentifiedTrack 212 -> ( List IdentifiedTrack, List String ) 213 -> ( List IdentifiedTrack, List String ) 214purifier tracks ( acc, idsToIgnore ) = 215 case idsToIgnore of 216 [] -> 217 -- Nothing more to ignore, 218 -- stop here. 219 ( acc ++ tracks, [] ) 220 221 _ -> 222 case tracks of 223 [] -> 224 -- No more tracks left, 225 -- end of the road. 226 ( acc, idsToIgnore ) 227 228 (( _, track ) as identifiedTrack) :: rest -> 229 case List.elemIndex track.id idsToIgnore of 230 Just ignoreIdx -> 231 -- It's a track to ignore, 232 -- remove it from the ignore list and carry on. 233 purifier 234 rest 235 ( acc, List.removeAt ignoreIdx idsToIgnore ) 236 237 Nothing -> 238 -- It's not a track to ignore, 239 -- add it to the to-keep list and carry on. 240 purifier 241 rest 242 ( identifiedTrack :: acc, idsToIgnore ) 243 244 245 246-- COMMON 247 248 249itemTrackId : Item -> String 250itemTrackId = 251 .identifiedTrack >> Tuple.second >> .id