<commit_before>{-# LANGUAGE OverloadedStrings #-}
-- | Module    : Network.MPD.Commands.Extensions
-- Copyright   : (c) <NAME> 2005-2009, <NAME> 2012
-- License     : LGPL (see LICENSE)
-- Maintainer  : <NAME> <<EMAIL>>
-- Stability   : alpha
--
-- Extensions and shortcuts to the standard MPD command set.

module Network.MPD.Commands.Extensions where

import           Network.MPD.Core
import           Network.MPD.Commands
import           Network.MPD.Commands.Arg
import           Network.MPD.Commands.Util
import qualified Network.MPD.Applicative as A
import qualified Network.MPD.Applicative.CurrentPlaylist as A
import qualified Network.MPD.Applicative.StoredPlaylists as A

import           Control.Monad (liftM)
import           Data.Traversable (for)
import           Data.Foldable (for_)

-- | This is exactly the same as `update`.
updateId :: MonadMPD m => Maybe Path -> m Integer
updateId = update
{-# DEPRECATED updateId "use `update` instead" #-}

-- | Toggles play\/pause. Plays if stopped.
toggle :: MonadMPD m => m ()
toggle = status >>= \st -> case stState st of Playing -> pause True
                                              _       -> play Nothing

-- | Add a list of songs\/folders to a playlist.
-- Should be more efficient than running 'add' many times.
addMany :: MonadMPD m => PlaylistName -> [Path] -> m ()
addMany plname xs = A.runCommand (for_ xs cmd)
    where cmd | plname == "" = A.add
              | otherwise    = A.playlistAdd plname

-- | Recursive 'addId'. For directories, it will use the given position
-- for the first file in the directory and use the successor for the remaining
-- files. It returns a list of playlist ids for the songs added.
addIdMany :: MonadMPD m => Path -> Maybe Position -> m [Id]
addIdMany x (Just p) = do
    fs <- listAll x
    let fs' = map (\(a, b) -> (a, Just b)) $ zip fs [p ..]
    A.runCommand $ for fs' (uncurry A.addId)
addIdMany x Nothing = do
    fs <- listAll x
    A.runCommand $ for fs (`A.addId` Nothing)

-- | Like 'add' but returns a list of the files added.
addList :: MonadMPD m => Path -> m [Path]
addList x = add x >> listAll x
{-# DEPRECATED addList "will be removed in a future version" #-}

-- | Like 'playlistAdd' but returns a list of the files added.
playlistAddList :: MonadMPD m => PlaylistName -> Path -> m [Path]
playlistAddList plname path = playlistAdd plname path >> listAll path
{-# DEPRECATED playlistAddList "will be removed in a future version" #-}

{-
-- | Delete a list of songs from a playlist.
-- If there is a duplicate then no further songs will be deleted, so
-- take care to avoid them (see 'prune' for this).
deleteMany :: MonadMPD m => PlaylistName -> [PLIndex] -> m ()
deleteMany _ [] = return ()
deleteMany plname [(Pos x)] = playlistDelete plname x
deleteMany "" xs = getResponses (map cmd xs) >> return ()
    where cmd (Pos x) = "delete"   <@> x
          cmd (ID x)  = "deleteid" <@> x
deleteMany plname xs = getResponses (map cmd xs) >> return ()
    where cmd (Pos x) = "playlistdelete" <@> plname <++> x
          cmd _       = ""
-}

{-
-- | Returns all songs and directories that match the given partial
-- path name.
complete :: MonadMPD m => String -> m [Either Path Song]
complete path = do
    xs <- liftM matches . lsInfo $ dropFileName path
    case xs of
        [Left dir] -> complete $ dir ++ "/"
        _          -> return xs
    where
        matches = filter (isPrefixOf path . takePath)
        takePath = either id sgFilePath
-}

{-
-- | Crop playlist.
-- The bounds are inclusive.
-- If 'Nothing' is passed the cropping will leave your playlist alone
-- on that side.
-- Using 'ID' will automatically find the absolute playlist position and use
-- that as the cropping boundary.
crop :: MonadMPD m => Maybe PLIndex -> Maybe PLIndex -> m ()
crop x y = do
    pl <- playlistInfo Nothing
    let x' = case x of Just (Pos p) -> fromInteger p
                       Just (ID i)  -> fromMaybe 0 (findByID i pl)
                       Nothing      -> 0
        -- ensure that no songs are deleted twice with 'max'.
        ys = case y of Just (Pos p) -> drop (max (fromInteger p) x') pl
                       Just (ID i)  -> maybe [] (flip drop pl . max x' . (+1))
                                      (findByID i pl)
                       Nothing      -> []
    deleteMany "" . mapMaybe sgIndex $ take x' pl ++ ys
    where findByID i = findIndex ((==) i . (\(ID j) -> j) . fromJust . sgIndex)
-}

{-
-- | Remove duplicate playlist entries.
prune :: MonadMPD m => m ()
prune = findDuplicates >>= deleteMany ""

-- Find duplicate playlist entries.
findDuplicates :: MonadMPD m => m [PLIndex]
findDuplicates =
    liftM (map ((\(ID x) -> ID x) . fromJust . sgIndex) . flip dups ([],[])) $
        playlistInfo Nothing
    where dups [] (_, dup) = dup
          dups (x:xs) (ys, dup)
              | x `mSong` xs && not (x `mSong` ys) = dups xs (ys, x:dup)
              | otherwise                          = dups xs (x:ys, dup)
          mSong x = let m = sgFilePath x in any ((==) m . sgFilePath)
-}

{-
-- | List directories non-recursively.
lsDirs :: MonadMPD m => Path -> m [Path]
lsDirs path =
    liftM (extractEntries (const Nothing,const Nothing, Just)) $
        takeEntries =<< getResponse ("lsinfo" <@> path)
-}

{-
-- | List files non-recursively.
lsFiles :: MonadMPD m => Path -> m [Path]
lsFiles path =
    liftM (extractEntries (Just . sgFilePath, const Nothing, const Nothing)) $
        takeEntries =<< getResponse ("lsinfo" <@> path)
-}

{-
-- | List all playlists.
lsPlaylists :: MonadMPD m => m [PlaylistName]
lsPlaylists = liftM (extractEntries (const Nothing, Just, const Nothing)) $
                    takeEntries =<< getResponse "lsinfo"
-}

-- | List the artists in the database.
listArtists :: MonadMPD m => m [Artist]
listArtists = list Artist Nothing

-- | List the albums in the database, optionally matching a given
-- artist.
listAlbums :: MonadMPD m => Maybe Artist -> m [Album]
listAlbums artist = (map Value . takeValues) `liftM`
                    getResponse ("list album" <@> fmap (("artist" :: String) <++>) artist)

-- | List the songs in an album of some artist.
listAlbum :: MonadMPD m => Artist -> Album -> m [Song]
listAlbum artist album = find (Artist =? artist <&> Album =? album)

-- | Retrieve the current playlist.
-- Equivalent to @playlistinfo Nothing@.
getPlaylist :: MonadMPD m => m [Song]
getPlaylist = playlistInfo Nothing

-- | Increase or decrease volume by a given percent, e.g.
-- 'volume 10' will increase the volume by 10 percent, while
-- 'volume (-10)' will decrease it by the same amount.
volume :: MonadMPD m => Int -> m ()
volume n = do
    current <- (fromIntegral . stVolume) `liftM` status
    setVolume . round $ (fromIntegral n / (100 :: Double)) * current + current<commit_msg>Implement `listAlbums` in terms of `list`<commit_after>{-# LANGUAGE OverloadedStrings #-}
-- | Module    : Network.MPD.Commands.Extensions
-- Copyright   : (c) <NAME> 2005-2009, <NAME> 2012
-- License     : LGPL (see LICENSE)
-- Maintainer  : <NAME> <<EMAIL>>
-- Stability   : alpha
--
-- Extensions and shortcuts to the standard MPD command set.

module Network.MPD.Commands.Extensions where

import           Network.MPD.Core
import           Network.MPD.Commands
import qualified Network.MPD.Applicative as A
import qualified Network.MPD.Applicative.CurrentPlaylist as A
import qualified Network.MPD.Applicative.StoredPlaylists as A

import           Control.Monad (liftM)
import           Data.Traversable (for)
import           Data.Foldable (for_)

-- | This is exactly the same as `update`.
updateId :: MonadMPD m => Maybe Path -> m Integer
updateId = update
{-# DEPRECATED updateId "use `update` instead" #-}

-- | Toggles play\/pause. Plays if stopped.
toggle :: MonadMPD m => m ()
toggle = status >>= \st -> case stState st of Playing -> pause True
                                              _       -> play Nothing

-- | Add a list of songs\/folders to a playlist.
-- Should be more efficient than running 'add' many times.
addMany :: MonadMPD m => PlaylistName -> [Path] -> m ()
addMany plname xs = A.runCommand (for_ xs cmd)
    where cmd | plname == "" = A.add
              | otherwise    = A.playlistAdd plname

-- | Recursive 'addId'. For directories, it will use the given position
-- for the first file in the directory and use the successor for the remaining
-- files. It returns a list of playlist ids for the songs added.
addIdMany :: MonadMPD m => Path -> Maybe Position -> m [Id]
addIdMany x (Just p) = do
    fs <- listAll x
    let fs' = map (\(a, b) -> (a, Just b)) $ zip fs [p ..]
    A.runCommand $ for fs' (uncurry A.addId)
addIdMany x Nothing = do
    fs <- listAll x
    A.runCommand $ for fs (`A.addId` Nothing)

-- | Like 'add' but returns a list of the files added.
addList :: MonadMPD m => Path -> m [Path]
addList x = add x >> listAll x
{-# DEPRECATED addList "will be removed in a future version" #-}

-- | Like 'playlistAdd' but returns a list of the files added.
playlistAddList :: MonadMPD m => PlaylistName -> Path -> m [Path]
playlistAddList plname path = playlistAdd plname path >> listAll path
{-# DEPRECATED playlistAddList "will be removed in a future version" #-}

{-
-- | Delete a list of songs from a playlist.
-- If there is a duplicate then no further songs will be deleted, so
-- take care to avoid them (see 'prune' for this).
deleteMany :: MonadMPD m => PlaylistName -> [PLIndex] -> m ()
deleteMany _ [] = return ()
deleteMany plname [(Pos x)] = playlistDelete plname x
deleteMany "" xs = getResponses (map cmd xs) >> return ()
    where cmd (Pos x) = "delete"   <@> x
          cmd (ID x)  = "deleteid" <@> x
deleteMany plname xs = getResponses (map cmd xs) >> return ()
    where cmd (Pos x) = "playlistdelete" <@> plname <++> x
          cmd _       = ""
-}

{-
-- | Returns all songs and directories that match the given partial
-- path name.
complete :: MonadMPD m => String -> m [Either Path Song]
complete path = do
    xs <- liftM matches . lsInfo $ dropFileName path
    case xs of
        [Left dir] -> complete $ dir ++ "/"
        _          -> return xs
    where
        matches = filter (isPrefixOf path . takePath)
        takePath = either id sgFilePath
-}

{-
-- | Crop playlist.
-- The bounds are inclusive.
-- If 'Nothing' is passed the cropping will leave your playlist alone
-- on that side.
-- Using 'ID' will automatically find the absolute playlist position and use
-- that as the cropping boundary.
crop :: MonadMPD m => Maybe PLIndex -> Maybe PLIndex -> m ()
crop x y = do
    pl <- playlistInfo Nothing
    let x' = case x of Just (Pos p) -> fromInteger p
                       Just (ID i)  -> fromMaybe 0 (findByID i pl)
                       Nothing      -> 0
        -- ensure that no songs are deleted twice with 'max'.
        ys = case y of Just (Pos p) -> drop (max (fromInteger p) x') pl
                       Just (ID i)  -> maybe [] (flip drop pl . max x' . (+1))
                                      (findByID i pl)
                       Nothing      -> []
    deleteMany "" . mapMaybe sgIndex $ take x' pl ++ ys
    where findByID i = findIndex ((==) i . (\(ID j) -> j) . fromJust . sgIndex)
-}

{-
-- | Remove duplicate playlist entries.
prune :: MonadMPD m => m ()
prune = findDuplicates >>= deleteMany ""

-- Find duplicate playlist entries.
findDuplicates :: MonadMPD m => m [PLIndex]
findDuplicates =
    liftM (map ((\(ID x) -> ID x) . fromJust . sgIndex) . flip dups ([],[])) $
        playlistInfo Nothing
    where dups [] (_, dup) = dup
          dups (x:xs) (ys, dup)
              | x `mSong` xs && not (x `mSong` ys) = dups xs (ys, x:dup)
              | otherwise                          = dups xs (x:ys, dup)
          mSong x = let m = sgFilePath x in any ((==) m . sgFilePath)
-}

{-
-- | List directories non-recursively.
lsDirs :: MonadMPD m => Path -> m [Path]
lsDirs path =
    liftM (extractEntries (const Nothing,const Nothing, Just)) $
        takeEntries =<< getResponse ("lsinfo" <@> path)
-}

{-
-- | List files non-recursively.
lsFiles :: MonadMPD m => Path -> m [Path]
lsFiles path =
    liftM (extractEntries (Just . sgFilePath, const Nothing, const Nothing)) $
        takeEntries =<< getResponse ("lsinfo" <@> path)
-}

{-
-- | List all playlists.
lsPlaylists :: MonadMPD m => m [PlaylistName]
lsPlaylists = liftM (extractEntries (const Nothing, Just, const Nothing)) $
                    takeEntries =<< getResponse "lsinfo"
-}

-- | List the artists in the database.
listArtists :: MonadMPD m => m [Artist]
listArtists = list Artist Nothing

-- | List the albums in the database, optionally matching a given
-- artist.
listAlbums :: MonadMPD m => Maybe Artist -> m [Album]
listAlbums = list Album

-- | List the songs in an album of some artist.
listAlbum :: MonadMPD m => Artist -> Album -> m [Song]
listAlbum artist album = find (Artist =? artist <&> Album =? album)

-- | Retrieve the current playlist.
-- Equivalent to @playlistinfo Nothing@.
getPlaylist :: MonadMPD m => m [Song]
getPlaylist = playlistInfo Nothing

-- | Increase or decrease volume by a given percent, e.g.
-- 'volume 10' will increase the volume by 10 percent, while
-- 'volume (-10)' will decrease it by the same amount.
volume :: MonadMPD m => Int -> m ()
volume n = do
    current <- (fromIntegral . stVolume) `liftM` status
    setVolume . round $ (fromIntegral n / (100 :: Double)) * current + current
{'fraction_non_alphanumeric': 0.12376053082830091, 'fraction_numerical': 0.0035786177588906284, 'mean_word_length': 2.477832512315271, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 157, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3848274', 'n_tokens_mistral': 4245, 'n_tokens_neox': 4094, 'n_words': 1598}