{-# LANGUAGE Arrows, ScopedTypeVariables, NamedFieldPuns #-} module Emx.Emx where import Control.Applicative import System.FilePath import Data.List (isPrefixOf) import Control.Monad.Error import Text.XML.HXT.Core import Emx.Track atTag :: (ArrowXml a) => String -> a XmlTree XmlTree atTag = deep . hasName text :: (ArrowXml a) => a XmlTree String text = getChildren >>> getText opttagtext :: (ArrowXml a) => String -> a XmlTree String opttagtext = (<<<) text . atTag tagtext t = (opttagtext t >>> arr Right) `orElse` constA (Left $ "Bad XML: couldn't find tag "++t) replace::(Eq a) => [a] -> [a] -> [a] -> [a] replace [] newSub list = joins newSub list replace oldSub newSub list = _replace list where _replace list@(h:ts) = if oldSub `isPrefixOf` list then newSub ++ _replace (drop len list) else h : _replace ts _replace [] = [] len = length oldSub joins::[a] -> [a] -> [a] joins glue [h] = [h] joins glue (h:ts) = h : glue ++ joins glue ts joins _ [] = [] clean repu repapo = pthc . uc . apoc where pthc = replace [pathSeparator] "_" uc = if repu then replace "_" " " else id apoc = if repapo then replace "'" "'" else id instance Applicative (Either a) where pure = Right (Right f) <*> (Right x) = Right $ f x (Left f) <*> _ = Left f _ <*> (Left x) = Left x gettrack repu repapo = atTag "TRACK" >>> (proc t -> do ar <- c <<< tagtext "ARTIST" -< t al <- c <<< tagtext "ALBUM"-< t ti <- c <<< tagtext "TITLE"-< t ext <- tagtext "EXTENSION" -< t url <- tagtext "TRACKURL" -< t lbl <- c <<< tagtext "LABEL" -< t art <- tagtext "ALBUMART" -< t dc <- rtag "DISCCOUNT" -< t dn <- rtag "DISCNUM" -< t tc <- rtag "TRACKCOUNT" -< t gr <- tagtext "GENRE" -< t tn <- tr <<< rtag "TRACKNUM" -< t returnA -< Tr <$> ar <*> al <*> ti <*> ext <*> url <*> lbl <*> art <*> tn <*> gr <*> dc <*> dn <*> tc) where c = right $ arr $ clean repu repapo r t = arr $ \i -> do v <- i case reads v of [] -> throwError $ "Bad XML: couldn't parse int in tag "++t [(x::Int,_)] -> return x rtag t = tagtext t >>> r t tr = right $ arr (fill '0' 2 . show) -- bad assumption: < 100 tracks fill fille until s = if length s < until then fill fille until (fille:s) else s collect repu repapo = atTag "PACKAGE" >>> (tagtext "ACTION" &&& tagtext "EXP_DATE" &&& listA (gettrack repu repapo)) >>> arr f where f (action, (exp, tracks)) = (,,) <$> action <*> exp <*> (sequence tracks) parseXML = readDocument [withValidate False] readfile f repu repapo = do r <- liftIO $ runX (parseXML f >>> collect repu repapo) case r of [] -> throwError $ "Couldn't parse emx file "++f++" at all!" [Right s] -> return s [Left e] -> throwError e