elm-twitch/src/Core.elm

217 lines
6.5 KiB
Elm

module Core exposing (FullModel(..), Model, Msg(..), Page(..), init, subscriptions, update)
import Browser.Events as Events
import Browser.Navigation as Nav
import Dict exposing (Dict)
import Element
import Ports
import Task
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
| Loading
| Playlist Twitch.PlaylistWithVideos
| Video Twitch.PlaylistWithVideos Twitch.Video
type Msg
= Noop
| PlaylistsReceived ( List Twitch.Playlist, Time.Zone )
| HomeClicked
| PlaylistClicked String
| PlaylistReceived Twitch.PlaylistWithVideos
| PlaylistReceivedVideo String (Maybe Int) Twitch.PlaylistWithVideos
| VideoClicked Twitch.PlaylistWithVideos Twitch.Video
| UrlReceived Url.Url
| 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
, Task.perform PlaylistsReceived Twitch.fetchPlaylists
)
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)
)
( VideoClicked playlist video, Loaded m ) ->
( model
, Nav.pushUrl m.key ("#" ++ playlist.url ++ Twitch.videoName video)
)
( UrlReceived url, Loaded m ) ->
let
splits =
String.split "?" (Maybe.withDefault "" url.fragment)
( split, args ) =
case splits of
h1 :: h2 :: _ ->
( String.split "/" h1 |> List.filter (not << String.isEmpty)
, parseQueryString h2
)
h1 :: _ ->
( String.split "/" h1 |> List.filter (not << String.isEmpty)
, 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 =
case m.page of
Playlist p ->
Just p
Video p _ ->
Just p
_ ->
Nothing
realVideo =
case playlist of
Just p ->
case List.head (List.filter (\x -> Just (Twitch.videoName x) == videoName) p.videos) of
Just v ->
Just v
_ ->
Nothing
_ ->
Nothing
( page, cmd ) =
case ( ( playlist, realVideo ), ( playlistName, videoName ) ) of
( ( Just p, _ ), ( Just _, Nothing ) ) ->
( Playlist p
, Cmd.none
)
( ( Just p, Just video ), ( Just _, Just _ ) ) ->
( Video p video
, Ports.registerVideo ( Twitch.videoId video, video.url, time )
)
( ( _, _ ), ( Just name, Nothing ) ) ->
( Loading
, Task.perform
PlaylistReceived
(Twitch.fetchPlaylistWithVideos name)
)
( ( _, _ ), ( Just name, Just video ) ) ->
( Loading
, Task.perform
(PlaylistReceivedVideo video time)
(Twitch.fetchPlaylistWithVideos name)
)
_ ->
( Home, Cmd.none )
in
( Loaded { m | page = page }, cmd )
( PlaylistReceived p, Loaded m ) ->
( Loaded { m | page = Playlist p }, Cmd.none )
( PlaylistReceivedVideo video time playlist, Loaded m ) ->
case List.head (List.filter (\x -> Twitch.videoName x == video) playlist.videos) of
Just v ->
( Loaded { m | page = Video playlist v }
, Ports.registerVideo ( Twitch.videoId v, v.url, time )
)
_ ->
( Loaded { m | page = Home }, Cmd.none )
_ ->
( 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))