10 Commits

Author SHA1 Message Date
tforgione e9db1724ac Major updates 2025-07-08 08:58:05 +02:00
tforgione 138433d32a Update to latest elm-video 2024-08-02 17:21:42 +02:00
tforgione a770755e67 Update elm-video 2024-08-02 16:47:10 +02:00
tforgione dcfc677331 Update to latest elm-video 2021-12-09 17:34:53 +01:00
tforgione 62004d9e56 Update elm-video 2021-07-02 10:23:30 +02:00
tforgione e706447e42 Fix miniatures 2021-06-22 09:21:37 +02:00
tforgione a8cba787bc Update makefile 2021-06-21 16:07:55 +02:00
tforgione b26cc79787 Update elm-video 2021-06-21 15:57:56 +02:00
tforgione ab510e4ec2 Update elm-video 2021-06-21 15:16:58 +02:00
tforgione 31cc8a1bb9 An attempt to work with elm-video 2021-06-21 11:30:31 +02:00
16 changed files with 185 additions and 2452 deletions
+1 -3
View File
@@ -1,6 +1,4 @@
videos
elm-stuff
js/main.js
js/main.tmp.js
js/main.min.js
js
deploy.sh
+3
View File
@@ -0,0 +1,3 @@
[submodule "elm-video"]
path = elm-video
url = https://github.com/polymny/elm-video
+2 -2
View File
@@ -18,13 +18,13 @@ dev: js/main.js
release: js/main.min.js
js/main.js: src/**
js/main.js: src/** elm-video/src/**
$(ELM) make src/Main.elm --output $(BUILD_DIR)/main.js
js/main.min.js: js/main.tmp.js
@$(UGLIFYJS) $(BUILD_DIR)/main.tmp.js --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle > $(BUILD_DIR)/main.min.js
js/main.tmp.js: src/**
js/main.tmp.js: src/** elm-video/src/**
@$(ELM) make src/Main.elm --optimize --output $(BUILD_DIR)/main.tmp.js
watch:
-78
View File
@@ -1,78 +0,0 @@
.lds-spinner {
color: official;
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-spinner div {
transform-origin: 40px 40px;
animation: lds-spinner 1.2s linear infinite;
}
.lds-spinner div:after {
content: " ";
display: block;
position: absolute;
top: 3px;
left: 37px;
width: 6px;
height: 18px;
border-radius: 20%;
background: #cef;
}
.lds-spinner div:nth-child(1) {
transform: rotate(0deg);
animation-delay: -1.1s;
}
.lds-spinner div:nth-child(2) {
transform: rotate(30deg);
animation-delay: -1s;
}
.lds-spinner div:nth-child(3) {
transform: rotate(60deg);
animation-delay: -0.9s;
}
.lds-spinner div:nth-child(4) {
transform: rotate(90deg);
animation-delay: -0.8s;
}
.lds-spinner div:nth-child(5) {
transform: rotate(120deg);
animation-delay: -0.7s;
}
.lds-spinner div:nth-child(6) {
transform: rotate(150deg);
animation-delay: -0.6s;
}
.lds-spinner div:nth-child(7) {
transform: rotate(180deg);
animation-delay: -0.5s;
}
.lds-spinner div:nth-child(8) {
transform: rotate(210deg);
animation-delay: -0.4s;
}
.lds-spinner div:nth-child(9) {
transform: rotate(240deg);
animation-delay: -0.3s;
}
.lds-spinner div:nth-child(10) {
transform: rotate(270deg);
animation-delay: -0.2s;
}
.lds-spinner div:nth-child(11) {
transform: rotate(300deg);
animation-delay: -0.1s;
}
.lds-spinner div:nth-child(12) {
transform: rotate(330deg);
animation-delay: 0s;
}
@keyframes lds-spinner {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
-1664
View File
File diff suppressed because one or more lines are too long
Submodule
+1
Submodule elm-video added at 4193ac975d
+6 -2
View File
@@ -1,25 +1,29 @@
{
"type": "application",
"source-directories": [
"src"
"src",
"elm-video/src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"STTR13/ziplist": "1.3.0",
"andrewMacmurray/elm-simple-animation": "2.1.0",
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/svg": "1.0.1",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"icidasset/elm-material-icons": "9.0.0",
"jims/html-parser": "1.0.0",
"justinmimbs/timezone-data": "3.0.3",
"mdgriffith/elm-ui": "1.1.8",
"rtfeldman/elm-iso8601-date-strings": "1.1.3"
},
"indirect": {
"avh4/elm-color": "1.0.0",
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/parser": "1.1.0",
+24
View File
@@ -0,0 +1,24 @@
<!doctype HTML>
<html>
<head>
<title>twitch.tforgione.fr</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/ico" href="favicon.ico"/>
</head>
<body>
<div id="container"></div>
<script src="js/polymny-video-full.min.js"></script>
<script src="js/main.js"></script>
<script>
PolymnyVideo.fullpage({
node: document.getElementById('container'),
url: "videos/" + PolymnyVideo.getArgumentFromUrl("v") + "/manifest.m3u8",
autoplay: true,
startTime: PolymnyVideo.getArgumentFromUrl("t"),
enableMiniatures: true,
});
</script>
</body>
</html>
+5 -27
View File
@@ -4,13 +4,11 @@
<title>twitch.tforgione.fr</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/ico" href="/favicon.ico"/>
<link href="css/video-js.css" rel="stylesheet">
<link href="css/spinner.css" rel="stylesheet">
<link rel="icon" type="image/ico" href="favicon.ico"/>
</head>
<body>
<div id="container"></div>
<script src="js/vd.js"></script>
<script src="js/polymny-video-elm.min.js"></script>
<script src="js/main.js"></script>
<script>
function isDarkMode(e) {
@@ -33,34 +31,14 @@
width: window.innerWidth,
height: window.innerHeight,
darkMode: isDarkMode(),
darkSetting: JSON.parse(localStorage.getItem('darkMode'))
darkSetting: JSON.parse(localStorage.getItem('darkMode')),
mobile: PolymnyVideo.isDeviceMobile(),
}
});
var lastId, player;
PolymnyVideo.setup(app);
if (app.ports !== undefined) {
if (app.ports.registerVideo !== undefined) {
app.ports.registerVideo.subscribe(function(args) {
window.scrollTo(0, 0);
var time = vd.parseTime(args[2]) || undefined;
requestAnimationFrame(function() {
if (args[0] !== lastId) {
lastId = args[0];
player = vd.setup(args[0], {
v: args[1] + "/manifest.m3u8",
t: time,
focus: true
});
} else if (time !== undefined ){
player.currentTime(time);
}
});
});
}
if (app.ports.setDarkMode !== undefined) {
app.ports.setDarkMode.subscribe(function(arg) {
if (arg === null) {
-562
View File
File diff suppressed because one or more lines are too long
-12
View File
@@ -1,24 +1,12 @@
module Consts exposing
( homeFontSize
, homePadding
, name
, normalFontSize
, titleFontSize
, url
, videoId
)
url : String
url =
"twitch.tforgione.fr"
name : String
name =
url
normalFontSize : Int
normalFontSize =
13
+82 -22
View File
@@ -13,10 +13,13 @@ import Time
import TimeZone
import Twitch
import Url
import Video
import Video.Events
type alias Model =
{ playlists : List Twitch.Playlist
{ title : String
, playlists : List Twitch.Playlist
, zone : Time.Zone
, page : Page
, key : Nav.Key
@@ -26,13 +29,15 @@ type alias Model =
, url : Url.Url
, darkMode : Bool
, darkSetting : Maybe Bool
, reverseVideos : Bool
, mobile : Bool
}
type Page
= Home (Maybe (Hover Twitch.Playlist))
| Playlist Twitch.Playlist (Maybe (Hover Twitch.Video))
| Video Twitch.Playlist Twitch.Video (Maybe (Hover Twitch.Video))
| Video Twitch.Playlist Twitch.Video Video.Video (Maybe (Hover Twitch.Video))
type Msg
@@ -53,11 +58,24 @@ type Msg
| CurrentDateReceived Time.Posix
| DarkMode Bool
| DarkModeClicked
| VideoMsg Video.Msg
init : { width : Int, height : Int, darkMode : Bool, darkSetting : Maybe Bool } -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init { width, height, darkMode, darkSetting } url key =
init :
{ title : Maybe String
, width : Int
, height : Int
, darkMode : Bool
, darkSetting : Maybe Bool
, reverseVideos : Maybe Bool
, mobile : Maybe Bool
}
-> Url.Url
-> Nav.Key
-> ( Model, Cmd Msg )
init { title, width, height, darkMode, darkSetting, reverseVideos, mobile } url key =
( Model
(Maybe.withDefault "elm-video-example" title)
[]
Time.utc
(Home Nothing)
@@ -68,6 +86,8 @@ init { width, height, darkMode, darkSetting } url key =
url
darkMode
darkSetting
(Maybe.withDefault False reverseVideos)
(Maybe.withDefault False mobile)
, Cmd.batch
[ Task.attempt TimeZoneReceivedResult TimeZone.getZone
, Task.perform CurrentDateReceived Time.now
@@ -87,11 +107,19 @@ resultToMsg result =
subscriptions : Model -> Sub Msg
subscriptions _ =
subscriptions model =
Sub.batch
[ Events.onResize (\w h -> SizeReceived w h)
, Time.every 200 TimeReceived
, Ports.darkMode DarkMode
, Sub.map VideoMsg
(case model.page of
Video _ _ v _ ->
Video.Events.subs v
_ ->
Sub.none
)
]
@@ -129,8 +157,8 @@ update msg model =
Playlist p Nothing ->
( { model | page = Playlist p (Just (Hover.hover hover model.time)) }, Cmd.none )
Video p v Nothing ->
( { model | page = Video p v (Just (Hover.hover v model.time)) }, Cmd.none )
Video p v x Nothing ->
( { model | page = Video p v x (Just (Hover.hover hover model.time)) }, Cmd.none )
_ ->
( model, Cmd.none )
@@ -143,8 +171,8 @@ update msg model =
Playlist p _ ->
( { model | page = Playlist p Nothing }, Cmd.none )
Video p v _ ->
( { model | page = Video p v Nothing }, Cmd.none )
Video p v x _ ->
( { model | page = Video p v x Nothing }, Cmd.none )
SizeReceived w h ->
( { model | device = Element.classifyDevice { width = w, height = h } }
@@ -152,9 +180,18 @@ update msg model =
)
PlaylistsReceived playlists ->
let
sortedPlaylists =
if model.reverseVideos then
List.reverse playlists
|> List.map (\x -> { x | videos = List.reverse x.videos })
else
playlists
in
update
(UrlReceived model.url)
{ model | playlists = playlists, page = Home Nothing }
{ model | playlists = sortedPlaylists, page = Home Nothing }
HomeClicked ->
( model
@@ -234,25 +271,32 @@ update msg model =
( page, cmd ) =
case ( playlist, video ) of
( Just p, Just v ) ->
( Video p v Nothing
, Ports.registerVideo ( Twitch.videoId v, "videos/" ++ p.url ++ v.url, time )
)
let
( rawVideo, videoCommand ) =
Video.fromConfig
{ url = "/videos/" ++ p.url ++ v.url ++ "/manifest.m3u8"
, id = "video"
, autoplay = True
, enableMiniatures = True
, startTime = time
, customElement = Nothing
, live = Just False
, miniaturesUrl = Nothing
, muted = False
}
el =
{ rawVideo | mobile = model.mobile }
in
( Video p v el Nothing, Cmd.map VideoMsg videoCommand )
( Just p, Nothing ) ->
( Playlist p Nothing, Cmd.none )
_ ->
( Home Nothing, Cmd.none )
extraCmd =
case page of
Video _ _ _ ->
Cmd.none
_ ->
Ports.eraseVideo ()
in
( { model | page = page }, Cmd.batch [ cmd, extraCmd ] )
( { model | page = page }, cmd )
UrlRequested u ->
case u of
@@ -265,6 +309,22 @@ update msg model =
DarkMode dark ->
( { model | darkMode = dark }, Cmd.none )
VideoMsg vMsg ->
let
( newPage, newCommand ) =
case model.page of
Video a b v c ->
let
( newVideo, cmd ) =
Video.update vMsg v
in
( Video a b newVideo c, cmd )
_ ->
( model.page, Cmd.none )
in
( { model | page = newPage }, Cmd.map VideoMsg newCommand )
splitter : String -> Maybe ( String, String )
splitter input =
+12 -1
View File
@@ -5,7 +5,18 @@ import Core
import Views
main : Program { width : Int, height : Int, darkMode : Bool, darkSetting : Maybe Bool } Core.Model Core.Msg
main :
Program
{ title : Maybe String
, width : Int
, height : Int
, darkMode : Bool
, darkSetting : Maybe Bool
, reverseVideos : Maybe Bool
, mobile : Maybe Bool
}
Core.Model
Core.Msg
main =
Browser.application
{ init = Core.init
+1 -7
View File
@@ -1,10 +1,4 @@
port module Ports exposing (darkMode, eraseVideo, registerVideo, setDarkMode)
port registerVideo : ( String, String, Maybe String ) -> Cmd msg
port eraseVideo : () -> Cmd msg
port module Ports exposing (darkMode, setDarkMode)
port setDarkMode : Maybe Bool -> Cmd msg
+2 -2
View File
@@ -46,12 +46,12 @@ 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)))
(Decode.field "videos" (Decode.map (List.sortBy .url) (Decode.list decodeVideo)))
decodePlaylists : Decode.Decoder (List Playlist)
decodePlaylists =
Decode.map (sortPlaylists >> List.reverse) (Decode.list decodePlaylist)
Decode.map sortPlaylists (Decode.list decodePlaylist)
mostRecentVideo : List Video -> Maybe Time.Posix
+46 -70
View File
@@ -12,13 +12,13 @@ import Element.Font as Font
import Element.Input as Input
import Element.Keyed as Keyed
import Hover exposing (Hover)
import Html
import Html.Attributes
import Json.Encode as Encode
import Time
import TimeUtils
import Twitch
import Ui
import Video
import Video.Views
view : Core.Model -> Browser.Document Core.Msg
@@ -42,7 +42,7 @@ view model =
]
(Element.column
[ Element.width Element.fill, Element.height Element.fill ]
[ topBar model.darkSetting, element ]
[ topBar model.title model.darkSetting, element ]
)
]
}
@@ -52,13 +52,13 @@ title : Core.Model -> String
title model =
case model.page of
Core.Home _ ->
Consts.url
model.title
Core.Playlist p _ ->
Consts.url ++ " - " ++ p.name
model.title ++ " - " ++ p.name
Core.Video p v _ ->
Consts.url ++ " - " ++ p.name ++ " - " ++ v.name
Core.Video p v _ _ ->
model.title ++ " - " ++ p.name ++ " - " ++ v.name
viewContent : Core.Model -> Element Core.Msg
@@ -70,19 +70,19 @@ viewContent model =
Core.Playlist playlist hover ->
videoMiniaturesView model.darkMode model.device model.zone model.currentDate model.time hover playlist
Core.Video playlist video hover ->
videoView model.darkMode model.device model.zone model.currentDate model.time hover playlist video
Core.Video playlist video v hover ->
videoView model.darkMode model.device model.zone model.currentDate model.time hover playlist video v
topBar : Maybe Bool -> Element Core.Msg
topBar darkSetting =
topBar : String -> Maybe Bool -> Element Core.Msg
topBar pageTitle darkSetting =
Element.row
[ Element.width Element.fill
, Background.color Colors.primary
, Font.color Colors.white
, Font.size Consts.homeFontSize
]
[ homeButton, mode darkSetting ]
[ homeButton pageTitle, mode darkSetting ]
mode : Maybe Bool -> Element Core.Msg
@@ -110,13 +110,13 @@ mode current =
}
homeButton : Element Core.Msg
homeButton =
homeButton : String -> Element Core.Msg
homeButton pageTitle =
Ui.link
[ Element.height Element.fill
, Font.bold
]
{ label = Element.el [ Element.padding 10 ] (Element.text Consts.name)
{ label = Element.el [ Element.padding 10 ] (Element.text pageTitle)
, url = "/"
}
@@ -293,8 +293,6 @@ videoMiniature currentDate time hover playlist video =
, Element.height (Element.px 0)
, Element.htmlAttribute (Html.Attributes.style "padding-top" "56.25%")
, Element.htmlAttribute (Html.Attributes.style "position" "relative")
, Events.onMouseEnter (Core.HoverVideo video)
, Events.onMouseLeave Core.Unhover
]
( key
, Element.image
@@ -318,9 +316,14 @@ videoMiniatureView : Bool -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hov
videoMiniatureView darkMode zone currentDate time hover playlist video =
let
display =
Element.column [ Element.width Element.fill, Element.spacing 10 ]
Element.column
[ Element.width Element.fill
, Element.spacing 10
, Events.onMouseEnter (Core.HoverVideo video)
, Events.onMouseLeave Core.Unhover
]
[ videoMiniature currentDate time hover playlist video
, videoDescription darkMode zone video
, videoDate darkMode zone video
]
button =
@@ -336,11 +339,16 @@ videoInList : Bool -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twit
videoInList darkMode zone currentDate time hover playlist activeVideo video =
let
label =
Element.row [ Element.width Element.fill, Element.spacing 10 ]
Element.row
[ Element.width Element.fill
, Element.spacing 10
, Events.onMouseEnter (Core.HoverVideo video)
, Events.onMouseLeave Core.Unhover
]
[ Element.el [ Element.width (Element.fillPortion 2) ]
(videoMiniature currentDate time hover playlist video)
, Element.el [ Element.width (Element.fillPortion 3), Element.paddingXY 0 10, Element.alignTop ]
(videoDescription darkMode zone video)
(videoDate darkMode zone video)
]
in
if video == activeVideo then
@@ -359,8 +367,8 @@ videoInList darkMode zone currentDate time hover playlist activeVideo video =
}
videoView : Bool -> Element.Device -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoView darkMode device zone currentDate time hover playlist video =
videoView : Bool -> Element.Device -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Video.Video -> Element Core.Msg
videoView darkMode device zone currentDate time hover playlist video v =
let
( builder, contentPadding ) =
case device.class of
@@ -379,31 +387,8 @@ videoView darkMode device zone currentDate time hover playlist video =
[ Element.width (Element.fillPortion 2)
, Element.spacing 10
, Element.alignTop
, Element.height Element.fill
]
[ Keyed.el
[ Element.width Element.fill
, Element.height (Element.px 0)
, Element.htmlAttribute (Html.Attributes.style "padding-top" "56.25%")
, Element.htmlAttribute (Html.Attributes.style "position" "relative")
]
( video.url
, Element.html
(Html.video
[ Html.Attributes.id (Twitch.videoId video)
, Html.Attributes.class "video-js"
, Html.Attributes.class "vjs-default-skin"
, Html.Attributes.class "wf"
, Html.Attributes.property "data-setup" (Encode.string "{\"fluid\": true}")
, Html.Attributes.style "position" "absolute"
, Html.Attributes.style "top" "0"
, Html.Attributes.style "height" "100%"
, Html.Attributes.controls True
, Html.Attributes.autoplay True
]
[]
)
)
[ Video.Views.embedElement v |> Element.map Core.VideoMsg
, Element.paragraph
[ Font.size Consts.homeFontSize
, Font.bold
@@ -431,8 +416,8 @@ videoView darkMode device zone currentDate time hover playlist video =
]
videoDescription : Bool -> Time.Zone -> Twitch.Video -> Element Core.Msg
videoDescription darkMode zone video =
videoDate : Bool -> Time.Zone -> Twitch.Video -> Element Core.Msg
videoDate darkMode zone video =
Element.column [ Element.spacing 10 ]
[ Element.paragraph
[ Font.bold
@@ -501,11 +486,17 @@ formatTime time =
else
String.fromInt seconds
in
hoursString
++ ":"
++ minutesString
++ ":"
++ secondsString
if hours >= 1 then
hoursString
++ ":"
++ minutesString
++ ":"
++ secondsString
else
minutesString
++ ":"
++ secondsString
toHours : Int -> Int
@@ -577,22 +568,7 @@ groupAux size list acc =
spinner : Element Core.Msg
spinner =
Element.html
(Html.div [ Html.Attributes.class "lds-spinner" ]
[ Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
, Html.div [] []
]
)
Element.none
newBadge : Element Core.Msg