diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/lord.cabal b/lord.cabal
new file mode 100644
--- /dev/null
+++ b/lord.cabal
@@ -0,0 +1,87 @@
+name:                lord
+version:             1.20130928
+synopsis:            Lord of radio daemon
+description:         
+    A unified interface to online radio service providers, use mpd as backend.
+    .
+    Supported radios:
+    <http://cmd.fm>
+    <http://douban.fm>
+    <http://jing.fm>
+homepage:            https://github.com/rnons/lord
+bug-reports:         https://github.com/rnons/lord/issues
+license:             PublicDomain
+license-file:        LICENSE
+author:              rnons
+maintainer:          remotenonsense@gmail.com
+category:            Web
+build-type:          Simple
+cabal-version:       >=1.10
+tested-with:         GHC == 7.6.3
+
+source-repository   head
+  type:             git
+  location:         git://github.com/rnons/lord.git
+ 
+executable lord
+  main-is:              main.hs         
+  -- other-modules:       
+  ghc-options:          -Wall -fno-warn-unused-do-bind
+  build-depends:        base >= 4 && < 5, 
+                        aeson >= 0.6, 
+                        ansi-terminal >= 0.6, 
+                        attoparsec-conduit >= 1.0, 
+                        bytestring >= 0.9, 
+                        case-insensitive >= 1.0, 
+                        conduit >= 1.0, 
+                        configurator >= 0.2, 
+                        daemons >= 0.1.2,
+                        data-default >= 0.5,
+                        directory >= 1.1, 
+                        fast-logger >= 0.3,
+                        html-conduit >= 1.1, 
+                        http-conduit >= 1.9, 
+                        http-types >= 0.8, 
+                        libmpd >= 0.8, 
+                        optparse-applicative >= 0.5,
+                        text >= 0.11, 
+                        transformers >= 0.3, 
+                        unix >= 2.5, 
+                        unordered-containers >= 0.2, 
+                        utf8-string >= 0.3, 
+                        xml-conduit >= 1.1,
+                        yaml >= 0.8
+  default-language:     Haskell2010
+
+test-suite test
+  type:                 exitcode-stdio-1.0
+  main-is:              test/main.hs
+  ghc-options:          -Wall -fno-warn-unused-do-bind
+  hs-source-dirs:       .
+  build-depends:        base >= 4 && < 5,
+                        aeson >= 0.6, 
+                        ansi-terminal >= 0.6, 
+                        attoparsec-conduit >= 1.0, 
+                        bytestring >= 0.9, 
+                        case-insensitive >= 1.0, 
+                        conduit >= 1.0, 
+                        configurator >= 0.2, 
+                        daemons >= 0.1.2,
+                        data-default >= 0.5,
+                        directory >= 1.1, 
+                        fast-logger >= 0.3,
+                        hspec >= 1.6,
+                        html-conduit >= 1.1, 
+                        http-conduit >= 1.9, 
+                        http-types >= 0.8, 
+                        HUnit >= 1.2,
+                        libmpd >= 0.8, 
+                        optparse-applicative >= 0.5,
+                        text >= 0.11, 
+                        transformers >= 0.3, 
+                        unix >= 2.5, 
+                        unordered-containers >= 0.2, 
+                        utf8-string >= 0.3, 
+                        xml-conduit >= 1.1,
+                        yaml >= 0.8
+  default-language:     Haskell2010
diff --git a/main.hs b/main.hs
new file mode 100644
--- /dev/null
+++ b/main.hs
@@ -0,0 +1,209 @@
+import           Control.Monad (when)
+import qualified Data.ByteString.Char8 as C
+import           Data.Char (isDigit)
+import           Data.Default (def)
+import           Network.MPD (withMPD, clear, status, stState)
+import           Options.Applicative
+import           Options.Applicative.Types (ParserPrefs, ParserInfo)
+import           System.Directory (createDirectoryIfMissing)
+import           System.Environment (getArgs, getProgName)
+import           System.Exit (exitWith, exitSuccess, ExitCode(..))
+import           System.IO ( openFile, IOMode(AppendMode)
+                           , hPutStr, stdout, stderr, SeekMode(..) )
+import           System.Log.FastLogger (mkLogger, Logger)
+import           System.Posix.Daemon
+import           System.Posix.Files (stdFileMode)
+import           System.Posix.IO ( fdWrite, createFile, setLock
+                                 , LockRequest(..) )
+import           System.Posix.Process (getProcessID)
+
+import Radio
+import Radio.Cmd
+import Radio.Douban
+import Radio.Jing
+
+data Options = Options
+    { optCommand    :: Command
+    , optDaemon     :: Bool
+    } deriving (Eq, Show)
+
+data Command = CmdFM CmdSubCommand
+             | DoubanFM DoubanSubCommand
+             | JingFM JingSubCommand
+             | Status
+             | Kill
+    deriving (Eq, Show)
+
+data CmdSubCommand = CmdListen String
+                   | CmdGenreList
+    deriving (Eq, Show)
+
+data DoubanSubCommand = DoubanListen String
+                      | DoubanHot
+                      | DoubanTrending
+                      | DoubanSearch String
+    deriving (Eq, Show)
+
+data JingSubCommand = JingListen String
+    deriving (Eq, Show)
+
+type Keywords = String
+
+optParser :: Parser Options
+optParser = Options 
+    <$> subparser ( command "cmd"           (info (helper <*> cmdOptions)
+                        (progDesc "cmd.fm commander"))
+                 <> command "douban"        (info (helper <*> doubanOptions)
+                        (progDesc "douban.fm commander"))
+                 <> command "jing"          (info (helper <*> jingOptions)
+                        (progDesc "jing.fm commander"))
+                 <> command "status"        (info (pure Status)
+                        (progDesc "show current status"))
+                 <> command "kill"          (info (pure Kill)
+                        (progDesc "kill the current running lord session"))
+                  )
+    <*> switch (long "no-daemon" <> help "don't detach from console")
+
+main :: IO ()
+main = do
+    o <- execParser' $ info (helper <*> optParser) 
+                           (fullDesc <> header "Lord: radio commander")
+    let nodaemon = optDaemon o
+    case optCommand o of
+        CmdFM subCommand ->
+            case subCommand of
+                CmdListen genre   -> listen nodaemon (cmd genre)
+                CmdGenreList      -> cmdGenres
+        DoubanFM subCommand -> 
+            case subCommand of
+                 DoubanListen key -> listen nodaemon (douban key)
+                 DoubanHot        -> doubanHot
+                 DoubanTrending   -> doubanTrending
+                 DoubanSearch key -> doubanSearch key
+        JingFM (JingListen key) -> jingListen nodaemon key
+        Status -> lordStatus
+        Kill -> killLord
+
+-- Taken from Options.Applicative.Extra
+execParser' :: ParserInfo a -> IO a
+execParser' = customExecParser' (prefs idm)
+
+-- Taken from Options.Applicative.Extra
+customExecParser' :: ParserPrefs -> ParserInfo a -> IO a
+customExecParser' pprefs pinfo = do
+    args <- getArgs
+    
+    -- My modification!
+    -- Run lord with no args is equivalent to run lord status.
+    when (null args) $ lordStatus >> exitSuccess
+  
+    case execParserPure pprefs pinfo args of
+        Right a -> return a
+        Left failure -> do
+            progn <- getProgName
+            let c = errExitCode failure
+            msg <- errMessage failure progn
+            case c of
+                ExitSuccess -> putStr msg
+                _           -> hPutStr stderr msg
+            exitWith c
+
+cmdOptions :: Parser Command
+cmdOptions = CmdFM <$> subparser
+    ( command "listen" 
+        (info (helper <*> (CmdListen <$> argument str (metavar "GENRE")))
+              (progDesc "Provide genre to listen to cmd.fm"))
+    <> command "genres" 
+        (info (pure CmdGenreList) (progDesc "List available genres"))
+    )
+
+doubanOptions :: Parser Command
+doubanOptions = DoubanFM <$> subparser 
+    ( command "listen" 
+        (info (helper <*> (DoubanListen <$> argument str (metavar "[<channel_id> | <musician>]")))
+              (progDesc "Provide cid/musician to listen to douban.fm"))
+    <> command "search" 
+        (info (helper <*> (DoubanSearch <$> argument str (metavar "KEYWORDS")))
+              (progDesc "search channels"))
+    <> command "hot" (info (pure DoubanHot) (progDesc "hot channels"))
+    <> command "trending" 
+        (info (pure DoubanTrending) (progDesc "trending up channels"))
+    )
+
+jingOptions :: Parser Command
+jingOptions = JingFM <$> subparser 
+    ( command "listen" 
+        (info (helper <*> (JingListen <$> argument str (metavar "KEYWORDS")))
+              (progDesc "Provide keywords to listen to jing.fm"))
+    )
+
+cmdGenres :: IO ()
+cmdGenres = genres >>= pprGenres
+
+doubanHot :: IO ()
+doubanHot = hot >>= pprChannels
+
+doubanTrending :: IO ()
+doubanTrending = trending >>= pprChannels
+
+doubanSearch :: String -> IO ()
+doubanSearch key = search key >>= pprChannels
+
+cmd :: Keywords -> Radio.Param Cmd
+cmd = Genre
+
+douban :: Keywords -> Radio.Param Douban
+douban k
+    | isChId k = Cid $ read k
+    | otherwise = Musician k
+  where
+    isChId = and . fmap isDigit
+
+jingListen :: Bool -> Keywords -> IO ()
+jingListen nodaemon k = do
+    tok <- readToken k
+    case tok of
+        Just tok' -> do
+            putStrLn $ "Welcome back, " ++ C.unpack (nick tok')
+            listen nodaemon tok'
+        _         -> login k >>= listen nodaemon
+
+listen :: Radio a => Bool -> Radio.Param a -> IO ()
+listen nodaemon param = do
+    -- Make sure ~/.lord exists
+    getLordDir >>= createDirectoryIfMissing False
+
+    pid <- getPidFile
+    logger <- if nodaemon then mkLogger True stdout 
+              else getLogFile >>= flip openFile AppendMode >>= mkLogger True
+    let listen' = play logger param []
+    running <- isRunning pid
+    when running $ killAndWait pid 
+    if nodaemon then runInForeground pid listen'
+                else runDetached (Just pid) def listen'
+
+-- Partially taken from System.Posix.Daemon module
+runInForeground :: FilePath -> IO () -> IO ()
+runInForeground pidFile program = do
+    fd <- createFile pidFile stdFileMode
+    setLock fd (WriteLock, AbsoluteSeek, 0, 0)
+    pid <- getProcessID
+    fdWrite fd (show pid)
+    program
+
+killLord :: IO ()
+killLord = withMPD clear >> getPidFile >>= kill
+
+lordStatus :: IO ()
+lordStatus = do
+    running <- getPidFile >>= isRunning
+    status <- 
+        if running then do
+            st <- fmap stState <$> withMPD status
+            let state = case st of
+                    Right s  -> show s
+                    Left err -> error $ show err
+            song <- getStateFile >>= readFile 
+            return $ "[" ++ state ++ "] " ++ song
+        else return "Not running!"
+    putStrLn status
diff --git a/test/main.hs b/test/main.hs
new file mode 100644
--- /dev/null
+++ b/test/main.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE OverloadedStrings #-}
+import Data.Maybe (fromJust)
+import Test.Hspec
+import Test.HUnit
+
+import Radio
+import Radio.Cmd
+import Radio.Jing
+import Radio.Douban
+
+
+main :: IO ()
+main = do
+    hspec spec
+
+spec :: Spec
+spec = do
+    describe "getPlaylist" $ do
+        it "cmd: given genre" $ do
+            ss <- Radio.getPlaylist (Genre "Dream Pop")
+            assert $ length ss > 0
+
+        it "douban: given channel id" $ do
+            ss <- Radio.getPlaylist (Cid 6)
+            assert $ length ss > 0
+    
+        it "douban: given musician name" $ do
+            ss <- Radio.getPlaylist (Musician "Sigur RóS")
+            assert $ length ss > 0
+
+        it "jing" $ do
+            tok <- readToken "postrock"
+            ss <- Radio.getPlaylist $ fromJust tok
+            assert $ length ss > 0
