196 lines
5.3 KiB
Elm
196 lines
5.3 KiB
Elm
module Core exposing (FullModel(..), Model, Msg(..), Page(..), init, subscriptions, update)
|
|
|
|
import Browser
|
|
import Browser.Events as Events
|
|
import Browser.Navigation as Nav
|
|
import Dict exposing (Dict)
|
|
import Element
|
|
import Http
|
|
import Ports
|
|
import Time
|
|
import Twitch
|
|
import Url
|
|
|
|
|
|
type FullModel
|
|
= Unloaded Element.Device Url.Url Nav.Key
|
|
| Loaded Model
|
|
|
|
|
|
type alias Model =
|
|
{ playlists : List Twitch.Playlist
|
|
, zone : Time.Zone
|
|
, page : Page
|
|
, key : Nav.Key
|
|
, device : Element.Device
|
|
}
|
|
|
|
|
|
type Page
|
|
= Home
|
|
| Playlist Twitch.Playlist
|
|
| Video Twitch.Playlist Twitch.Video
|
|
|
|
|
|
type Msg
|
|
= Noop
|
|
| PlaylistsReceived ( List Twitch.Playlist, Time.Zone )
|
|
| HomeClicked
|
|
| PlaylistClicked Twitch.Playlist
|
|
| VideoClicked Twitch.Playlist Twitch.Video
|
|
| UrlReceived Url.Url
|
|
| UrlRequested Browser.UrlRequest
|
|
| SizeReceived Int Int
|
|
|
|
|
|
init : { width : Int, height : Int } -> Url.Url -> Nav.Key -> ( FullModel, Cmd Msg )
|
|
init { width, height } url key =
|
|
( Unloaded (Element.classifyDevice { width = width, height = height }) url key
|
|
, Twitch.fetchPlaylists resultToMsg
|
|
)
|
|
|
|
|
|
resultToMsg : Result Http.Error (List Twitch.Playlist) -> Msg
|
|
resultToMsg result =
|
|
case result of
|
|
Ok o ->
|
|
PlaylistsReceived ( o, Time.utc )
|
|
|
|
Err _ ->
|
|
Noop
|
|
|
|
|
|
subscriptions : FullModel -> Sub Msg
|
|
subscriptions _ =
|
|
Events.onResize (\w h -> SizeReceived w h)
|
|
|
|
|
|
update : Msg -> FullModel -> ( FullModel, Cmd Msg )
|
|
update msg model =
|
|
case ( msg, model ) of
|
|
( Noop, _ ) ->
|
|
( model, Cmd.none )
|
|
|
|
( SizeReceived w h, Loaded m ) ->
|
|
( Loaded { m | device = Element.classifyDevice { width = w, height = h } }
|
|
, Cmd.none
|
|
)
|
|
|
|
( PlaylistsReceived ( playlists, zone ), Unloaded device url key ) ->
|
|
update
|
|
(UrlReceived url)
|
|
(Loaded { key = key, playlists = playlists, zone = zone, page = Home, device = device })
|
|
|
|
( HomeClicked, Loaded m ) ->
|
|
( model
|
|
, Nav.pushUrl m.key "#"
|
|
)
|
|
|
|
( PlaylistClicked playlist, Loaded m ) ->
|
|
( model
|
|
, Nav.pushUrl m.key ("#" ++ playlist.url)
|
|
)
|
|
|
|
( VideoClicked playlist video, Loaded m ) ->
|
|
( model
|
|
, Nav.pushUrl m.key ("#" ++ playlist.url ++ video.url)
|
|
)
|
|
|
|
( UrlReceived url, Loaded m ) ->
|
|
let
|
|
splits =
|
|
String.split "?" (Maybe.withDefault "" url.fragment)
|
|
|
|
( split, args ) =
|
|
case splits of
|
|
h1 :: h2 :: _ ->
|
|
( String.split "/" h1, parseQueryString h2 )
|
|
|
|
h1 :: _ ->
|
|
( String.split "/" h1, Dict.empty )
|
|
|
|
_ ->
|
|
( [], Dict.empty )
|
|
|
|
time =
|
|
case Maybe.map String.toInt (Dict.get "t" args) of
|
|
Just (Just 0) ->
|
|
Nothing
|
|
|
|
Just (Just t) ->
|
|
Just t
|
|
|
|
_ ->
|
|
Nothing
|
|
|
|
( playlistName, videoName ) =
|
|
case split of
|
|
p :: v :: _ ->
|
|
( Just (p ++ "/"), Just (v ++ "/") )
|
|
|
|
p :: _ ->
|
|
( Just (p ++ "/"), Nothing )
|
|
|
|
_ ->
|
|
( Nothing, Nothing )
|
|
|
|
playlist =
|
|
List.head (List.filter (\x -> Just x.url == playlistName) m.playlists)
|
|
|
|
video =
|
|
case playlist of
|
|
Just p ->
|
|
List.head (List.filter (\x -> Just x.url == videoName) p.videos)
|
|
|
|
_ ->
|
|
Nothing
|
|
|
|
( page, cmd ) =
|
|
case ( playlist, video ) of
|
|
( Just p, Just v ) ->
|
|
( Video p v
|
|
, Ports.registerVideo ( Twitch.videoId v, "videos/" ++ p.url ++ v.url, time )
|
|
)
|
|
|
|
( Just p, Nothing ) ->
|
|
( Playlist p, Cmd.none )
|
|
|
|
_ ->
|
|
( Home, Cmd.none )
|
|
|
|
extraCmd =
|
|
case page of
|
|
Video _ _ ->
|
|
Cmd.none
|
|
|
|
_ ->
|
|
Ports.eraseVideo ()
|
|
in
|
|
( Loaded { m | page = page }, Cmd.batch [ cmd, extraCmd ] )
|
|
|
|
( UrlRequested u, Loaded m ) ->
|
|
case u of
|
|
Browser.Internal url ->
|
|
( model, Nav.pushUrl m.key (Url.toString url) )
|
|
|
|
Browser.External s ->
|
|
( model, Nav.load s )
|
|
|
|
_ ->
|
|
( model, Cmd.none )
|
|
|
|
|
|
splitter : String -> Maybe ( String, String )
|
|
splitter input =
|
|
case String.split "=" input of
|
|
h :: t ->
|
|
Just ( h, String.join "=" t )
|
|
|
|
_ ->
|
|
Nothing
|
|
|
|
|
|
parseQueryString : String -> Dict String String
|
|
parseQueryString input =
|
|
Dict.fromList (List.filterMap splitter (String.split "&" input))
|