136 lines
3.2 KiB
Elm
136 lines
3.2 KiB
Elm
|
module Twitch exposing (Playlist, Video, fetchPlaylists)
|
||
|
|
||
|
import Html.Parser
|
||
|
import Http
|
||
|
import Json.Decode as Decode
|
||
|
import Task exposing (Task)
|
||
|
|
||
|
|
||
|
type alias Playlist =
|
||
|
{ name : String
|
||
|
, videos : List Video
|
||
|
}
|
||
|
|
||
|
|
||
|
type alias Video =
|
||
|
{ name : String
|
||
|
, url : String
|
||
|
}
|
||
|
|
||
|
|
||
|
get : { url : String, resolver : Http.Resolver x a } -> Task x a
|
||
|
get { url, resolver } =
|
||
|
Http.task
|
||
|
{ body = Http.emptyBody
|
||
|
, headers = []
|
||
|
, method = "GET"
|
||
|
, resolver = resolver
|
||
|
, timeout = Nothing
|
||
|
, url = url
|
||
|
}
|
||
|
|
||
|
|
||
|
fetchPlaylists : Task x (List Playlist)
|
||
|
fetchPlaylists =
|
||
|
fetchPlaylistPath |> Task.andThen fetchPlaylistsMapper
|
||
|
|
||
|
|
||
|
fetchPlaylistPath : Task x (List String)
|
||
|
fetchPlaylistPath =
|
||
|
get
|
||
|
{ url = "/videos"
|
||
|
, resolver = Http.stringResolver parsePlaylistPath
|
||
|
}
|
||
|
|
||
|
|
||
|
fetchPlaylist : String -> Task x Playlist
|
||
|
fetchPlaylist name =
|
||
|
get
|
||
|
{ url = "/videos/" ++ name ++ "/description.json"
|
||
|
, resolver = Http.stringResolver parsePlaylist
|
||
|
}
|
||
|
|
||
|
|
||
|
fetchPlaylistsMapper : List String -> Task x (List Playlist)
|
||
|
fetchPlaylistsMapper names =
|
||
|
Task.sequence (List.map fetchPlaylist names)
|
||
|
|
||
|
|
||
|
parsePlaylist : Http.Response String -> Result x Playlist
|
||
|
parsePlaylist result =
|
||
|
case result of
|
||
|
Http.GoodStatus_ _ content ->
|
||
|
case Decode.decodeString decodePlaylist content of
|
||
|
Ok p ->
|
||
|
Ok p
|
||
|
|
||
|
_ ->
|
||
|
Ok { name = "", videos = [] }
|
||
|
|
||
|
_ ->
|
||
|
Ok { name = "", videos = [] }
|
||
|
|
||
|
|
||
|
parsePlaylistPath : Http.Response String -> Result x (List String)
|
||
|
parsePlaylistPath result =
|
||
|
case result of
|
||
|
Http.GoodStatus_ _ content ->
|
||
|
let
|
||
|
withoutDoctype =
|
||
|
if String.startsWith "<!doctype" (String.toLower content) then
|
||
|
String.lines content |> List.drop 1 |> String.join "\n"
|
||
|
|
||
|
else
|
||
|
content
|
||
|
|
||
|
decoded =
|
||
|
Html.Parser.run withoutDoctype
|
||
|
|
||
|
hrefs =
|
||
|
Result.map findHrefs decoded
|
||
|
in
|
||
|
case hrefs of
|
||
|
Ok h ->
|
||
|
Ok h
|
||
|
|
||
|
_ ->
|
||
|
Ok []
|
||
|
|
||
|
_ ->
|
||
|
Ok []
|
||
|
|
||
|
|
||
|
findHrefsAux : List String -> Html.Parser.Node -> List String
|
||
|
findHrefsAux acc node =
|
||
|
case node of
|
||
|
Html.Parser.Element string (( key, value ) :: t) nodes ->
|
||
|
let
|
||
|
newAcc =
|
||
|
if key == "href" then
|
||
|
value :: acc
|
||
|
|
||
|
else
|
||
|
acc
|
||
|
in
|
||
|
findHrefsAux newAcc (Html.Parser.Element string t nodes)
|
||
|
|
||
|
Html.Parser.Element string [] (h :: t) ->
|
||
|
let
|
||
|
attrs =
|
||
|
findHrefsAux [] h
|
||
|
in
|
||
|
findHrefsAux (acc ++ attrs) (Html.Parser.Element string [] t)
|
||
|
|
||
|
_ ->
|
||
|
acc
|
||
|
|
||
|
|
||
|
findHrefs : List Html.Parser.Node -> List String
|
||
|
findHrefs x =
|
||
|
findHrefsAux [] (Html.Parser.Element "" [] x)
|
||
|
|
||
|
|
||
|
decodePlaylist : Decode.Decoder Playlist
|
||
|
decodePlaylist =
|
||
|
Decode.map (\x -> Playlist x []) (Decode.field "title" Decode.string)
|