diff --git a/public/index.html b/public/index.html index a2be7da..7fcc7bd 100644 --- a/public/index.html +++ b/public/index.html @@ -19,7 +19,8 @@ } select, - footer { + footer, + .downloadList { margin-left: auto; margin-right: auto; margin-top: 1em; @@ -53,6 +54,31 @@ background-color: #cc60b6; color: #ccc; } + + .downloadList:before { + content: "Direct Download"; + font-weight: bold; + text-decoration: underline; + margin-bottom: 1em; + display: block; + } + + .downloadList { + margin-top: 2em; + width: 500px; + margin-bottom: 2em; + } + + .downloadList > a { + color: #60b5cc; + display: list-item; + margin-top: 0.2em; + text-decoration: none; + } + + .downloadList > a:hover { + color: #ccc; + } @@ -67,7 +93,13 @@ diff --git a/src/Main.elm b/src/Main.elm index 2f160e4..beb8fc9 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -1,15 +1,13 @@ module Main exposing (..) import Browser -import Browser.Navigation -import Url - import Msg -import Update import Request import Types +import Update import View + main : Program Types.Flags Types.Model Msg.Msg main = Browser.application @@ -21,5 +19,16 @@ main = , onUrlRequest = \_ -> Msg.NoOp } -init : Types.Flags -> Url.Url -> Browser.Navigation.Key -> ( Types.Model, Cmd Msg.Msg ) -init _ _ _ = ({ selected = "", videos = [] }, Request.videoList) + +init : Types.Flags -> a -> b -> ( Types.Model, Cmd Msg.Msg ) +init flags _ _ = + ( initialState flags, Request.videoList ) + + +initialState : Types.Flags -> Types.Model +initialState flags = + { selected = Nothing + , videos = [] + , extensions = flags.extentions + , withDownload = Types.withDownload flags + } diff --git a/src/Types.elm b/src/Types.elm index 58d48d4..0912649 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -2,9 +2,26 @@ module Types exposing (..) import Video -type alias Flags = { } +type alias Flags = + { debug : Bool + , extentions : List Video.FileFormat + } type alias Model = - { selected : String + { selected : Maybe String , videos : List Video.Video - } \ No newline at end of file + , extensions : List Video.FileFormat + , withDownload : Bool + } + +videos : Model -> List Video.Video +videos model = model.videos + + -- These functions may seem useless, but that way it's easier to swap out + -- from flags without changing the init function. + +debugEnabled : Flags -> Bool +debugEnabled flags = flags.debug + +withDownload : Flags -> Bool +withDownload flags = flags.debug \ No newline at end of file diff --git a/src/Update.elm b/src/Update.elm index a847cfc..c2c836c 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -6,7 +6,7 @@ import Types update : Msg.Msg -> Types.Model -> ( Types.Model, Cmd Msg.Msg ) update msg model = case msg of - Msg.VideoSelected path -> ({model | selected = path}, Cmd.none) + Msg.VideoSelected path -> ({model | selected = Just path}, Cmd.none) Msg.VideoListLanded response -> case response of Ok videos -> ({model | videos = videos}, Cmd.none) diff --git a/src/Video.elm b/src/Video.elm index 0b3767a..7af1846 100644 --- a/src/Video.elm +++ b/src/Video.elm @@ -1,13 +1,19 @@ module Video exposing (..) +import Html +import Html.Attributes import Json.Decode -import Http type alias Video = { title : String , path : String } +type alias FileFormat = + { extention : String + , mime : String + } + videoListDecoder : Json.Decode.Decoder (List Video) videoListDecoder = Json.Decode.list videoDecoder @@ -15,4 +21,23 @@ videoDecoder : Json.Decode.Decoder Video videoDecoder = Json.Decode.map2 Video (Json.Decode.field "Title" Json.Decode.string) - (Json.Decode.field "Path" Json.Decode.string) \ No newline at end of file + (Json.Decode.field "Path" Json.Decode.string) + +htmlSourceElem : String -> FileFormat -> Html.Html msg +htmlSourceElem path format = + Html.source + [ Html.Attributes.src (path ++ "." ++ format.extention) + , Html.Attributes.type_ format.mime + ] [] + +downloadLink : String -> FileFormat -> Html.Html msg +downloadLink path format = + Html.a + [ Html.Attributes.href (path ++ "." ++ format.extention) + , Html.Attributes.download <| filename path format + ] + [ Html.text <| filename path format ] + +filename : String -> FileFormat -> String +filename path format = + (Maybe.withDefault "unknown" <| List.head <| List.drop 1 <| String.split "/" path) ++ "." ++ format.extention \ No newline at end of file diff --git a/src/View.elm b/src/View.elm index 9131b1e..bcd1795 100644 --- a/src/View.elm +++ b/src/View.elm @@ -8,13 +8,15 @@ import Html.Events as Events import Msg import Types import Video +import Types exposing (withDownload) view : Types.Model -> Document Msg.Msg view model = { title = "Minimal WebPlayer" , body = - [ if List.length model.videos == 0 then Html.div [] [] else makeDropDown model.videos - , if model.selected == "" then Html.div [] [] else makePlayer model.selected + [ makeDropDown model.videos + , makePlayer model + , downloadList model , Html.footer [] [ Html.text "Handmade with love (and Vim and elm) ;)" , Html.a @@ -25,23 +27,40 @@ view model = ] } +empty : Html.Html Msg.Msg +empty = Html.div [] [] + makeDropDown : List Video.Video -> Html.Html Msg.Msg makeDropDown videos = - Html.select [ Events.onInput Msg.VideoSelected ] - <| makeOption {title = "Select one please ;)", path = ""} :: (List.map makeOption videos) + if List.isEmpty videos + then empty + else + Html.select [ Events.onInput Msg.VideoSelected ] + <| makeOption {title = "Select one please ;)", path = ""} :: (List.map makeOption videos) makeOption : Video.Video -> Html.Html Msg.Msg makeOption video = Html.option [ Html.Attributes.value video.path ] [ Html.text video.title ] -makePlayer : String -> Html.Html Msg.Msg -makePlayer path = - Html.video - [ Html.Attributes.width 960 - , Html.Attributes.height 650 - , Html.Attributes.controls True - ] - [ Html.source [Html.Attributes.src (path ++ ".mkv"), Html.Attributes.type_ "video/x-matroska"] [] - , Html.source [Html.Attributes.src (path ++ ".mp4"), Html.Attributes.type_ "video/mp4"] [] - ] \ No newline at end of file +makePlayer : Types.Model -> Html.Html Msg.Msg +makePlayer model = + case model.selected of + Nothing -> empty + Just path -> + Html.video + [ Html.Attributes.width 960 + , Html.Attributes.height 650 + , Html.Attributes.controls True + ] <| List.map (Video.htmlSourceElem path) model.extensions + +downloadList : Types.Model -> Html.Html Msg.Msg +downloadList model = + let + selected = if not model.withDownload then Nothing else model.selected + in + case selected of + Nothing -> empty + Just path -> + Html.div [ Html.Attributes.class "downloadList" ] + <| List.map (\e -> Video.downloadLink path e) model.extensions \ No newline at end of file