平常经常用千千静听来听音乐,长期以来就形成了一个自己最喜欢听的音乐列表。这几天想把这些音乐全部复制到U盘,插在车上,开车的时候也可以听听。但是每个MP3、WMA分散在不同的文件夹,一个个复制的话工作量就大了。我的音乐列表一般存为千千静听的 *.ttpl 格式,其本质就是一个 XML 文件。一般格式如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <ttplaylist title="[默认]" version="4" generator="TTPlayer -- 5.9.6"> <format tagtitle="%A - %T" deftitle="%F"/> <items count="163"> <item file="E:\incomings\cd3\I Still Believe.mp3" title="I Still Believe" len="287111"/> <item file="E:\incomings\cd3\When You Believe.mp3" title="When You Believe" len="273136"/> </items> </ttplaylist>
Haskell 中可以实现 XML操作的库有很多,比如 HaXml、HXT、xml 等。本文采用最简单的 xml 库。安装 xml 库时可以使用 Haskell 的安装工具 Cabal 来自动安装:cabal install xml。有一些音乐文件可能是中文的文件名,经过测试,Haskell 不支持 ANSI 形式的中文路径、文件名的文件操作。所以还需要调用 UTF8 的库:cabal install utf8-string。
首先,需要将 Prelude 中的 readFile 隐藏,使用 UTF8 的 readFile,这样子后面才能识别 ttpl 中的中文路径。
import Prelude hiding (readFile) import System.IO.UTF8 (readFile)
import Text.XML.Light.Input import Text.XML.Light.Output import Text.XML.Light.Proc import Text.XML.Light.Types import Data.Maybe import Data.List
import System.Directory
parse s = let contents = parseXML s quotes = concatMap (findElements $ qqName "item") (onlyElems contents) symbols = map (findAttr $ qqName "file") quotes files = map fromJust symbols qqName name = QName name Nothing Nothing in files
接着,再写一个函数将找出来的所有文件复制到 U 盘中。
copyMP3 [] = do return () copyMP3 (x:xs) = do let output = "U:\\" ++ findFilename x copyFile x output copyMP3 xs
findFilename s = drop (length s - (fromJust $ findIndex (=='\\') $ reverse s)) s
main = do s <- readFile "r:\\test.ttpl" copyMP3 $ parse s putStrLn "ok"