diff options
-rw-r--r-- | priv/room.html.eex | 62 | ||||
-rw-r--r-- | priv/static/main.css | 44 | ||||
-rw-r--r-- | priv/static/room/main.js | 59 |
3 files changed, 130 insertions, 35 deletions
diff --git a/priv/room.html.eex b/priv/room.html.eex index 012ec0d..c3ae92e 100644 --- a/priv/room.html.eex +++ b/priv/room.html.eex @@ -2,15 +2,16 @@ <% import Mediasync.Constants -{video_info, websocket_path, state_url, home_button_url} = if in_discord_activity? do +{video_info, websocket_path, state_url, home_button_url, show_snap_button?} = if in_discord_activity? do { %{video_info | url: "/.proxy/room/#{room_id}/video?#{query_param_discord_activity_inner()}"}, "/.proxy/room/#{room_id}/websocket?#{query_param_discord_activity_inner()}", "/.proxy/room/#{room_id}/state.json?#{query_param_discord_activity_inner()}", - "/.proxy/?#{query_param_discord_activity_inner()}" + "/.proxy/?#{query_param_discord_activity_inner()}", + true } else - {video_info, "/room/#{room_id}/websocket", "/room/#{room_id}/state.json", nil} + {video_info, "/room/#{room_id}/websocket", "/room/#{room_id}/state.json", nil, false} end %> <html lang="en"> @@ -27,33 +28,31 @@ end margin: 0; } - @font-face { - font-family: "FontAwesomeSolid"; - src: url("/static/fontawesome-free-6.6.0-web/webfonts/fa-solid-900.woff2") format("woff2"); + div#outerContainer { + display: flex; + flex-direction: row; + align-items: center; + height: 100svh; + width: 100svw; } - .icon-home, .icon-users, .icon-left, .icon-right, .icon-left-right { - font-family: "FontAwesomeSolid"; + div#playerContainer { + /* Default values; JS will adjust depending on actual aspect ratio */ + height: 100svh; + width: 100svw; + /* We should be in the (horizontal) center by default */ + margin: 0 auto; } - .icon-home::before { - content: "\f015"; + div#playerContainer:has(#snap-button.icon-right) { + /* We should be on the left */ + margin-left: 0; } - .icon-users::before { - content: "\f0c0"; - } - - .icon-left::before { - content: "\f30a"; - } - - .icon-right::before { - content: "\f30b"; - } - - .icon-left-right::before { - content: "\f337"; + div#playerContainer:has(#snap-button.icon-left-right) { + /* We should be on the right */ + margin-left: auto; + margin-right: 0; } #state-button-active::after { @@ -67,14 +66,18 @@ end top: 0; } </style> + <!-- Will be modified by JS --> + <style id="extra-styles"></style> </head> <body> - <div id="playerContainer"> - <video-js id="player"> - <source src="<%= Plug.HTML.html_escape(video_info.url) %>" - type="<%= Plug.HTML.html_escape(video_info.content_type) %>"> - </video-js> + <div id="outerContainer"> + <div id="playerContainer"> + <video-js id="player"> + <source src="<%= Plug.HTML.html_escape(video_info.url) %>" + type="<%= Plug.HTML.html_escape(video_info.content_type) %>"> + </video-js> + </div> </div> <script src="/static/video.js/video.min.js"></script> <script> @@ -82,6 +85,7 @@ end const HOME_BUTTON_URL = <%= if home_button_url, do: ~s("#{home_button_url}"), else: "null" %>; const STATE_ELEMENT_INITIAL_TEXT = "loading..."; const STATE_URL = "<%= state_url %>"; + const SHOW_SNAP_BUTTON = <%= show_snap_button? %>; </script> <script src="/static/room/main.js"></script> <script src="/static/room/displayState.js"></script> diff --git a/priv/static/main.css b/priv/static/main.css index 85906c6..9841b35 100644 --- a/priv/static/main.css +++ b/priv/static/main.css @@ -1,3 +1,13 @@ +:root { + box-sizing: border-box; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} + body { background-color: black; color: white; @@ -8,7 +18,35 @@ input { font-family: inherit; } -div#playerContainer { - width: 100svw; - height: 100svh; +@font-face { + font-family: "FontAwesomeSolid"; + src: url("/static/fontawesome-free-6.6.0-web/webfonts/fa-solid-900.woff2") format("woff2"); +} + +.icon-home, +.icon-users, +.icon-left, +.icon-right, +.icon-left-right { + font-family: "FontAwesomeSolid"; +} + +.icon-home::before { + content: "\f015"; +} + +.icon-users::before { + content: "\f0c0"; +} + +.icon-left::before { + content: "\f30a"; +} + +.icon-right::before { + content: "\f30b"; +} + +.icon-left-right::before { + content: "\f337"; } diff --git a/priv/static/room/main.js b/priv/static/room/main.js index 9a0b2ec..8e46f66 100644 --- a/priv/static/room/main.js +++ b/priv/static/room/main.js @@ -26,6 +26,21 @@ } }; + const setPlayerDimensions = (player) => { + document.querySelector("style#extra-styles").textContent = ` + div#playerContainer { + height: 100svh; + width: calc(100svh * ${player.videoWidth() / player.videoHeight()}); + } + @media (orientation: portrait) { + div#playerContainer { + width: 100svw; + height: calc(100svw * ${player.videoHeight() / player.videoWidth()}); + } + } + `; + }; + const player = videojs("player", { controls: true, experimentalSvgIcons: true, @@ -37,6 +52,14 @@ player.ready(() => { setControlsEnabled(player, false); + if (player.readyState() >= 1) { + setPlayerDimensions(player); + } else { + player.on("loadedmetadata", () => { + setPlayerDimensions(player); + }); + } + { let customIconPosition = 1; const Button = videojs.getComponent("Button"); @@ -52,16 +75,46 @@ } const stateButton = new Button(player, { - clickHandler: (event) => { + clickHandler: (_) => { const stateButtonEl = stateButton.el(); - const id = stateButtonEl.getAttribute("id"); - stateButtonEl.setAttribute("id", id ? "" : "state-button-active"); + stateButtonEl.id = stateButtonEl.id ? "" : "state-button-active"; }, }); stateButton.el().setAttribute("data-text", STATE_ELEMENT_INITIAL_TEXT); stateButton.addClass("icon-users state-element"); stateButton.controlText("Viewers"); player.controlBar.addChild(stateButton, {}, customIconPosition++); + + if (SHOW_SNAP_BUTTON) { + const SNAP_NEXT_L = "icon-left"; + const SNAP_NEXT_R = "icon-right"; + const SNAP_NEXT_LR = "icon-left-right"; + const SNAP_TITLE_L = "Snap Video To Left"; + const SNAP_TITLE_R = "Snap Video To Right"; + const SNAP_TITLE_LR = "Snap Video To Center"; + const snapButton = new Button(player, { + clickHandler: (_) => { + const snapButtonEl = snapButton.el(); + if (snapButtonEl.classList.contains(SNAP_NEXT_L)) { + snapButtonEl.classList.remove(SNAP_NEXT_L); + snapButtonEl.classList.add(SNAP_NEXT_R); + snapButtonEl.title = SNAP_TITLE_R; + } else if (snapButtonEl.classList.contains(SNAP_NEXT_R)) { + snapButtonEl.classList.remove(SNAP_NEXT_R); + snapButtonEl.classList.add(SNAP_NEXT_LR); + snapButtonEl.title = SNAP_TITLE_LR; + } else { + snapButtonEl.classList.remove(SNAP_NEXT_LR); + snapButtonEl.classList.add(SNAP_NEXT_L); + snapButtonEl.title = SNAP_TITLE_L; + } + }, + }); + snapButton.el().id = "snap-button"; + snapButton.addClass(SNAP_NEXT_L); + snapButton.controlText(SNAP_TITLE_L); + player.controlBar.addChild(snapButton, {}, customIconPosition++); + } } const updatePlaybackState = (latestReceivedState, nowMilliseconds) => { |