149 lines
3.5 KiB
Elm
149 lines
3.5 KiB
Elm
module Twitch exposing
|
|
( Playlist
|
|
, Video
|
|
, decodePlaylists
|
|
, fetchPlaylists
|
|
, playlistMiniatureUrl
|
|
, videoId
|
|
, videoMiniatureUrl
|
|
, videoName
|
|
)
|
|
|
|
import Hover exposing (Hover)
|
|
import Http
|
|
import Iso8601
|
|
import Json.Decode as Decode
|
|
import Time
|
|
|
|
|
|
type alias Video =
|
|
{ name : String
|
|
, url : String
|
|
, duration : Int
|
|
, date : Maybe Time.Posix
|
|
}
|
|
|
|
|
|
type alias Playlist =
|
|
{ url : String
|
|
, name : String
|
|
, videos : List Video
|
|
}
|
|
|
|
|
|
decodeVideo : Decode.Decoder Video
|
|
decodeVideo =
|
|
Decode.map4 Video
|
|
(Decode.field "title" Decode.string)
|
|
(Decode.field "url" Decode.string)
|
|
(Decode.map Basics.round (Decode.field "duration" Decode.float))
|
|
(Decode.maybe (Decode.field "date" Iso8601.decoder))
|
|
|
|
|
|
decodePlaylist : Decode.Decoder Playlist
|
|
decodePlaylist =
|
|
Decode.map3 Playlist
|
|
(Decode.field "url" Decode.string)
|
|
(Decode.field "title" Decode.string)
|
|
(Decode.field "videos" (Decode.map (List.sortBy .url >> List.reverse) (Decode.list decodeVideo)))
|
|
|
|
|
|
decodePlaylists : Decode.Decoder (List Playlist)
|
|
decodePlaylists =
|
|
Decode.map (sortPlaylists >> List.reverse) (Decode.list decodePlaylist)
|
|
|
|
|
|
mostRecentVideo : List Video -> Maybe Time.Posix
|
|
mostRecentVideo videos =
|
|
case ( videos, List.map .date videos ) of
|
|
( _, (Just t) :: _ ) ->
|
|
Just t
|
|
|
|
( _ :: t, Nothing :: _ ) ->
|
|
mostRecentVideo t
|
|
|
|
_ ->
|
|
Nothing
|
|
|
|
|
|
playlistDate : Playlist -> Int
|
|
playlistDate playlist =
|
|
mostRecentVideo playlist.videos
|
|
|> Maybe.map Time.posixToMillis
|
|
|> Maybe.withDefault 0
|
|
|
|
|
|
sortPlaylists : List Playlist -> List Playlist
|
|
sortPlaylists list =
|
|
List.sortBy playlistDate list
|
|
|
|
|
|
fetchPlaylists : (Result Http.Error (List Playlist) -> msg) -> Cmd msg
|
|
fetchPlaylists resultToMsg =
|
|
Http.get
|
|
{ url = "videos/index.json"
|
|
, expect = Http.expectJson resultToMsg decodePlaylists
|
|
}
|
|
|
|
|
|
videoName : Video -> String
|
|
videoName video =
|
|
video.url
|
|
|
|
|
|
videoId : Video -> String
|
|
videoId video =
|
|
String.dropLeft 1 video.url |> String.replace "/" "-"
|
|
|
|
|
|
playlistMiniatureUrl : Time.Posix -> Maybe (Hover Playlist) -> Playlist -> String
|
|
playlistMiniatureUrl currentTime hover playlist =
|
|
let
|
|
skip =
|
|
case hover of
|
|
Nothing ->
|
|
0
|
|
|
|
Just { element, time } ->
|
|
if element == playlist then
|
|
modBy (List.length playlist.videos) ((Time.posixToMillis currentTime - Time.posixToMillis time) // 1000)
|
|
|
|
else
|
|
0
|
|
in
|
|
case List.head (List.drop skip playlist.videos) of
|
|
Just v ->
|
|
"videos/" ++ playlist.url ++ v.url ++ "miniature-050.png"
|
|
|
|
_ ->
|
|
""
|
|
|
|
|
|
videoMiniatureUrl : Time.Posix -> Maybe (Hover Video) -> Playlist -> Video -> String
|
|
videoMiniatureUrl currentTime hover playlist video =
|
|
let
|
|
index =
|
|
case hover of
|
|
Nothing ->
|
|
5
|
|
|
|
Just { element, time } ->
|
|
if element == video then
|
|
modBy 11 ((Time.posixToMillis currentTime - Time.posixToMillis time) // 1000)
|
|
|
|
else
|
|
5
|
|
|
|
indexString =
|
|
case index of
|
|
10 ->
|
|
"100"
|
|
|
|
0 ->
|
|
"000"
|
|
|
|
n ->
|
|
"0" ++ String.fromInt n ++ "0"
|
|
in
|
|
"videos/" ++ playlist.url ++ video.url ++ "miniature-" ++ indexString ++ ".png"
|