mirror of
https://gitlab.com/futo-org/fcast.git
synced 2025-06-24 21:25:23 +00:00
Receivers: Add playlist next/previous buttons and metadata for audio files
This commit is contained in:
parent
782a01f4e9
commit
56e10760b8
8 changed files with 151 additions and 32 deletions
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.2458 11.0964L5.62154 4.44966C5.13411 4.14317 4.54083 4.22564 4.11248 4.54936C3.93865 4.67665 3.7964 4.8422 3.69673 5.03322C3.59706 5.22423 3.54264 5.43561 3.53766 5.651V18.8276C3.53766 19.9157 4.74269 20.6198 5.62154 20.0634L15.247 13.4573C16.0471 12.9169 16.0471 11.6356 15.247 11.0952L15.2458 11.0964ZM20.4623 5.7864C20.4623 5.45995 20.3326 5.14687 20.1018 4.91603C19.8709 4.6852 19.5579 4.55552 19.2314 4.55552C18.905 4.55552 18.5919 4.6852 18.361 4.91603C18.1302 5.14687 18.0005 5.45995 18.0005 5.7864V18.7304C18.0005 19.0568 18.1302 19.3699 18.361 19.6007C18.5919 19.8316 18.905 19.9612 19.2314 19.9612C19.5579 19.9612 19.8709 19.8316 20.1018 19.6007C20.3326 19.3699 20.4623 19.0568 20.4623 18.7304V5.7864Z" fill="#c9c9c9"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 886 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.2458 11.0964L5.62154 4.44966C5.13411 4.14317 4.54083 4.22564 4.11248 4.54936C3.93865 4.67665 3.7964 4.8422 3.69673 5.03322C3.59706 5.22423 3.54264 5.43561 3.53766 5.651V18.8276C3.53766 19.9157 4.74269 20.6198 5.62154 20.0634L15.247 13.4573C16.0471 12.9169 16.0471 11.6356 15.247 11.0952L15.2458 11.0964ZM20.4623 5.7864C20.4623 5.45995 20.3326 5.14687 20.1018 4.91603C19.8709 4.6852 19.5579 4.55552 19.2314 4.55552C18.905 4.55552 18.5919 4.6852 18.361 4.91603C18.1302 5.14687 18.0005 5.45995 18.0005 5.7864V18.7304C18.0005 19.0568 18.1302 19.3699 18.361 19.6007C18.5919 19.8316 18.905 19.9612 19.2314 19.9612C19.5579 19.9612 19.8709 19.8316 20.1018 19.6007C20.3326 19.3699 20.4623 19.0568 20.4623 18.7304V5.7864Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 884 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.93149 13.3567L18.03 19.6404C18.4908 19.9301 19.0516 19.8522 19.4566 19.5461C19.6209 19.4258 19.7554 19.2693 19.8496 19.0887C19.9438 18.9081 19.9953 18.7083 20 18.5047L20 6.04795C20 5.01929 18.8608 4.35369 18.03 4.87966L8.93033 11.1249C8.17397 11.6357 8.17397 12.8471 8.93033 13.3579L8.93149 13.3567ZM4 18.3767C4 18.6853 4.1226 18.9813 4.34082 19.1995C4.55905 19.4177 4.85502 19.5403 5.16364 19.5403C5.47225 19.5403 5.76823 19.4177 5.98645 19.1995C6.20468 18.9813 6.32727 18.6853 6.32727 18.3767L6.32727 6.13987C6.32727 5.83126 6.20468 5.53528 5.98645 5.31706C5.76823 5.09883 5.47225 4.97624 5.16364 4.97624C4.85502 4.97624 4.55905 5.09883 4.34082 5.31706C4.1226 5.53528 4 5.83126 4 6.13987L4 18.3767Z" fill="#c9c9c9"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 874 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.93149 13.3567L18.03 19.6404C18.4908 19.9301 19.0516 19.8522 19.4566 19.5461C19.6209 19.4258 19.7554 19.2693 19.8496 19.0887C19.9438 18.9081 19.9953 18.7083 20 18.5047L20 6.04795C20 5.01929 18.8608 4.35369 18.03 4.87966L8.93033 11.1249C8.17397 11.6357 8.17397 12.8471 8.93033 13.3579L8.93149 13.3567ZM4 18.3767C4 18.6853 4.1226 18.9813 4.34082 19.1995C4.55905 19.4177 4.85502 19.5403 5.16364 19.5403C5.47225 19.5403 5.76823 19.4177 5.98645 19.1995C6.20468 18.9813 6.32727 18.6853 6.32727 18.3767L6.32727 6.13987C6.32727 5.83126 6.20468 5.53528 5.98645 5.31706C5.76823 5.09883 5.47225 4.97624 5.16364 4.97624C4.85502 4.97624 4.55905 5.09883 4.34082 5.31706C4.1226 5.53528 4 5.83126 4 6.13987L4 18.3767Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 872 B |
|
@ -1,6 +1,6 @@
|
||||||
import dashjs from 'modules/dashjs';
|
import dashjs from 'modules/dashjs';
|
||||||
import Hls, { LevelLoadedData } from 'modules/hls.js';
|
import Hls, { LevelLoadedData } from 'modules/hls.js';
|
||||||
import { EventMessage, EventType, KeyEvent, MediaItem, MediaItemEvent, PlaybackState, PlaybackUpdateMessage, PlaylistContent, PlayMessage, SeekMessage, SetPlaylistItemMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets';
|
import { EventMessage, EventType, GenericMediaMetadata, KeyEvent, MediaItem, MediaItemEvent, MetadataType, PlaybackState, PlaybackUpdateMessage, PlaylistContent, PlayMessage, SeekMessage, SetPlaylistItemMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets';
|
||||||
import { Player, PlayerType } from './Player';
|
import { Player, PlayerType } from './Player';
|
||||||
import * as connectionMonitor from 'common/ConnectionMonitor';
|
import * as connectionMonitor from 'common/ConnectionMonitor';
|
||||||
import { supportedAudioTypes } from 'common/MimeTypes';
|
import { supportedAudioTypes } from 'common/MimeTypes';
|
||||||
|
@ -88,12 +88,16 @@ function onPlayerLoad(value: PlayMessage) {
|
||||||
const idleIcon = document.getElementById('title-icon');
|
const idleIcon = document.getElementById('title-icon');
|
||||||
const loadingSpinner = document.getElementById('loading-spinner');
|
const loadingSpinner = document.getElementById('loading-spinner');
|
||||||
const idleBackground = document.getElementById('idle-background');
|
const idleBackground = document.getElementById('idle-background');
|
||||||
|
const thumbnailImage = document.getElementById('thumbnailImage') as HTMLImageElement;
|
||||||
const videoElement = document.getElementById("videoPlayer") as HTMLVideoElement;
|
const videoElement = document.getElementById("videoPlayer") as HTMLVideoElement;
|
||||||
const videoCaptions = document.getElementById("videoCaptions") as HTMLDivElement;
|
const videoCaptions = document.getElementById("videoCaptions") as HTMLDivElement;
|
||||||
|
const mediaTitle = document.getElementById("mediaTitle");
|
||||||
|
|
||||||
const playerControls = document.getElementById("controls");
|
const playerControls = document.getElementById("controls");
|
||||||
|
|
||||||
|
const playerCtrlPlayPrevious = document.getElementById("playPrevious");
|
||||||
const playerCtrlAction = document.getElementById("action");
|
const playerCtrlAction = document.getElementById("action");
|
||||||
|
const playerCtrlPlayNext = document.getElementById("playNext");
|
||||||
const playerCtrlVolume = document.getElementById("volume");
|
const playerCtrlVolume = document.getElementById("volume");
|
||||||
|
|
||||||
const playerCtrlProgressBar = document.getElementById("progressBar");
|
const playerCtrlProgressBar = document.getElementById("progressBar");
|
||||||
|
@ -141,6 +145,7 @@ let showDurationTimeout: number = null;
|
||||||
let playlistIndex = 0;
|
let playlistIndex = 0;
|
||||||
let isMediaItem = false;
|
let isMediaItem = false;
|
||||||
let playItemCached = false;
|
let playItemCached = false;
|
||||||
|
let mediaTitleTimeoutHandle = null;
|
||||||
|
|
||||||
function onPlay(_event, value: PlayMessage) {
|
function onPlay(_event, value: PlayMessage) {
|
||||||
if (!playItemCached) {
|
if (!playItemCached) {
|
||||||
|
@ -372,10 +377,10 @@ function onPlayPlaylist(_event, value: PlaylistContent) {
|
||||||
window.targetAPI.sendPlayRequest(playMessage, playlistIndex);
|
window.targetAPI.sendPlayRequest(playMessage, playlistIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.targetAPI.onSetPlaylistItem((_event, value: SetPlaylistItemMessage) => {
|
function setPlaylistItem(index: number) {
|
||||||
if (value.itemIndex >= 0 && value.itemIndex < cachedPlaylist.items.length) {
|
if (index >= 0 && index < cachedPlaylist.items.length) {
|
||||||
logger.info(`Setting playlist item to index ${value.itemIndex}`);
|
logger.info(`Setting playlist item to index ${index}`);
|
||||||
playlistIndex = value.itemIndex;
|
playlistIndex = index;
|
||||||
cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
||||||
playItemCached = true;
|
playItemCached = true;
|
||||||
window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
||||||
|
@ -386,9 +391,9 @@ window.targetAPI.onSetPlaylistItem((_event, value: SetPlaylistItemMessage) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
logger.warn(`Playlist index out of bounds ${value.itemIndex}, ignoring...`);
|
logger.warn(`Playlist index out of bounds ${index}, ignoring...`);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
connectionMonitor.setUiUpdateCallbacks({
|
connectionMonitor.setUiUpdateCallbacks({
|
||||||
onConnect: (connections: string[], initialUpdate: boolean = false) => {
|
onConnect: (connections: string[], initialUpdate: boolean = false) => {
|
||||||
|
@ -403,6 +408,7 @@ connectionMonitor.setUiUpdateCallbacks({
|
||||||
|
|
||||||
window.targetAPI.onPlay(onPlay);
|
window.targetAPI.onPlay(onPlay);
|
||||||
window.targetAPI.onPlayPlaylist(onPlayPlaylist);
|
window.targetAPI.onPlayPlaylist(onPlayPlaylist);
|
||||||
|
window.targetAPI.onSetPlaylistItem((_event, value: SetPlaylistItemMessage) => { setPlaylistItem(value.itemIndex); });
|
||||||
|
|
||||||
let scrubbing = false;
|
let scrubbing = false;
|
||||||
let volumeChanging = false;
|
let volumeChanging = false;
|
||||||
|
@ -431,6 +437,15 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case PlayerControlEvent.Load: {
|
case PlayerControlEvent.Load: {
|
||||||
|
if (isMediaItem) {
|
||||||
|
playerCtrlPlayPrevious.style.display = 'block';
|
||||||
|
playerCtrlPlayNext.style.display = 'block';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
playerCtrlPlayPrevious.style.display = 'none';
|
||||||
|
playerCtrlPlayNext.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
playerCtrlProgressBarBuffer.setAttribute("style", "width: 0px");
|
playerCtrlProgressBarBuffer.setAttribute("style", "width: 0px");
|
||||||
playerCtrlProgressBarProgress.setAttribute("style", "width: 0px");
|
playerCtrlProgressBarProgress.setAttribute("style", "width: 0px");
|
||||||
playerCtrlProgressBarHandle.setAttribute("style", `left: ${playerCtrlProgressBar.offsetLeft}px`);
|
playerCtrlProgressBarHandle.setAttribute("style", `left: ${playerCtrlProgressBar.offsetLeft}px`);
|
||||||
|
@ -440,30 +455,54 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
||||||
playerCtrlVolumeBarHandle.setAttribute("style", `left: ${volume + 8}px`);
|
playerCtrlVolumeBarHandle.setAttribute("style", `left: ${volume + 8}px`);
|
||||||
|
|
||||||
if (isLive) {
|
if (isLive) {
|
||||||
playerCtrlLiveBadge.setAttribute("style", "display: block");
|
playerCtrlLiveBadge.style.display = 'block';
|
||||||
playerCtrlPosition.setAttribute("style", "display: none");
|
playerCtrlPosition.style.display = 'none';
|
||||||
playerCtrlDurationSeparator.setAttribute("style", "display: none");
|
playerCtrlDurationSeparator.style.display = 'none';
|
||||||
playerCtrlDuration.setAttribute("style", "display: none");
|
playerCtrlDuration.style.display = 'none';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
playerCtrlLiveBadge.setAttribute("style", "display: none");
|
playerCtrlLiveBadge.style.display = 'none';
|
||||||
playerCtrlPosition.setAttribute("style", "display: block");
|
playerCtrlPosition.style.display = 'block';
|
||||||
playerCtrlDurationSeparator.setAttribute("style", "display: block");
|
playerCtrlDurationSeparator.style.display = 'block';
|
||||||
playerCtrlDuration.setAttribute("style", "display: block");
|
playerCtrlDuration.style.display = 'block';
|
||||||
|
|
||||||
playerCtrlPosition.textContent = formatDuration(player.getCurrentTime());
|
playerCtrlPosition.textContent = formatDuration(player.getCurrentTime());
|
||||||
playerCtrlDuration.innerHTML = formatDuration(player.getDuration());
|
playerCtrlDuration.innerHTML = formatDuration(player.getDuration());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.isCaptionsSupported()) {
|
if (player.isCaptionsSupported()) {
|
||||||
playerCtrlCaptions.setAttribute("style", "display: block");
|
playerCtrlCaptions.style.display = 'block';
|
||||||
videoCaptions.setAttribute("style", "display: block");
|
videoCaptions.style.display = 'block';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
playerCtrlCaptions.setAttribute("style", "display: none");
|
playerCtrlCaptions.style.display = 'none';
|
||||||
videoCaptions.setAttribute("style", "display: none");
|
videoCaptions.style.display = 'none';
|
||||||
player.enableCaptions(false);
|
player.enableCaptions(false);
|
||||||
}
|
}
|
||||||
playerCtrlStateUpdate(PlayerControlEvent.SetCaptions);
|
playerCtrlStateUpdate(PlayerControlEvent.SetCaptions);
|
||||||
|
|
||||||
|
if (supportedAudioTypes.find(v => v === cachedPlayMediaItem.container.toLocaleLowerCase())) {
|
||||||
|
if (cachedPlayMediaItem.metadata && cachedPlayMediaItem.metadata?.type === MetadataType.Generic) {
|
||||||
|
const metadata = cachedPlayMediaItem.metadata as GenericMediaMetadata;
|
||||||
|
|
||||||
|
if (metadata.title) {
|
||||||
|
mediaTitle.innerHTML = metadata.title;
|
||||||
|
|
||||||
|
captionsContentHeight = mediaTitle.getBoundingClientRect().height - captionsLineHeight;
|
||||||
|
const captionsHeight = captionsBaseHeightExpanded + captionsContentHeight;
|
||||||
|
mediaTitle.setAttribute("style", `display: block; bottom: ${captionsHeight}px;`);
|
||||||
|
|
||||||
|
if (mediaTitleTimeoutHandle) {
|
||||||
|
clearTimeout(mediaTitleTimeoutHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaTitleTimeoutHandle = setTimeout(() => {
|
||||||
|
mediaTitle.style.display = 'none';
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +572,7 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
||||||
|
|
||||||
case PlayerControlEvent.UiFadeOut: {
|
case PlayerControlEvent.UiFadeOut: {
|
||||||
document.body.style.cursor = "none";
|
document.body.style.cursor = "none";
|
||||||
playerControls.setAttribute("style", "opacity: 0");
|
playerControls.style.opacity = '0';
|
||||||
captionsBaseHeight = captionsBaseHeightCollapsed;
|
captionsBaseHeight = captionsBaseHeightCollapsed;
|
||||||
const captionsHeight = captionsBaseHeight + captionsContentHeight;
|
const captionsHeight = captionsBaseHeight + captionsContentHeight;
|
||||||
|
|
||||||
|
@ -543,13 +582,12 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
||||||
videoCaptions.setAttribute("style", `display: none; bottom: ${captionsHeight}px;`);
|
videoCaptions.setAttribute("style", `display: none; bottom: ${captionsHeight}px;`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PlayerControlEvent.UiFadeIn: {
|
case PlayerControlEvent.UiFadeIn: {
|
||||||
document.body.style.cursor = "default";
|
document.body.style.cursor = "default";
|
||||||
playerControls.setAttribute("style", "opacity: 1");
|
playerControls.style.opacity = '1';
|
||||||
captionsBaseHeight = captionsBaseHeightExpanded;
|
captionsBaseHeight = captionsBaseHeightExpanded;
|
||||||
const captionsHeight = captionsBaseHeight + captionsContentHeight;
|
const captionsHeight = captionsBaseHeight + captionsContentHeight;
|
||||||
|
|
||||||
|
@ -565,19 +603,19 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
||||||
case PlayerControlEvent.SetCaptions:
|
case PlayerControlEvent.SetCaptions:
|
||||||
if (player?.isCaptionsEnabled()) {
|
if (player?.isCaptionsEnabled()) {
|
||||||
playerCtrlCaptions.setAttribute("class", "captions_on iconSize");
|
playerCtrlCaptions.setAttribute("class", "captions_on iconSize");
|
||||||
videoCaptions.setAttribute("style", "display: block");
|
videoCaptions.style.display = 'block';
|
||||||
} else {
|
} else {
|
||||||
playerCtrlCaptions.setAttribute("class", "captions_off iconSize");
|
playerCtrlCaptions.setAttribute("class", "captions_off iconSize");
|
||||||
videoCaptions.setAttribute("style", "display: none");
|
videoCaptions.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PlayerControlEvent.ToggleSpeedMenu: {
|
case PlayerControlEvent.ToggleSpeedMenu: {
|
||||||
if (playerCtrlSpeedMenuShown) {
|
if (playerCtrlSpeedMenuShown) {
|
||||||
playerCtrlSpeedMenu.setAttribute("style", "display: none");
|
playerCtrlSpeedMenu.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
playerCtrlSpeedMenu.setAttribute("style", "display: block");
|
playerCtrlSpeedMenu.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
playerCtrlSpeedMenuShown = !playerCtrlSpeedMenuShown;
|
playerCtrlSpeedMenuShown = !playerCtrlSpeedMenuShown;
|
||||||
|
@ -590,12 +628,12 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
||||||
|
|
||||||
playbackRates.forEach(r => {
|
playbackRates.forEach(r => {
|
||||||
const entry = document.getElementById(`speedMenuEntry_${r}_enabled`);
|
const entry = document.getElementById(`speedMenuEntry_${r}_enabled`);
|
||||||
entry.setAttribute("style", "opacity: 0");
|
entry.style.opacity = '0';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ignore updating GUI for custom rates
|
// Ignore updating GUI for custom rates
|
||||||
if (entryElement !== null) {
|
if (entryElement !== null) {
|
||||||
entryElement.setAttribute("style", "opacity: 1");
|
entryElement.style.opacity = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -634,6 +672,8 @@ playerCtrlAction.onclick = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
playerCtrlPlayPrevious.onclick = () => { setPlaylistItem(playlistIndex - 1); }
|
||||||
|
playerCtrlPlayNext.onclick = () => { setPlaylistItem(playlistIndex + 1); }
|
||||||
playerCtrlVolume.onclick = () => { player?.setMute(!player?.isMuted()); };
|
playerCtrlVolume.onclick = () => { player?.setMute(!player?.isMuted()); };
|
||||||
|
|
||||||
PlayerCtrlProgressBarInteractiveArea.onmousedown = (e: MouseEvent) => { scrubbing = true; scrubbingMouseHandler(e) };
|
PlayerCtrlProgressBarInteractiveArea.onmousedown = (e: MouseEvent) => { scrubbing = true; scrubbingMouseHandler(e) };
|
||||||
|
@ -738,11 +778,13 @@ function videoClickedHandler() {
|
||||||
|
|
||||||
videoElement.onclick = () => { videoClickedHandler(); };
|
videoElement.onclick = () => { videoClickedHandler(); };
|
||||||
idleBackground.onclick = () => { videoClickedHandler(); };
|
idleBackground.onclick = () => { videoClickedHandler(); };
|
||||||
|
thumbnailImage.onclick = () => { videoClickedHandler(); };
|
||||||
idleIcon.onclick = () => { videoClickedHandler(); };
|
idleIcon.onclick = () => { videoClickedHandler(); };
|
||||||
|
|
||||||
function setIdleScreenVisible(visible: boolean, loading: boolean = false, message?: PlayMessage) {
|
function setIdleScreenVisible(visible: boolean, loading: boolean = false, message?: PlayMessage) {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
idleBackground.style.display = 'block';
|
idleBackground.style.display = 'block';
|
||||||
|
thumbnailImage.style.display = 'none';
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
idleIcon.style.display = 'none';
|
idleIcon.style.display = 'none';
|
||||||
|
@ -757,11 +799,26 @@ function setIdleScreenVisible(visible: boolean, loading: boolean = false, messag
|
||||||
if (!supportedAudioTypes.find(v => v === message.container.toLocaleLowerCase())) {
|
if (!supportedAudioTypes.find(v => v === message.container.toLocaleLowerCase())) {
|
||||||
idleIcon.style.display = 'none';
|
idleIcon.style.display = 'none';
|
||||||
idleBackground.style.display = 'none';
|
idleBackground.style.display = 'none';
|
||||||
|
thumbnailImage.style.display = 'none';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
idleIcon.style.display = 'block';
|
let displayThumbnail = false;
|
||||||
idleBackground.style.display = 'block';
|
if (message?.metadata?.type === MetadataType.Generic) {
|
||||||
|
const metadata = message.metadata as GenericMediaMetadata;
|
||||||
|
displayThumbnail = metadata.thumbnailUrl ? true : false;
|
||||||
|
thumbnailImage.src = metadata.thumbnailUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayThumbnail) {
|
||||||
|
idleIcon.style.display = 'none';
|
||||||
|
idleBackground.style.display = 'none';
|
||||||
|
thumbnailImage.style.display = 'block';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
idleIcon.style.display = 'block';
|
||||||
|
idleBackground.style.display = 'block';
|
||||||
|
thumbnailImage.style.display = 'none';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingSpinner.style.display = 'none';
|
loadingSpinner.style.display = 'none';
|
||||||
|
|
|
@ -66,6 +66,17 @@ body {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#thumbnailImage {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
object-fit: contain;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#videoPlayer {
|
#videoPlayer {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -331,6 +342,30 @@ body {
|
||||||
background-image: url("../assets/icons/player/icon24_pause_active.svg");
|
background-image: url("../assets/icons/player/icon24_pause_active.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.playPrevious {
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
background-image: url("../assets/icons/player/icon24_play_previous.svg");
|
||||||
|
transition: background-image 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playPrevious:hover {
|
||||||
|
background-image: url("../assets/icons/player/icon24_play_previous_active.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.playNext {
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
background-image: url("../assets/icons/player/icon24_play_next.svg");
|
||||||
|
transition: background-image 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playNext:hover {
|
||||||
|
background-image: url("../assets/icons/player/icon24_play_next_active.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.volume_high {
|
.volume_high {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { BrowserWindow, ipcMain, IpcMainEvent, nativeImage, Tray, Menu, dialog, shell } from 'electron';
|
import { BrowserWindow, ipcMain, IpcMainEvent, nativeImage, Tray, Menu, dialog, shell } from 'electron';
|
||||||
import { ToastIcon } from 'common/components/Toast';
|
import { ToastIcon } from 'common/components/Toast';
|
||||||
import { Opcode, PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage, PlayMessage, PlayUpdateMessage, EventMessage, EventType, PlaylistContent, SeekMessage, SetVolumeMessage, SetSpeedMessage, SetPlaylistItemMessage } from 'common/Packets';
|
import { Opcode, PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage, PlayMessage, PlayUpdateMessage, EventMessage, EventType, PlaylistContent, SeekMessage, SetVolumeMessage, SetSpeedMessage, SetPlaylistItemMessage, MetadataType, GenericMediaMetadata } from 'common/Packets';
|
||||||
import { DiscoveryService } from 'common/DiscoveryService';
|
import { DiscoveryService } from 'common/DiscoveryService';
|
||||||
import { TcpListenerService } from 'common/TcpListenerService';
|
import { TcpListenerService } from 'common/TcpListenerService';
|
||||||
import { WebSocketListenerService } from 'common/WebSocketListenerService';
|
import { WebSocketListenerService } from 'common/WebSocketListenerService';
|
||||||
|
@ -19,6 +19,8 @@ import { hideBin } from 'yargs/helpers';
|
||||||
const cp = require('child_process');
|
const cp = require('child_process');
|
||||||
let logger = null;
|
let logger = null;
|
||||||
|
|
||||||
|
const APPLICATION_TITLE = 'FCast Receiver';
|
||||||
|
|
||||||
class AppCache {
|
class AppCache {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
public interfaces: any = null;
|
public interfaces: any = null;
|
||||||
|
@ -125,7 +127,7 @@ export class Main {
|
||||||
|
|
||||||
await dialog.showMessageBox({
|
await dialog.showMessageBox({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: 'Fcast Receiver',
|
title: APPLICATION_TITLE,
|
||||||
message: aboutMessage,
|
message: aboutMessage,
|
||||||
buttons: ['OK'],
|
buttons: ['OK'],
|
||||||
defaultId: 0
|
defaultId: 0
|
||||||
|
@ -168,11 +170,18 @@ export class Main {
|
||||||
Main.mediaCache = new MediaCache(playMessage);
|
Main.mediaCache = new MediaCache(playMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let windowTitle = APPLICATION_TITLE;
|
||||||
|
if (message.metadata?.type === MetadataType.Generic) {
|
||||||
|
const metadata = message.metadata as GenericMediaMetadata;
|
||||||
|
windowTitle = metadata.title ? `${metadata.title} - ${APPLICATION_TITLE}` : APPLICATION_TITLE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Main.playerWindow) {
|
if (!Main.playerWindow) {
|
||||||
Main.playerWindow = new BrowserWindow({
|
Main.playerWindow = new BrowserWindow({
|
||||||
fullscreen: true,
|
fullscreen: true,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
icon: path.join(__dirname, 'icon512.png'),
|
icon: path.join(__dirname, 'icon512.png'),
|
||||||
|
title: windowTitle,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, 'player/preload.js')
|
preload: path.join(__dirname, 'player/preload.js')
|
||||||
}
|
}
|
||||||
|
@ -191,11 +200,13 @@ export class Main {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (Main.playerWindow && messageInfo.contentViewer !== Main.playerWindowContentViewer) {
|
else if (Main.playerWindow && messageInfo.contentViewer !== Main.playerWindowContentViewer) {
|
||||||
|
Main.playerWindow.setTitle(windowTitle);
|
||||||
Main.playerWindow.loadFile(path.join(__dirname, `${messageInfo.contentViewer}/index.html`));
|
Main.playerWindow.loadFile(path.join(__dirname, `${messageInfo.contentViewer}/index.html`));
|
||||||
Main.playerWindow.on('ready-to-show', async () => {
|
Main.playerWindow.on('ready-to-show', async () => {
|
||||||
Main.playerWindow?.webContents?.send(messageInfo.rendererEvent, messageInfo.rendererMessage);
|
Main.playerWindow?.webContents?.send(messageInfo.rendererEvent, messageInfo.rendererMessage);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
Main.playerWindow.setTitle(windowTitle);
|
||||||
Main.playerWindow?.webContents?.send(messageInfo.rendererEvent, messageInfo.rendererMessage);
|
Main.playerWindow?.webContents?.send(messageInfo.rendererEvent, messageInfo.rendererMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
<div id="title-icon"></div>
|
<div id="title-icon"></div>
|
||||||
<div id="loading-spinner" class="lds-ring"><div></div><div></div><div></div><div></div></div>
|
<div id="loading-spinner" class="lds-ring"><div></div><div></div><div></div><div></div></div>
|
||||||
<div id="idle-background"></div>
|
<div id="idle-background"></div>
|
||||||
|
<img id="thumbnailImage" />
|
||||||
<video id="videoPlayer" autoplay preload="auto"></video>
|
<video id="videoPlayer" autoplay preload="auto"></video>
|
||||||
|
<div id="mediaTitle" class="captionsContainer"></div>
|
||||||
<div id="videoCaptions" class="captionsContainer"></div>
|
<div id="videoCaptions" class="captionsContainer"></div>
|
||||||
|
|
||||||
<div id="controls" class="container">
|
<div id="controls" class="container">
|
||||||
|
@ -27,7 +29,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="leftButtonContainer">
|
<div class="leftButtonContainer">
|
||||||
|
<div id="playPrevious" class="playPrevious iconSize"></div>
|
||||||
<div id="action" class="play iconSize"></div>
|
<div id="action" class="play iconSize"></div>
|
||||||
|
<div id="playNext" class="playNext iconSize"></div>
|
||||||
|
|
||||||
<div id="volume" class="volume_high iconSize"></div>
|
<div id="volume" class="volume_high iconSize"></div>
|
||||||
<div class="volumeContainer">
|
<div class="volumeContainer">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue