Source

getemx / Emx / Options.hs

Full commit
{-# LANGUAGE NoMonomorphismRestriction #-}
module Emx.Options where
import System.IO 
import System.FilePath
import System.Directory
import Control.Applicative
import Control.Monad.Error
import Emx.Track

data Subs = Txt String | IntSub (Track -> Int) | StrSub (Track -> String)

data Options = Opt {repu, repapo, get_art :: Bool, dldir :: String,
                    dlfmt, dlfmt_m :: [Subs]}

lookupsub "a" = return $ StrSub artist
lookupsub "A" = return $ StrSub album
lookupsub "D" = return $ IntSub disccount
lookupsub "d" = return $ IntSub discnum
lookupsub "e" = return $ StrSub ext
lookupsub "t" = return $ StrSub title
lookupsub "l" = return $ StrSub label
lookupsub "g" = return $ StrSub genre
lookupsub "n" = return $ StrSub tracknum
lookupsub x = throwError $ "Unrecognized format option: \""++x++"\""

subfromstring s = go s []
    where
      go "" a = return $ reverse a
      go "%" a = throwError $ "Unescaped parenthesis at end of option string \""++s++"\""
      go ('%':'(':cs) a = do
        (kind, rest) <- return $ break (==')') cs
        when (null rest) $ throwError $ "Unclosed parenthesis in option string \""++s++"\""
        sub <- lookupsub kind
        go (tail rest) (sub:a)
      go ('%':'%':cs) as = 
          case as of
            Txt s:r -> go cs ((Txt $ s++"%"):r)
            _ -> go cs (Txt "%":as)
      go s as =
          case as of
            Txt s:r -> go rest ((Txt $ s++run):as)
            _ -> go rest (Txt run:as)
          where
            (run,rest) = break (=='%') s

(Right default_dlf) = subfromstring "%(a)/%(A)/%(a) - %(A) - %(n) - %(t)"
(Right default_dlfm) = subfromstring "%(a)/%(A): %(d)/%(a) - %(A): %(d) - %(n) - %(t)"

strip rem = reverse.snd.span (`elem` rem).reverse.snd.span (`elem` rem)
split s splite = (before, after)
    where
      (before,rest) = break (==splite) s
      (_,after) = span (==splite) rest
stripw = strip " \t\n"

optline o line = ps (stripw s) (stripw e)
    where
      (s,e) = split line '='
      ps ('#':rest) _ = return o
      ps s e = 
          case s of 
            "replace_underscores" -> bconv (\x -> o {repu = x}) s e
            "replace_apostrophe_identity" -> bconv (\x -> o {repapo = x}) s e
            "get_art" -> bconv (\x -> o {get_art = x}) s e
            "dlfmt" -> sconv (\x -> o {dlfmt = x}) s e
            "dlfmt_multidisc" -> sconv (\x -> o {dlfmt_m = x}) s e
            "dldir" -> return $ o {dldir = e}
            "" -> return o
            x -> throwError $ "Unrecognized option: " ++ x
      bconv u oname v 
          | v `elem` ["f", "false"] = return $ u False
          | v `elem` ["t", "true"]  = return $ u True
          | otherwise = throwError $ "Boolean values must be one of 'f', 't', 'true', and 'false', not `"++v++"\', in option "++oname
      sconv u on v = catchError (u `liftM` (subfromstring v))
                     (\t -> throwError $ t++" (error in option \""++on++"\")")

readopts = do
  dotfile <- fmap (</> ".emxdownloader") getHomeDirectory
  curdir <- getCurrentDirectory
  let default_options = Opt True True True curdir default_dlf default_dlfm
  exists <- doesFileExist dotfile
  if exists 
     then do
       h <- openFile dotfile ReadMode
       contents <- fmap lines $ hGetContents h
       return (foldM optline default_options contents)
     else return $ return default_options