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

Configure Feed

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

fix: Auto-generated playlists with sources which specify sub directory

+138 -103
+5 -3
src/Core/Themes/Sunrise/Playlists/View.elm
··· 9 9 import List.Extra as List 10 10 import Material.Icons.Round as Icons 11 11 import Material.Icons.Types exposing (Coloring(..)) 12 + import Maybe.Extra as Maybe 12 13 import Playlists exposing (..) 13 14 import Themes.Sunrise.Kit as Kit exposing (ButtonType(..)) 14 15 import Themes.Sunrise.List ··· 33 34 let 34 35 filtered = 35 36 List.filter 36 - (.autoGenerated >> (==) False) 37 + (.autoGenerated >> Maybe.isNothing) 37 38 playlists 38 39 in 39 40 encodedName ··· 62 63 63 64 customPlaylists = 64 65 playlists 65 - |> List.filterNot .autoGenerated 66 + |> List.filterNot (.autoGenerated >> Maybe.isJust) 66 67 |> List.sortBy lowercaseName 67 68 68 69 customPlaylistListItem playlist = ··· 105 106 106 107 directoryPlaylists = 107 108 playlists 108 - |> List.filter .autoGenerated 109 + |> List.filter (.autoGenerated >> Maybe.isJust) 109 110 |> List.sortBy lowercaseName 111 + |> List.uniqueBy .name 110 112 111 113 directoryPlaylistListItem playlist = 112 114 if isSelected playlist then
+6 -6
src/Core/Themes/Sunrise/Tracks/View.elm
··· 108 108 109 109 List -> 110 110 model.selectedPlaylist 111 - |> Maybe.map .autoGenerated 112 111 |> Maybe.andThen 113 - (\bool -> 114 - if bool then 115 - Nothing 112 + (\playlist -> 113 + case playlist.autoGenerated of 114 + Just _ -> 115 + Nothing 116 116 117 - else 118 - Just model.dnd 117 + Nothing -> 118 + Just model.dnd 119 119 ) 120 120 |> Themes.Sunrise.Tracks.Scene.List.view 121 121 { bgColor = model.extractedBackdropColor
+2 -2
src/Core/UI/Commands/Alfred.elm
··· 222 222 viewCommands model = 223 223 let 224 224 sortCommands = 225 - (case Maybe.map .autoGenerated model.selectedPlaylist of 226 - Just False -> 225 + (case Maybe.andThen .autoGenerated model.selectedPlaylist of 226 + Nothing -> 227 227 [] 228 228 229 229 _ ->
+2 -1
src/Core/UI/Common/State.elm
··· 5 5 import ContextMenu exposing (ContextMenu) 6 6 import Debouncer.Basic as Debouncer exposing (Debouncer) 7 7 import List.Extra as List 8 + import Maybe.Extra as Maybe 8 9 import Monocle.Lens as Lens exposing (Lens) 9 10 import Notifications exposing (Notification) 10 11 import Return exposing (return) ··· 82 83 let 83 84 nonDirectoryPlaylists = 84 85 List.filterNot 85 - .autoGenerated 86 + (.autoGenerated >> Maybe.isJust) 86 87 model.playlists 87 88 88 89 directoryPlaylists =
+8 -1
src/Core/UI/Playlists/Alfred.elm
··· 106 106 makeIndex playlists = 107 107 playlists 108 108 |> Dict.groupBy 109 - (\p -> ifThenElse p.autoGenerated "AutoGenerated Directory Playlists" "Your Playlists") 109 + (\p -> 110 + case p.autoGenerated of 111 + Just _ -> 112 + "AutoGenerated Directory Playlists" 113 + 114 + Nothing -> 115 + "Your Playlists" 116 + ) 110 117 |> Dict.toList 111 118 |> List.reverse 112 119 |> List.map
+36 -33
src/Core/UI/Playlists/ContextMenu.elm
··· 24 24 listMenu playlist allTracks confirmation coordinates = 25 25 let 26 26 identifiedTracksFromPlaylist = 27 - if playlist.autoGenerated then 28 - List.filter 29 - (Tuple.second >> Tracks.matchesAutoGeneratedPlaylist playlist) 30 - allTracks 27 + case playlist.autoGenerated of 28 + Just _ -> 29 + List.filter 30 + (Tuple.second >> Tracks.matchesAutoGeneratedPlaylist playlist) 31 + allTracks 31 32 32 - else 33 - allTracks 34 - |> Playlists.Matching.match playlist 35 - |> Tuple.first 33 + Nothing -> 34 + allTracks 35 + |> Playlists.Matching.match playlist 36 + |> Tuple.first 36 37 37 38 tracksFromPlaylist = 38 - if playlist.autoGenerated then 39 - identifiedTracksFromPlaylist 40 - |> Tracks.Sorting.sort Album Asc 41 - |> List.map Tuple.second 39 + case playlist.autoGenerated of 40 + Just _ -> 41 + identifiedTracksFromPlaylist 42 + |> Tracks.Sorting.sort Album Asc 43 + |> List.map Tuple.second 42 44 43 - else 44 - identifiedTracksFromPlaylist 45 - |> List.sortBy (\( i, t ) -> Maybe.withDefault (t.tags.disc * 1000 + t.tags.nr) i.indexInPlaylist) 46 - |> List.map Tuple.second 45 + Nothing -> 46 + identifiedTracksFromPlaylist 47 + |> List.sortBy (\( i, t ) -> Maybe.withDefault (t.tags.disc * 1000 + t.tags.nr) i.indexInPlaylist) 48 + |> List.map Tuple.second 47 49 48 50 menuMsg = 49 51 ShowPlaylistListMenu ··· 56 58 , screenPos = ( 0, 0 ) 57 59 } 58 60 in 59 - if playlist.autoGenerated then 60 - ContextMenu 61 - [ addToQueue identifiedTracksFromPlaylist 62 - , convertToRegularPlaylist tracksFromPlaylist playlist 63 - , downloadAsZip tracksFromPlaylist playlist 64 - , storeInCache tracksFromPlaylist 65 - ] 66 - coordinates 61 + case playlist.autoGenerated of 62 + Just _ -> 63 + ContextMenu 64 + [ addToQueue identifiedTracksFromPlaylist 65 + , convertToRegularPlaylist tracksFromPlaylist playlist 66 + , downloadAsZip tracksFromPlaylist playlist 67 + , storeInCache tracksFromPlaylist 68 + ] 69 + coordinates 67 70 68 - else 69 - ContextMenu 70 - [ addToQueue identifiedTracksFromPlaylist 71 - , downloadAsZip tracksFromPlaylist playlist 72 - , removePlaylist menuMsg confirmation playlist 73 - , renamePlaylist playlist 74 - , storeInCache tracksFromPlaylist 75 - ] 76 - coordinates 71 + Nothing -> 72 + ContextMenu 73 + [ addToQueue identifiedTracksFromPlaylist 74 + , downloadAsZip tracksFromPlaylist playlist 75 + , removePlaylist menuMsg confirmation playlist 76 + , renamePlaylist playlist 77 + , storeInCache tracksFromPlaylist 78 + ] 79 + coordinates 77 80 78 81 79 82
+16 -13
src/Core/UI/Playlists/Directory.elm
··· 6 6 import Sources exposing (Source) 7 7 import String.Ext as String 8 8 import Tracks exposing (Track) 9 - 9 + import List.Extra as List 10 10 11 11 12 12 -- 🔱 ··· 39 39 in 40 40 playlistNames 41 41 |> Set.toList 42 - |> List.filter 43 - (\n -> 44 - case n of 45 - "" -> 46 - False 47 - 48 - _ -> 49 - True 50 - ) 51 42 |> List.map 52 43 (\n -> 53 - { autoGenerated = True 54 - , name = n 44 + let 45 + s = 46 + String.split "/" n 47 + in 48 + { autoGenerated = Just { level = List.length s - 1 } 49 + , name = Maybe.withDefault n (List.last s) 55 50 , public = False 56 51 , tracks = [] 57 52 } ··· 84 79 String.dropLeft (String.length prefix) track.path 85 80 in 86 81 case String.split "/" path of 82 + "" :: _ :: _ -> 83 + identity 84 + 87 85 a :: _ :: _ -> 88 - Set.insert a 86 + case prefix of 87 + "" -> 88 + Set.insert a 89 + 90 + _ -> 91 + Set.insert (prefix ++ "/" ++ a) 89 92 90 93 _ -> 91 94 identity
+10 -9
src/Core/UI/Playlists/State.elm
··· 5 5 import Html.Events.Extra.Mouse as Mouse 6 6 import List.Ext as List 7 7 import List.Extra as List 8 + import Maybe.Extra as Maybe 8 9 import Notifications 9 10 import Playlists exposing (..) 10 11 import Return exposing (andThen) ··· 40 41 41 42 playlistIndex = 42 43 List.findIndex 43 - (\p -> p.autoGenerated == False && p.name == properPlaylistName) 44 + (\p -> Maybe.isNothing p.autoGenerated && p.name == properPlaylistName) 44 45 model.playlists 45 46 46 47 newCollection = ··· 52 53 model.playlists 53 54 54 55 Nothing -> 55 - { autoGenerated = False 56 + { autoGenerated = Nothing 56 57 , name = properPlaylistName 57 58 , public = False 58 59 , tracks = tracks ··· 81 82 assistWithAddingTracksToPlaylist : List IdentifiedTrack -> Manager 82 83 assistWithAddingTracksToPlaylist tracks model = 83 84 model.playlists 84 - |> List.filterNot .autoGenerated 85 + |> List.filterNot (.autoGenerated >> Maybe.isJust) 85 86 |> UI.Playlists.Alfred.create tracks 86 87 |> (\a -> Alfred.assign a model) 87 88 ··· 101 102 alreadyExists = 102 103 List.any 103 104 (.name >> (==) playlistName) 104 - (List.filterNot .autoGenerated model.playlists) 105 + (List.filterNot (.autoGenerated >> Maybe.isJust) model.playlists) 105 106 106 107 playlist = 107 - { autoGenerated = False 108 + { autoGenerated = Nothing 108 109 , name = playlistName 109 110 , public = False 110 111 , tracks = [] ··· 149 150 model.selectedPlaylist 150 151 151 152 ( selectedPlaylistChanged, newSelectedPlaylist ) = 152 - if selectedPlaylist == Just ( False, playlistName ) then 153 + if selectedPlaylist == Just ( Nothing, playlistName ) then 153 154 ( True, Nothing ) 154 155 155 156 else ··· 158 159 model.playlists 159 160 |> List.filter 160 161 (\p -> 161 - if p.autoGenerated then 162 + if Maybe.isJust p.autoGenerated then 162 163 True 163 164 164 165 else ··· 191 192 String.isEmpty properName == False 192 193 193 194 ( autoGenerated, notAutoGenerated ) = 194 - List.partition .autoGenerated model.playlists 195 + List.partition (.autoGenerated >> Maybe.isJust) model.playlists 195 196 196 197 alreadyExists = 197 198 List.any ··· 243 244 List.map 244 245 (\p -> 245 246 ifThenElse 246 - (p.autoGenerated == False && p.name == updatedPlaylist.name) 247 + (p.autoGenerated == Nothing && p.name == updatedPlaylist.name) 247 248 updatedPlaylist 248 249 p 249 250 )
+8 -1
src/Core/UI/Tracks/ContextMenu.elm
··· 160 160 let 161 161 maybeCustomPlaylist = 162 162 Maybe.andThen 163 - (\p -> ifThenElse p.autoGenerated Nothing (Just p)) 163 + (\p -> 164 + case p.autoGenerated of 165 + Just _ -> 166 + Nothing 167 + 168 + Nothing -> 169 + Just p 170 + ) 164 171 selectedPlaylist 165 172 166 173 maybeAddToLastModifiedPlaylist =
+3 -2
src/Core/UI/User/State/Export.elm
··· 4 4 import File.Download 5 5 import Json.Encode 6 6 import List.Extra as List 7 + import Maybe.Extra as Maybe exposing (isJust) 7 8 import Playlists.Encoding as Playlists 8 9 import Return exposing (return) 9 10 import Settings exposing (Settings) ··· 20 21 21 22 export model = 22 23 { favourites = model.favourites 23 - , playlists = List.filterNot .autoGenerated model.playlists 24 + , playlists = List.filterNot (.autoGenerated >> Maybe.isJust) model.playlists 24 25 , progress = model.progress 25 26 , settings = Just (gatherSettings model) 26 27 , sources = model.sources ··· 91 92 savePlaylists : Manager 92 93 savePlaylists model = 93 94 model.playlists 94 - |> List.filterNot .autoGenerated 95 + |> List.filterNot (.autoGenerated >> Maybe.isJust) 95 96 |> Json.Encode.list Playlists.encode 96 97 |> Alien.broadcast Alien.SavePlaylists 97 98 |> Ports.toBrain
+1 -1
src/Library/Playlists.elm
··· 4 4 5 5 6 6 type alias Playlist = 7 - { autoGenerated : Bool 7 + { autoGenerated : Maybe { level : Int } 8 8 , name : String 9 9 , public : Bool 10 10 , tracks : List PlaylistTrack
+11 -2
src/Library/Playlists/Encoding.elm
··· 4 4 import Json.Decode.Ext as Decode 5 5 import Json.Encode as Encode 6 6 import Json.Encode.Ext exposing (..) 7 + import Maybe.Extra as Maybe exposing (isJust) 7 8 import Playlists exposing (..) 8 9 9 10 ··· 14 15 encode : Playlist -> Encode.Value 15 16 encode playlist = 16 17 Encode.object 17 - [ ( "autoGenerated", Encode.bool playlist.autoGenerated ) 18 + [ ( "autoGenerated" 19 + , case playlist.autoGenerated of 20 + Just { level } -> 21 + Encode.object 22 + [ ( "level", Encode.int level ) ] 23 + 24 + Nothing -> 25 + Encode.null 26 + ) 18 27 , ( "name", Encode.string playlist.name ) 19 28 , ( "public", Encode.bool playlist.public ) 20 29 , ( "tracks", Encode.list encodePlaylistTrack playlist.tracks ) ··· 37 46 decoder : Decode.Decoder Playlist 38 47 decoder = 39 48 Decode.map4 Playlist 40 - (Decode.field "autoGenerated" Decode.bool) 49 + (Decode.field "autoGenerated" <| Decode.maybe <| Decode.map (\l -> { level = l }) <| Decode.field "level" Decode.int) 41 50 (Decode.field "name" Decode.string) 42 51 (Decode.optionalField "public" Decode.bool False) 43 52 (Decode.field "tracks" <| Decode.list playlistTrackDecoder)
+10 -5
src/Library/Tracks.elm
··· 306 306 307 307 matchesAutoGeneratedPlaylist : Playlist -> Track -> Bool 308 308 matchesAutoGeneratedPlaylist playlist track = 309 - track.path 310 - |> String.split "/" 311 - |> List.head 312 - |> (==) (Just playlist.name) 313 - |> (&&) playlist.autoGenerated 309 + case playlist.autoGenerated of 310 + Just { level } -> 311 + track.path 312 + |> String.split "/" 313 + |> List.drop (max 0 (level - 1)) 314 + |> List.head 315 + |> (==) (Just playlist.name) 316 + 317 + Nothing -> 318 + False 314 319 315 320 316 321 missingId : String
+12 -17
src/Library/Tracks/Collection/Internal/Arrange.elm
··· 21 21 arrange ( deps, collection ) = 22 22 case deps.selectedPlaylist of 23 23 Just playlist -> 24 - if playlist.autoGenerated then 25 - arrangeByGroup ( deps, collection ) 24 + case playlist.autoGenerated of 25 + Just _ -> 26 + arrangeByGroup ( deps, collection ) 26 27 27 - else 28 - arrangeByPlaylist ( deps, collection ) playlist 28 + Nothing -> 29 + arrangeByPlaylist ( deps, collection ) playlist 29 30 30 31 Nothing -> 31 32 arrangeByGroup ( deps, collection ) ··· 130 131 groupByDirectoryFolder : CollectionDependencies -> IdentifiedTrack -> Dict String (List IdentifiedTrack) -> Dict String (List IdentifiedTrack) 131 132 groupByDirectoryFolder deps ( i, t ) = 132 133 let 133 - prefix = 134 - case deps.selectedPlaylist of 135 - Just playlist -> 136 - if playlist.autoGenerated then 137 - playlist.name ++ "/" 138 - 139 - else 140 - "" 141 - 142 - _ -> 143 - "" 144 - 145 134 directory = 146 135 t.path 147 - |> String.dropLeft (String.length prefix) 148 136 |> String.chopStart "/" 149 137 |> String.split "/" 138 + |> (case Maybe.andThen .autoGenerated deps.selectedPlaylist of 139 + Just { level } -> 140 + List.drop (max 0 (level - 1) + 1) 141 + 142 + Nothing -> 143 + identity 144 + ) 150 145 |> List.init 151 146 |> Maybe.map (String.join " / ") 152 147 |> Maybe.withDefault t.path
+8 -7
src/Library/Tracks/Collection/Internal/Harvest.elm
··· 32 32 if deps.favouritesOnly then 33 33 Tuple.first >> .isFavourite >> (==) True 34 34 35 - else if Maybe.map .autoGenerated deps.selectedPlaylist == Just False then 35 + else if Maybe.map .autoGenerated deps.selectedPlaylist == Just Nothing then 36 36 always True 37 37 38 38 else ··· 42 42 ----------- 43 43 , case deps.selectedPlaylist of 44 44 Just playlist -> 45 - if playlist.autoGenerated then 46 - \( _, t ) -> 47 - Tracks.matchesAutoGeneratedPlaylist playlist t 45 + case playlist.autoGenerated of 46 + Just _ -> 47 + \( _, t ) -> 48 + Tracks.matchesAutoGeneratedPlaylist playlist t 48 49 49 - else 50 - \( i, _ ) -> 51 - Maybe.isJust i.indexInPlaylist 50 + Nothing -> 51 + \( i, _ ) -> 52 + Maybe.isJust i.indexInPlaylist 52 53 53 54 Nothing -> 54 55 always True