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

Configure Feed

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

Playlist improvements

+131 -68
+3 -2
CHANGELOG.md
··· 3 3 ## 3.2.0 4 4 5 5 - **Native builds with [Tauri](https://tauri.app/)**. 6 - - Fixes playback issue with Google Drive on Safari/iOS. 6 + - Add support for non-standard `audio/x-flac` mimetype 7 + - Fixes a playback issue with Google Drive on Safari/iOS. 7 8 - Improves Google Drive support, access tokens are now refreshed when needed (before it only refreshed on source processing) 8 - - Add support for non-standard `audio/x-flac` mimetype 9 + - Several playlist improvements: add to queue, add options to autogenerated playlists, etc. 9 10 10 11 11 12 ## 3.1.1
+102 -54
src/Applications/UI/Playlists/ContextMenu.elm
··· 9 9 import Tracks exposing (IdentifiedTrack) 10 10 import UI.Page 11 11 import UI.Playlists.Page 12 + import UI.Queue.Types as Queue 12 13 import UI.Tracks.Types as Tracks 13 14 import UI.Types exposing (Msg(..)) 14 15 import Url ··· 21 22 listMenu : Playlist -> List IdentifiedTrack -> Maybe String -> Coordinates -> ContextMenu Msg 22 23 listMenu playlist allTracks confirmation coordinates = 23 24 let 24 - ( identifiedTracksFromPlaylist, _ ) = 25 - Playlists.Matching.match playlist allTracks 25 + identifiedTracksFromPlaylist = 26 + if playlist.autoGenerated then 27 + List.filter 28 + (Tuple.second >> Tracks.matchesAutoGeneratedPlaylist playlist) 29 + allTracks 30 + 31 + else 32 + allTracks 33 + |> Playlists.Matching.match playlist 34 + |> Tuple.first 26 35 27 36 tracksFromPlaylist = 28 37 identifiedTracksFromPlaylist 29 38 |> List.sortBy (Tuple.first >> .indexInPlaylist >> Maybe.withDefault 0) 30 39 |> List.map Tuple.second 31 - 32 - playlistId = 33 - "Playlist - " ++ playlist.name 34 40 35 41 menuMsg = 36 42 ShowPlaylistListMenu ··· 42 48 , pagePos = ( 0, 0 ) 43 49 , screenPos = ( 0, 0 ) 44 50 } 45 - 46 - askForConfirmation = 47 - confirmation == Just playlistId 48 51 in 49 - ContextMenu 50 - [ Item 51 - { icon = Icons.archive 52 - , label = "Download as zip file" 53 - , msg = 54 - tracksFromPlaylist 55 - |> Tracks.Download playlist.name 56 - |> TracksMsg 52 + if playlist.autoGenerated then 53 + ContextMenu 54 + [ addToQueue identifiedTracksFromPlaylist 55 + , downloadAsZip tracksFromPlaylist playlist 56 + , storeInCache tracksFromPlaylist 57 + ] 58 + coordinates 57 59 58 - -- 59 - , active = False 60 - } 60 + else 61 + ContextMenu 62 + [ addToQueue identifiedTracksFromPlaylist 63 + , downloadAsZip tracksFromPlaylist playlist 64 + , removePlaylist menuMsg confirmation playlist 65 + , renamePlaylist playlist 66 + , storeInCache tracksFromPlaylist 67 + ] 68 + coordinates 69 + 70 + 71 + 72 + -- ITEMS 73 + 74 + 75 + addToQueue identifiedTracks = 76 + Item 77 + { icon = Icons.update 78 + , label = "Add to queue" 79 + , msg = 80 + { inFront = False, tracks = identifiedTracks } 81 + |> Queue.AddTracks 82 + |> QueueMsg 61 83 62 84 -- 63 - , Item 64 - { icon = Icons.font_download 65 - , label = "Rename playlist" 66 - , msg = 67 - playlist.name 68 - |> Url.percentEncode 69 - |> UI.Playlists.Page.Edit 70 - |> UI.Page.Playlists 71 - |> ChangeUrlUsingPage 85 + , active = False 86 + } 72 87 73 - -- 74 - , active = False 75 - } 88 + 89 + downloadAsZip tracksFromPlaylist playlist = 90 + Item 91 + { icon = Icons.archive 92 + , label = "Download as zip file" 93 + , msg = 94 + tracksFromPlaylist 95 + |> Tracks.Download playlist.name 96 + |> TracksMsg 76 97 77 98 -- 78 - , Item 79 - { icon = Icons.delete 80 - , label = 81 - if askForConfirmation then 82 - "Are you sure?" 99 + , active = False 100 + } 83 101 84 - else 85 - "Remove playlist" 86 - , msg = 87 - if askForConfirmation then 88 - DeletePlaylist { playlistName = playlist.name } 102 + 103 + removePlaylist menuMsg confirmation playlist = 104 + let 105 + playlistId = 106 + "Playlist - " ++ playlist.name 89 107 90 - else 91 - ContextMenuConfirmation playlistId menuMsg 92 - , active = 93 - askForConfirmation 94 - } 108 + askForConfirmation = 109 + confirmation == Just playlistId 110 + in 111 + Item 112 + { icon = Icons.delete 113 + , label = 114 + if askForConfirmation then 115 + "Are you sure?" 116 + 117 + else 118 + "Remove playlist" 119 + , msg = 120 + if askForConfirmation then 121 + DeletePlaylist { playlistName = playlist.name } 122 + 123 + else 124 + ContextMenuConfirmation playlistId menuMsg 125 + , active = 126 + askForConfirmation 127 + } 128 + 129 + 130 + renamePlaylist playlist = 131 + Item 132 + { icon = Icons.font_download 133 + , label = "Rename playlist" 134 + , msg = 135 + playlist.name 136 + |> Url.percentEncode 137 + |> UI.Playlists.Page.Edit 138 + |> UI.Page.Playlists 139 + |> ChangeUrlUsingPage 95 140 96 141 -- 97 - , Item 98 - { icon = Icons.offline_bolt 99 - , label = "Store in cache" 100 - , msg = TracksMsg (Tracks.StoreInCache tracksFromPlaylist) 101 - , active = False 102 - } 103 - ] 104 - coordinates 142 + , active = False 143 + } 144 + 145 + 146 + storeInCache tracksFromPlaylist = 147 + Item 148 + { icon = Icons.offline_bolt 149 + , label = "Store in cache" 150 + , msg = TracksMsg (Tracks.StoreInCache tracksFromPlaylist) 151 + , active = False 152 + }
+11 -2
src/Applications/UI/Playlists/View.elm
··· 112 112 113 113 else 114 114 { label = text playlist.name 115 - , actions = [] 115 + , actions = 116 + [ { icon = Icons.more_vert 117 + , msg = Just (ShowPlaylistListMenu playlist) 118 + , title = "Menu" 119 + } 120 + ] 116 121 , msg = Just (ActivatePlaylist playlist) 117 122 , isSelected = False 118 123 } ··· 257 262 [ text playlist.name ] 258 263 , actions = 259 264 [ { icon = \size _ -> Icons.check size (Color selectionColor) 260 - , msg = Nothing 265 + , msg = Just (always DeactivatePlaylist) 261 266 , title = "Selected playlist" 267 + } 268 + , { icon = Icons.more_vert 269 + , msg = Just (ShowPlaylistListMenu playlist) 270 + , title = "Menu" 262 271 } 263 272 ] 264 273 , msg = Just DeactivatePlaylist
+14 -5
src/Library/Tracks.elm
··· 242 242 } 243 243 244 244 245 + matchesAutoGeneratedPlaylist : Playlist -> Track -> Bool 246 + matchesAutoGeneratedPlaylist playlist track = 247 + track.path 248 + |> String.split "/" 249 + |> List.head 250 + |> (==) (Just playlist.name) 251 + |> (&&) playlist.autoGenerated 252 + 253 + 245 254 missingAlbumPlaceholder : String 246 255 missingAlbumPlaceholder = 247 256 "⌁" 257 + 258 + 259 + missingId : String 260 + missingId = 261 + "<missing>" 248 262 249 263 250 264 pathParts : Track -> { filename : String, parentDirectory : String } ··· 352 366 , List.map (Tuple.first >> .indexInPlaylist) tracks 353 367 ) 354 368 |> (\( t, _ ) -> { playlist | tracks = t }) 355 - 356 - 357 - missingId : String 358 - missingId = 359 - "<missing>" 360 369 361 370 362 371 shouldRenderGroup : Identifiers -> Bool
+1 -5
src/Library/Tracks/Collection/Internal/Harvest.elm
··· 44 44 Just playlist -> 45 45 if playlist.autoGenerated then 46 46 \( _, t ) -> 47 - t.path 48 - |> String.split "/" 49 - |> List.head 50 - |> Maybe.withDefault "" 51 - |> (==) playlist.name 47 + Tracks.matchesAutoGeneratedPlaylist playlist t 52 48 53 49 else 54 50 \( i, _ ) ->