Skip to content

Commit

Permalink
Resolve #2
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudcrypt committed Aug 26, 2019
1 parent 9091af3 commit f44567f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 11 deletions.
6 changes: 4 additions & 2 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ extra-source-files:
- ChangeLog.md

# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
synopsis: Haskell library for m3u8 stream parsing, downloading, and decrypting.
category: Web

# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
Expand All @@ -32,6 +32,8 @@ dependencies:
- SafeSemaphore
- SimpleAES
- hxt-unicode
- containers
- split

library:
source-dirs: src
Expand Down
46 changes: 38 additions & 8 deletions src/M3U8.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,61 @@
module M3U8
(
streams,
segmentUrls
segmentUrls,
Stream(..),
StreamType(..)
) where

import Text.Regex.Posix
import qualified Data.Map.Strict as Map
import Data.List.Split
import Network.HTTP.Conduit (simpleHttp)

import M3U8.Util

data Stream = Stream { getStreamMeta :: Map.Map String String
, getStreamUrl :: String
, getStreamType :: StreamType } deriving (Eq)

instance Show Stream where
show (Stream s url Video) = "Video Stream: "++(s Map.! "RESOLUTION")++(case Map.member "AUDIO" s of
True -> ", "++(s Map.! "AUDIO")
False -> "")
show (Stream s url Audio) = "Audio Stream: "++(case Map.member "AUDIO" s of
True -> s Map.! "AUDIO"
False -> url)

data StreamType = Video | Audio
deriving (Eq, Show)

toStream :: (Map.Map String String, String) -> Stream
toStream (meta, url) = case Map.member "RESOLUTION" meta of
True -> Stream meta url Video
False -> Stream meta url Audio

baseUrl :: String -> String
baseUrl url = reverse $ dropWhile (\x -> x /= '/') $ reverse url

fixUrl :: String -> String -> String
fixUrl base url = if (take 4 url == "http") then url else (base++url)

isVideoStreamLine :: String -> Bool
isVideoStreamLine str = take 18 str == "#EXT-X-STREAM-INF:" && contains "RESOLUTION" str
isStreamLine :: String -> Bool
isStreamLine str = take 18 str == "#EXT-X-STREAM-INF:"

parseMeta :: String -> Map.Map String String
parseMeta str = Map.fromList $ map (tuplify2 . splitOn "=" . init) matches
where
matches = getAllTextMatches ((drop 18 (str++",")) =~ "[^,]+=(([^,\"]+)|(\"[^\"]+\"))," :: AllTextMatches [] String)

streamsFromStr :: String -> String -> [(String, String)]
streamsFromStr manifestStr url = zip (map snd metas) urls
streamsFromStr :: String -> String -> [Stream]
streamsFromStr manifestStr url = map toStream $ zip metas urls
where
metas = filter (isVideoStreamLine . snd) $ enumerate 0 manifestLines
urls = map (fixUrl (baseUrl url)) $ map ((!!) manifestLines . (+) 1 . fst) metas
metaPairs = filter (isStreamLine . snd) $ enumerate 0 manifestLines
urls = map (fixUrl (baseUrl url)) $ map ((!!) manifestLines . (+) 1 . fst) metaPairs
metas = map parseMeta (map snd metaPairs)
manifestLines = lines manifestStr

streams :: String -> IO [(String, String)]
streams :: String -> IO [Stream]
streams url = do
manifestHtml <- simpleHttp url
let manifestStr = toString manifestHtml
Expand Down
1 change: 1 addition & 0 deletions src/M3U8/Downloader.hs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ saveSegments urls = displayConsoleRegions $ do
return files

data DecryptMode = Off | ZeroIV | SequentialIV
deriving (Show, Eq)

appendAndDecrypt :: String -> DecryptMode -> Maybe B.ByteString -> ProgressBar -> (Int, String) -> IO ()
appendAndDecrypt output dm key pg (i, file) = do
Expand Down
6 changes: 5 additions & 1 deletion src/M3U8/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ module M3U8.Util
contains,
toString,
parseStreamInfo,
removeColons
removeColons,
tuplify2
) where

import System.IO (hFlush, stdout)
Expand All @@ -34,6 +35,9 @@ printList strs = putStrLn $ intercalate "\n" strs
contains :: String -> String -> Bool
contains s1 s2 = Txt.isInfixOf (Txt.pack s1) (Txt.pack s2)

tuplify2 :: [a] -> (a,a)
tuplify2 [x,y] = (x,y)

removeColons :: String -> String
removeColons str = filter (\c -> c /= ':') str

Expand Down

0 comments on commit f44567f

Please sign in to comment.