along with FuncTorrent; if not, see <http://www.gnu.org/licenses/>
-}
+{-# LANGUAGE OverloadedStrings #-}
+
-- | Parse magnet URI
-- The spec for magnetURI: https://en.wikipedia.org/wiki/Magnet_URI_scheme
-- An example from tpb:
module FuncTorrent.MagnetURI where
+import Text.ParserCombinators.Parsec
+import qualified Text.Parsec.ByteString as ParsecBS
+import Data.ByteString.Char8 (ByteString, pack)
+
+data Magnetinfo = Magnetinfo { infoHash :: ByteString
+ , trackerlist :: [String]
+ , name :: String
+ , xlen :: Maybe Integer
+ }
+ deriving (Eq, Show)
+
+magnetHdr :: ParsecBS.Parser String
+magnetHdr = string "magnet:?"
+
+kvpair :: ParsecBS.Parser (String, String)
+kvpair = do
+ k <- many1 letter
+ _ <- char '='
+ v <- many1 (letter <|> digit <|> (char ':'))
+ return (k, v)
+
+magnetBody :: ParsecBS.Parser Magnetinfo
+magnetBody = do
+ pairs <- kvpair `sepBy1` (char '&')
+ -- walk through pairs, populate Magnetinfo (fold?)
+ return $ foldl f magnetInfo pairs
+ where f magnetRecord pair = let (k, v) = pair in
+ case k of
+ "xt" -> magnetRecord { infoHash = pack v }
+ "tr" -> let trVal = trackerlist magnetRecord in
+ magnetRecord { trackerlist = trVal ++ [v] }
+ "dn" -> magnetRecord { name = v }
+ "xl" -> magnetRecord { xlen = Just (read v :: Integer) }
+ magnetInfo = Magnetinfo { infoHash = mempty
+ , trackerlist = mempty
+ , name = mempty
+ , xlen = Nothing }
+
+magnetUri :: ParsecBS.Parser Magnetinfo
+magnetUri = magnetHdr >> magnetBody
+parseMagneturi :: ByteString -> Either ParseError Magnetinfo
+parseMagneturi input = parse magnetUri "magnetParse" input