hum-0.2.0.0: src/Hum/Rebuild.hs
-- | Module : Hum.Rebuild
-- Copyright : (c) Itai Y. Efrat 2020-2021
-- License : GPLv2-or-later (see LICENSE)
-- Maintainer : Itai Y. Efrat <itai3397@gmail.com>
--
-- 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 "<no playlists>" 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 "<no playlists>" 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 "<no playlists>" 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'