-- | Module : Hum.Rebuild -- Copyright : (c) Itai Y. Efrat 2020-2021 -- License : GPLv2-or-later (see LICENSE) -- Maintainer : Itai Y. Efrat -- -- Functions that rebuild the state after changes that require it, -- Or that have to be here to avoid dependency loops. module Hum.Rebuild where import Hum.Types import Control.Lens import Data.Foldable import Brick.Widgets.List import Network.MPD ( withMPD ) import qualified Network.MPD as MPD import qualified Data.Vector as V -- | All songs of a given artist songsOfArtist :: MPD.Value -> IO (V.Vector MPD.Song) songsOfArtist artist' = (V.fromList . fromRight [] <$>) . withMPD . MPD.find $ (MPD.AlbumArtist MPD.=? artist') -- | All songs in a given album songsOfAlbum ::MPD.Value -> IO (V.Vector MPD.Song) songsOfAlbum album' = (V.fromList . fromRight [] <$>) . withMPD . MPD.find $ (MPD.Album MPD.=? album') -- | All albums of a given artist albumsOfArtist :: MPD.Value -> IO (V.Vector MPD.Value) albumsOfArtist artist' = V.fromList . fromRight [] <$> withMPD (MPD.list MPD.Album (MPD.AlbumArtist MPD.=? artist')) -- | All year-album pairs of a given artist yalbumsOfArtist :: Bool -> MPD.Value -> IO (V.Vector (MPD.Value,MPD.Value)) yalbumsOfArtist bl artist' = let srt = (if bl then fst else snd) in do albums' <- fromRight [] <$> withMPD (MPD.list MPD.Album (MPD.AlbumArtist MPD.=? artist')) yalbums' <- liftIO . sequence $ (\x -> (,x) <$> yearOfAlbum x) <$> albums' pure $ V.fromList (sortBy (\x y -> compare (srt x) (srt y)) yalbums') -- | Earliest year of any song in the given album yearOfAlbum :: MPD.Value -> IO MPD.Value yearOfAlbum album' = fromRight "????" <$> (minYear <<$>> withMPD (MPD.list MPD.Date (MPD.Album MPD.=? album'))) where minYear :: [MPD.Value] -> MPD.Value minYear [] = "????" minYear vals = minimum vals -- | Rebuild entire library state, keeping the index of the left column if possible. rebuildLib :: MonadIO m => HumState -> m HumState rebuildLib s = do let mi = s ^. libraryL . artistsL & listSelected artistsVec <- liftIO (V.fromList . fromRight [] <$> withMPD (MPD.list MPD.AlbumArtist mempty)) let artists' = maybe id listMoveTo mi $ list ArtistsList artistsVec 1 albumsVec <- liftIO $ maybe (pure empty) albumsOfArtist (snd <$> listSelectedElement artists') let albums' = list AlbumsList albumsVec 1 yalbumsVec <- liftIO $ maybe (pure empty) (yalbumsOfArtist (s ^. libraryL . yalbumSortL)) (snd <$> listSelectedElement artists') let yalbums' = list YalbumsList yalbumsVec 1 songsVec <- liftIO $ maybe (pure empty) songsOfAlbum (snd <$> listSelectedElement albums') let songs' = list SongsList songsVec 1 pure $ s & libraryL . artistsL .~ artists' & libraryL . yalbumsL .~ yalbums' & libraryL . songsL .~ songs' -- | Rebuild library state from selected artist. rebuildLibArtists :: MonadIO m => HumState -> m HumState rebuildLibArtists s = do let artists' = s ^. libraryL . artistsL yalbumsVec <- liftIO $ maybe (pure empty) (yalbumsOfArtist (s ^. libraryL . yalbumSortL)) (snd <$> listSelectedElement artists') let yalbums' = list YalbumsList yalbumsVec 1 songsVec <- liftIO $ maybe (pure empty) songsOfAlbum (snd . snd <$> listSelectedElement yalbums') let songs' = list SongsList songsVec 1 pure $ s & libraryL . yalbumsL .~ yalbums' & libraryL . songsL .~ songs' -- | Rebuild library state from selected artist. reloadLibArtists :: MonadIO m => HumState -> m HumState reloadLibArtists s = do let mi = s ^. libraryL . yalbumsL & listSelected let mj = s ^. libraryL . songsL & listSelected let artists' = s ^. libraryL . artistsL yalbumsVec <- liftIO $ maybe (pure empty) (yalbumsOfArtist (s ^. libraryL . yalbumSortL)) (snd <$> listSelectedElement artists') let yalbums' = maybe id listMoveTo mi $ list YalbumsList yalbumsVec 1 songsVec <- liftIO $ maybe (pure empty) songsOfAlbum (snd . snd <$> listSelectedElement yalbums') let songs' = maybe id listMoveTo mj $ list SongsList songsVec 1 pure $ s & libraryL . yalbumsL .~ yalbums' & libraryL . songsL .~ songs' -- | Rebuild library state from selected album. rebuildLibAlbums :: MonadIO m => HumState -> m HumState rebuildLibAlbums s = do let yalbums' = s ^. libraryL . yalbumsL songsVec <- liftIO $ maybe (pure empty) songsOfAlbum (snd . snd <$> listSelectedElement yalbums') let songs' = list SongsList songsVec 1 pure $ s & libraryL . songsL .~ songs' -- | Rebuild library state from selected album, keeping the selected song index if possible. reloadLibAlbums :: MonadIO m => HumState -> m HumState reloadLibAlbums s = do let mi = s ^. libraryL . songsL & listSelected let yalbums' = s ^. libraryL . yalbumsL songsVec <- liftIO $ maybe (pure empty) songsOfAlbum (snd . snd <$> listSelectedElement yalbums') let songs' = maybe id listMoveTo mi $ list SongsList songsVec 1 pure $ s & libraryL . songsL .~ songs' -- | Rebuild entire stored playlists state, keeping the index of the left column if possible. rebuildPl :: MonadIO m => HumState -> m HumState rebuildPl s = do let mi = s ^. playlistsL . plListL & listSelected plListVec <- liftIO $ V.fromList . sort . fromRight [] <$> withMPD MPD.listPlaylists let plList' = maybe id listMoveTo mi $ list PlaylistList plListVec 1 plSongsVec <- liftIO $ V.fromList . fromRight [] <$> withMPD (MPD.listPlaylistInfo (maybe "" snd (listSelectedElement plList')) ) let plSongs' = (, False) <$> list PlaylistSongs plSongsVec 1 pure $ s & playlistsL . plListL .~ plList' & playlistsL . plSongsL .~ plSongs' -- | Rebuild stored playlists state from selected playlist. rebuildPlList :: MonadIO m => HumState -> m HumState rebuildPlList s = do let plList' = s ^. playlistsL . plListL plSongsVec <- liftIO (V.fromList . fromRight [] <$> withMPD (MPD.listPlaylistInfo (maybe "" snd (listSelectedElement plList')) ) ) let plSongs' = (, False) <$> list PlaylistSongs plSongsVec 1 pure $ s & playlistsL . plSongsL .~ plSongs' -- | Rebuild stored playlists state from selected playlist, keeping the selected song index if possible. reloadPlList :: MonadIO m => HumState -> m HumState reloadPlList s = do let mi = s ^. playlistsL . plSongsL & listSelected let plList' = s ^. playlistsL . plListL plSongsVec <- liftIO (V.fromList . fromRight [] <$> withMPD (MPD.listPlaylistInfo (maybe "" snd (listSelectedElement plList')) ) ) let plSongs' = maybe id listMoveTo mi $ (, False) <$> list PlaylistSongs plSongsVec 1 pure $ s & playlistsL . plSongsL .~ plSongs' -- | Rebuild queue state, keeping the index of the left column if possible. rebuildQueue :: MonadIO m => HumState -> m HumState rebuildQueue s = do let mi = s ^. queueL & listSelected queueVec <- liftIO $ V.fromList . fromRight [] <$> withMPD (MPD.playlistInfo Nothing) let queue' = maybe id listMoveTo mi $ (, False) <$> list QueueList queueVec 1 pure $ s & queueL .~ queue' -- | Rebuild status and current song state. rebuildStatus :: MonadIO m => HumState -> m HumState rebuildStatus s = do currentSong' <- liftIO (fromRight Nothing <$> withMPD MPD.currentSong) status' <- liftIO (fromRight Nothing <$> (Just <<$>> withMPD MPD.status)) pure $ s & currentSongL .~ currentSong' & statusL .~ status'