diff --git a/receivers/common/web/FCastSession.ts b/receivers/common/web/FCastSession.ts index f7a6b27..ede0a58 100644 --- a/receivers/common/web/FCastSession.ts +++ b/receivers/common/web/FCastSession.ts @@ -1,6 +1,6 @@ import * as net from 'net'; import * as log4js from "modules/log4js"; -import { EventEmitter } from 'node:events'; +import { EventEmitter } from 'events'; import { PlaybackErrorMessage, PlaybackUpdateMessage, PlayMessage, SeekMessage, SetSpeedMessage, SetVolumeMessage, VersionMessage, VolumeUpdateMessage } from 'common/Packets'; import { WebSocket } from 'modules/ws'; const logger = log4js.getLogger(); diff --git a/receivers/common/web/TcpListenerService.ts b/receivers/common/web/TcpListenerService.ts index 31e6124..5865b08 100644 --- a/receivers/common/web/TcpListenerService.ts +++ b/receivers/common/web/TcpListenerService.ts @@ -1,6 +1,6 @@ import * as net from 'net'; import { FCastSession, Opcode } from 'common/FCastSession'; -import { EventEmitter } from 'node:events'; +import { EventEmitter } from 'events'; import { Main, errorHandler } from 'src/Main'; export class TcpListenerService { diff --git a/receivers/common/web/WebSocketListenerService.ts b/receivers/common/web/WebSocketListenerService.ts index cb29f3a..3010a20 100644 --- a/receivers/common/web/WebSocketListenerService.ts +++ b/receivers/common/web/WebSocketListenerService.ts @@ -1,5 +1,5 @@ import { FCastSession, Opcode } from 'common/FCastSession'; -import { EventEmitter } from 'node:events'; +import { EventEmitter } from 'events'; import { WebSocket, WebSocketServer } from 'modules/ws'; import { Main, errorHandler } from 'src/Main'; diff --git a/receivers/common/web/main/Preload.ts b/receivers/common/web/main/Preload.ts index db2adb2..851df3c 100644 --- a/receivers/common/web/main/Preload.ts +++ b/receivers/common/web/main/Preload.ts @@ -86,6 +86,7 @@ if (TARGET === 'electron') { playService.cancel(); } + history.pushState({}, '', '../main_window/index.html'); window.open('../player/index.html'); } }); diff --git a/receivers/common/web/main/Renderer.ts b/receivers/common/web/main/Renderer.ts index 8c5bb6a..77bb5cc 100644 --- a/receivers/common/web/main/Renderer.ts +++ b/receivers/common/web/main/Renderer.ts @@ -1,5 +1,6 @@ import QRCode from 'modules/qrcode'; +import { onQRCodeRendered } from 'src/main/Renderer'; window.targetAPI.onDeviceInfo(renderIPsAndQRCode); @@ -45,4 +46,6 @@ function renderIPsAndQRCode() { (e) => { console.log(`Error rendering QR Code: ${e}`) }); + + onQRCodeRendered(); } diff --git a/receivers/common/web/player/Preload.ts b/receivers/common/web/player/Preload.ts index 5aba8c6..73974d4 100644 --- a/receivers/common/web/player/Preload.ts +++ b/receivers/common/web/player/Preload.ts @@ -123,7 +123,7 @@ if (TARGET === 'electron') { setSpeedService.cancel(); // window.open('../main_window/index.html'); - window.webOS.platformBack(); + history.back(); } }, onFailure: (message: any) => { diff --git a/receivers/common/web/player/Renderer.ts b/receivers/common/web/player/Renderer.ts index 108b1cb..e410b8a 100644 --- a/receivers/common/web/player/Renderer.ts +++ b/receivers/common/web/player/Renderer.ts @@ -2,7 +2,13 @@ import dashjs from 'modules/dashjs'; import Hls, { LevelLoadedData } from 'modules/hls.js'; import { PlaybackUpdateMessage, PlayMessage, SeekMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets'; import { Player, PlayerType } from './Player'; -import { targetPlayerCtrlStateUpdate, targetKeyDownEventListener } from 'src/player/Renderer'; +import { + targetPlayerCtrlStateUpdate, + targetKeyDownEventListener, + captionsBaseHeightCollapsed, + captionsBaseHeightExpanded, + captionsLineHeight +} from 'src/player/Renderer'; function formatDuration(duration: number) { const totalSeconds = Math.floor(duration); @@ -85,6 +91,7 @@ const playerCtrlVolumeBarInteractiveArea = document.getElementById("volumeBarInt const playerCtrlLiveBadge = document.getElementById("liveBadge"); const playerCtrlPosition = document.getElementById("position"); +const playerCtrlDurationSeparator = document.getElementById("durationSeparator"); const playerCtrlDuration = document.getElementById("duration"); const playerCtrlCaptions = document.getElementById("captions"); @@ -103,7 +110,7 @@ let playerPrevTime: number = 0; let lastPlayerUpdateGenerationTime = 0; let isLive = false; let isLivePosition = false; -let captionsBaseHeight = 160; +let captionsBaseHeight = 0; let captionsContentHeight = 0; function onPlay(_event, value: PlayMessage) { @@ -115,6 +122,7 @@ function onPlay(_event, value: PlayMessage) { lastPlayerUpdateGenerationTime = 0; isLive = false; isLivePosition = false; + captionsBaseHeight = captionsBaseHeightExpanded; if (player) { if (player.getSource() === value.url) { @@ -193,7 +201,7 @@ function onPlay(_event, value: PlayMessage) { subtitle.textContent = e.text; videoCaptions.appendChild(subtitle); - captionsContentHeight = subtitle.getBoundingClientRect().height - 34; + captionsContentHeight = subtitle.getBoundingClientRect().height - captionsLineHeight; const captionsHeight = captionsBaseHeight + captionsContentHeight; if (player.isCaptionsEnabled()) { @@ -293,7 +301,17 @@ function onPlay(_event, value: PlayMessage) { console.error("Player error", {source, lineno, colno, error}); }; - videoElement.onloadedmetadata = () => { onPlayerLoad(value, currentPlaybackRate, currentVolume); }; + videoElement.onloadedmetadata = (ev) => { + if (videoElement.duration === Infinity) { + isLive = true; + isLivePosition = true; + } + else { + isLive = false; + isLivePosition = false; + } + + onPlayerLoad(value, currentPlaybackRate, currentVolume); }; } } @@ -327,6 +345,11 @@ enum PlayerControlEvent { // UI update handlers function playerCtrlStateUpdate(event: PlayerControlEvent) { + const handledCase = targetPlayerCtrlStateUpdate(event); + if (handledCase) { + return; + } + switch (event) { case PlayerControlEvent.Load: { playerCtrlProgressBarBuffer.setAttribute("style", "width: 0px"); @@ -340,14 +363,16 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { if (isLive) { playerCtrlLiveBadge.setAttribute("style", "display: block"); playerCtrlPosition.setAttribute("style", "display: none"); + playerCtrlDurationSeparator.setAttribute("style", "display: none"); playerCtrlDuration.setAttribute("style", "display: none"); } else { playerCtrlLiveBadge.setAttribute("style", "display: none"); playerCtrlPosition.setAttribute("style", "display: block"); + playerCtrlDurationSeparator.setAttribute("style", "display: block"); playerCtrlDuration.setAttribute("style", "display: block"); playerCtrlPosition.textContent = formatDuration(player.getCurrentTime()); - playerCtrlDuration.innerHTML = `/  ${formatDuration(player.getDuration())}`; + playerCtrlDuration.innerHTML = formatDuration(player.getDuration()); } if (player.isCaptionsSupported()) { @@ -364,12 +389,12 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { } case PlayerControlEvent.Pause: - playerCtrlAction.setAttribute("class", "play"); + playerCtrlAction.setAttribute("class", "play iconSize"); stopUiHideTimer(); break; case PlayerControlEvent.Play: - playerCtrlAction.setAttribute("class", "pause"); + playerCtrlAction.setAttribute("class", "pause iconSize"); startUiHideTimer(); break; @@ -378,16 +403,16 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { const volume = Math.round(player.getVolume() * playerCtrlVolumeBar.offsetWidth); if (player.isMuted()) { - playerCtrlVolume.setAttribute("class", "mute"); + playerCtrlVolume.setAttribute("class", "mute iconSize"); playerCtrlVolumeBarProgress.setAttribute("style", `width: 0px`); playerCtrlVolumeBarHandle.setAttribute("style", `left: 0px`); } else if (player.getVolume() >= 0.5) { - playerCtrlVolume.setAttribute("class", "volume_high"); + playerCtrlVolume.setAttribute("class", "volume_high iconSize"); playerCtrlVolumeBarProgress.setAttribute("style", `width: ${volume}px`); playerCtrlVolumeBarHandle.setAttribute("style", `left: ${volume}px`); } else { - playerCtrlVolume.setAttribute("class", "volume_low"); + playerCtrlVolume.setAttribute("class", "volume_low iconSize"); playerCtrlVolumeBarProgress.setAttribute("style", `width: ${volume}px`); playerCtrlVolumeBarHandle.setAttribute("style", `left: ${volume}px`); } @@ -430,7 +455,7 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { case PlayerControlEvent.UiFadeOut: { document.body.style.cursor = "none"; playerControls.setAttribute("style", "opacity: 0"); - captionsBaseHeight = 75; + captionsBaseHeight = captionsBaseHeightCollapsed; const captionsHeight = captionsBaseHeight + captionsContentHeight; if (player.isCaptionsEnabled()) { @@ -446,7 +471,7 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { case PlayerControlEvent.UiFadeIn: { document.body.style.cursor = "default"; playerControls.setAttribute("style", "opacity: 1"); - captionsBaseHeight = 160; + captionsBaseHeight = captionsBaseHeightExpanded; const captionsHeight = captionsBaseHeight + captionsContentHeight; if (player.isCaptionsEnabled()) { @@ -460,10 +485,10 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { case PlayerControlEvent.SetCaptions: if (player.isCaptionsEnabled()) { - playerCtrlCaptions.setAttribute("class", "captions_on"); + playerCtrlCaptions.setAttribute("class", "captions_on iconSize"); videoCaptions.setAttribute("style", "display: block"); } else { - playerCtrlCaptions.setAttribute("class", "captions_off"); + playerCtrlCaptions.setAttribute("class", "captions_off iconSize"); videoCaptions.setAttribute("style", "display: none"); } @@ -498,14 +523,13 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) { } default: - targetPlayerCtrlStateUpdate(event); break; } } function scrubbingMouseUIHandler(e: MouseEvent) { - const progressBarOffset = e.offsetX - 8; - const progressBarWidth = PlayerCtrlProgressBarInteractiveArea.offsetWidth - 16; + const progressBarOffset = e.offsetX - playerCtrlProgressBar.offsetLeft; + const progressBarWidth = PlayerCtrlProgressBarInteractiveArea.offsetWidth - (playerCtrlProgressBar.offsetLeft * 2); let time = isLive ? Math.round((1 - (progressBarOffset / progressBarWidth)) * player.getDuration()) : Math.round((progressBarOffset / progressBarWidth) * player.getDuration()); time = Math.min(player.getDuration(), Math.max(0.0, time)); @@ -546,8 +570,8 @@ PlayerCtrlProgressBarInteractiveArea.onmouseleave = () => { playerCtrlProgressBa PlayerCtrlProgressBarInteractiveArea.onmousemove = (e: MouseEvent) => { scrubbingMouseHandler(e) }; function scrubbingMouseHandler(e: MouseEvent) { - const progressBarOffset = e.offsetX - 8; - const progressBarWidth = PlayerCtrlProgressBarInteractiveArea.offsetWidth - 16; + const progressBarOffset = e.offsetX - playerCtrlProgressBar.offsetLeft; + const progressBarWidth = PlayerCtrlProgressBarInteractiveArea.offsetWidth - (playerCtrlProgressBar.offsetLeft * 2); let time = Math.round((progressBarOffset / progressBarWidth) * player.getDuration()); time = Math.min(player.getDuration(), Math.max(0.0, time)); @@ -578,8 +602,8 @@ playerCtrlVolumeBarInteractiveArea.onwheel = (e: WheelEvent) => { function volumeChangeMouseHandler(e: MouseEvent) { if (volumeChanging && e.buttons === 1) { - const volumeBarOffsetX = e.offsetX - 8; - const volumeBarWidth = playerCtrlVolumeBarInteractiveArea.offsetWidth - 16; + const volumeBarOffsetX = e.offsetX - playerCtrlVolumeBar.offsetLeft; + const volumeBarWidth = playerCtrlVolumeBarInteractiveArea.offsetWidth - (playerCtrlVolumeBar.offsetLeft * 2); const volume = volumeBarOffsetX / volumeBarWidth; volumeChangeHandler(volume); } @@ -761,8 +785,25 @@ function keyDownEventListener(event: any) { document.addEventListener('keydown', keyDownEventListener); export { - videoElement, PlayerControlEvent, + videoElement, + videoCaptions, + playerCtrlProgressBar, + playerCtrlProgressBarBuffer, + playerCtrlProgressBarProgress, + playerCtrlProgressBarHandle, + playerCtrlVolumeBar, + playerCtrlVolumeBarProgress, + playerCtrlVolumeBarHandle, + playerCtrlLiveBadge, + playerCtrlPosition, + playerCtrlDuration, + playerCtrlCaptions, + player, + isLive, + captionsBaseHeight, + captionsLineHeight, onPlay, playerCtrlStateUpdate, + formatDuration, }; diff --git a/receivers/common/web/player/common.css b/receivers/common/web/player/common.css index f5b97ec..087b8f5 100644 --- a/receivers/common/web/player/common.css +++ b/receivers/common/web/player/common.css @@ -44,6 +44,11 @@ body { transition: opacity 0.1s ease-in-out; } +.iconSize { + width: 24px; + height: 24px; +} + .volumeContainer { position: relative; height: 24px; @@ -252,8 +257,6 @@ body { } .play { - width: 24px; - height: 24px; cursor: pointer; flex-shrink: 0; @@ -266,8 +269,6 @@ body { } .pause { - width: 24px; - height: 24px; cursor: pointer; flex-shrink: 0; @@ -280,8 +281,6 @@ body { } .volume_high { - width: 24px; - height: 24px; cursor: pointer; flex-shrink: 0; @@ -294,8 +293,6 @@ body { } .volume_low { - width: 24px; - height: 24px; cursor: pointer; flex-shrink: 0; @@ -308,8 +305,6 @@ body { } .mute { - width: 24px; - height: 24px; cursor: pointer; flex-shrink: 0; @@ -322,8 +317,6 @@ body { } .speed { - width: 24px; - height: 24px; cursor: pointer; background-image: url("../assets/icons/player/icon24_speed.svg"); @@ -335,8 +328,6 @@ body { } .captions_off { - width: 24px; - height: 24px; cursor: pointer; background-image: url("../assets/icons/player/icon24_cc_off.svg"); @@ -348,8 +339,6 @@ body { } .captions_on { - width: 24px; - height: 24px; cursor: pointer; background-image: url("../assets/icons/player/icon24_cc_on.svg"); diff --git a/receivers/electron/src/main/Renderer.ts b/receivers/electron/src/main/Renderer.ts index 802ad6a..b5c83c2 100644 --- a/receivers/electron/src/main/Renderer.ts +++ b/receivers/electron/src/main/Renderer.ts @@ -1,5 +1,7 @@ import 'common/main/Renderer'; +export function onQRCodeRendered() {} + const updateView = document.getElementById("update-view"); const updateViewTitle = document.getElementById("update-view-title"); const updateText = document.getElementById("update-text"); diff --git a/receivers/electron/src/player/Renderer.ts b/receivers/electron/src/player/Renderer.ts index 0ce2f4a..a7ed7ab 100644 --- a/receivers/electron/src/player/Renderer.ts +++ b/receivers/electron/src/player/Renderer.ts @@ -1,10 +1,16 @@ import { videoElement, PlayerControlEvent, playerCtrlStateUpdate } from 'common/player/Renderer'; +const captionsBaseHeightCollapsed = 75; +const captionsBaseHeightExpanded = 160; +const captionsLineHeight = 34; + const playerCtrlFullscreen = document.getElementById("fullscreen"); playerCtrlFullscreen.onclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); }; videoElement.ondblclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); }; -export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent) { +export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean { + let handledCase = false; + switch (event) { case PlayerControlEvent.ToggleFullscreen: { window.electronAPI.toggleFullScreen(); @@ -17,17 +23,22 @@ export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent) { } }); + handledCase = true; break; } case PlayerControlEvent.ExitFullscreen: window.electronAPI.exitFullScreen(); playerCtrlFullscreen.setAttribute("class", "fullscreen_off"); + + handledCase = true; break; default: break; } + + return handledCase; } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -46,3 +57,9 @@ export function targetKeyDownEventListener(event: any) { break; } }; + +export { + captionsBaseHeightCollapsed, + captionsBaseHeightExpanded, + captionsLineHeight, +} diff --git a/receivers/electron/src/player/index.html b/receivers/electron/src/player/index.html index e753298..05b60f4 100644 --- a/receivers/electron/src/player/index.html +++ b/receivers/electron/src/player/index.html @@ -23,9 +23,9 @@