2024-09-15 14:16:45 +02:00
|
|
|
window.addEventListener("load", main);
|
|
|
|
|
|
|
|
let displaySelectDialog;
|
|
|
|
let audioSinkSelectDialog;
|
|
|
|
let openNewVideoDialog;
|
|
|
|
let closeVideoDialog;
|
|
|
|
|
|
|
|
let closeVideoDialogID;
|
|
|
|
|
|
|
|
let videoTemplate;
|
|
|
|
let videoContainer;
|
|
|
|
let currentVideos = [];
|
|
|
|
let currentVideoData;
|
|
|
|
|
|
|
|
let seekbar;
|
|
|
|
let volumeBar;
|
|
|
|
let playPauseButton;
|
|
|
|
let playPauseButtonIcon;
|
|
|
|
let replayButton;
|
|
|
|
let forwardButton;
|
|
|
|
let currentTimestamp;
|
|
|
|
let videoLength;
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
displaySelectDialog = document.querySelector("#display-select-dialog");
|
|
|
|
audioSinkSelectDialog = document.querySelector("#audio-sink-select-dialog");
|
|
|
|
openNewVideoDialog = document.querySelector("#open-new-video-dialog");
|
|
|
|
closeVideoDialog = document.querySelector("#close-video-dialog");
|
|
|
|
|
|
|
|
videoTemplate = document.querySelector("#video-template");
|
|
|
|
videoContainer = document.querySelector("#video-container");
|
|
|
|
|
|
|
|
seekbar = document.querySelector("#seekbar");
|
|
|
|
volumeBar = document.querySelector("#volume-bar");
|
|
|
|
playPauseButton = document.querySelector("#play-pause");
|
|
|
|
playPauseButtonIcon = playPauseButton.querySelector(".material-symbols-outlined");
|
|
|
|
replayButton = document.querySelector("#replay");
|
|
|
|
forwardButton = document.querySelector("#forward");
|
|
|
|
currentTimestamp = document.querySelector("#current-timestamp");
|
|
|
|
videoLength = document.querySelector("#video-length");
|
|
|
|
|
|
|
|
playPauseButton.addEventListener("click", onPlayPauseButtonClicked);
|
|
|
|
replayButton.addEventListener("click", onReplayButtonClicked);
|
|
|
|
forwardButton.addEventListener("click", onForwardButtonClicked);
|
|
|
|
seekbar.addEventListener("change", onSeekbarChanged);
|
|
|
|
volumeBar.addEventListener("input", onVolumeBarChanged);
|
|
|
|
|
|
|
|
updateUI();
|
|
|
|
setInterval(updateUI, 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function updateUI() {
|
|
|
|
const videoDatas = await listVideos();
|
|
|
|
const currentDisplay = localStorage.getItem("display");
|
|
|
|
currentVideoData = videoDatas.find(videoData => videoData.display == currentDisplay);
|
|
|
|
|
|
|
|
if (currentVideoData !== undefined) {
|
|
|
|
console.log(currentVideoData);
|
|
|
|
|
|
|
|
seekbar.disabled = false;
|
|
|
|
volumeBar.disabled = false;
|
|
|
|
playPauseButton.disabled = false;
|
|
|
|
replayButton.disabled = false;
|
|
|
|
forwardButton.disabled = false;
|
|
|
|
|
|
|
|
const {progress, duration} = formatTimestamps(currentVideoData.progress, currentVideoData.duration);
|
|
|
|
currentTimestamp.textContent = progress;
|
|
|
|
videoLength.textContent = duration;
|
|
|
|
seekbar.max = currentVideoData.duration;
|
|
|
|
seekbar.setValue(currentVideoData.progress);
|
|
|
|
volumeBar.setValue(currentVideoData.volume);
|
|
|
|
playPauseButtonIcon.textContent = currentVideoData.paused ? "play_circle" : "pause_circle";
|
|
|
|
} else {
|
|
|
|
seekbar.disabled = true;
|
|
|
|
seekbar.setValue(0);
|
|
|
|
volumeBar.disabled = true;
|
|
|
|
playPauseButton.disabled = true;
|
|
|
|
playPauseButtonIcon.textContent = "play_circle";
|
|
|
|
replayButton.disabled = true;
|
|
|
|
forwardButton.disabled = true;
|
|
|
|
currentTimestamp.textContent = "";
|
|
|
|
videoLength.textContent = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
await refreshVideoList(videoDatas);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function refreshVideoList(videoDatas) {
|
|
|
|
const videoIDs = videoDatas.map(videoData => videoData.id);
|
|
|
|
const shownVideoIDs = currentVideos.map(video => video.videoID);
|
|
|
|
const missingVideoIDs = videoIDs.filter(videoID => !shownVideoIDs.includes(videoID));
|
|
|
|
const unneededVideoIDs = shownVideoIDs.filter(shownVideoID => !videoIDs.includes(shownVideoID));
|
|
|
|
|
|
|
|
for (let unneededVideoID of unneededVideoIDs) {
|
|
|
|
const index = currentVideos.findIndex(video => video.videoID == unneededVideoID);
|
|
|
|
const video = currentVideos[index];
|
|
|
|
video.hide();
|
|
|
|
currentVideos.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let index in videoDatas) {
|
|
|
|
const videoData = videoDatas[index];
|
|
|
|
|
|
|
|
if (missingVideoIDs.includes(videoData.id)) {
|
|
|
|
const video = new Video(videoData);
|
|
|
|
video.showAt(index);
|
|
|
|
currentVideos.splice(index, 0, video);
|
|
|
|
} else {
|
|
|
|
const video = currentVideos.find(currentVideo => currentVideo.videoID == videoData.id);
|
|
|
|
video.update(videoData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onShowSelectDisplayDialogClicked() {
|
|
|
|
const displays = await listDisplays();
|
|
|
|
const currentDisplay = localStorage.getItem("display");
|
|
|
|
|
|
|
|
const displaySelectForm = document.querySelector("#display-select-dialog-form");
|
|
|
|
displaySelectForm.clearChildren();
|
|
|
|
|
|
|
|
for (let display of displays) {
|
|
|
|
const input = document.createElement("input");
|
|
|
|
input.setAttribute("type", "radio");
|
|
|
|
input.setAttribute("name", "display");
|
|
|
|
input.setAttribute("id", `display_${display}`);
|
|
|
|
input.setAttribute("value", display);
|
|
|
|
input.addEventListener("change", onCloseSelectDisplayDialogClicked);
|
|
|
|
if (display == currentDisplay) input.setAttribute("checked", "checked");
|
|
|
|
displaySelectForm.appendChild(input);
|
|
|
|
|
|
|
|
const label = document.createElement("label");
|
|
|
|
label.setAttribute("for", `display_${display}`);
|
|
|
|
label.textContent = display;
|
|
|
|
displaySelectForm.appendChild(label);
|
|
|
|
}
|
|
|
|
|
|
|
|
displaySelectDialog.showModal();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCloseSelectDisplayDialogClicked() {
|
|
|
|
const selectedDisplay = document.forms["display-select-dialog-form"].elements["display"].value;
|
|
|
|
localStorage.setItem("display", selectedDisplay);
|
|
|
|
setTimeout(() => displaySelectDialog.close(), 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onShowSelectAudioSinkDialogClicked() {
|
|
|
|
const audioSinks = await listAudioSinks();
|
|
|
|
const currentAudioSink = localStorage.getItem("audio-sink");
|
|
|
|
|
|
|
|
const audioSinkSelectForm = document.querySelector("#audio-sink-select-dialog-form");
|
|
|
|
audioSinkSelectForm.clearChildren();
|
|
|
|
|
|
|
|
for (let index in audioSinks) {
|
|
|
|
const audioSink = audioSinks[index];
|
|
|
|
|
|
|
|
const input = document.createElement("input");
|
|
|
|
input.setAttribute("type", "radio");
|
|
|
|
input.setAttribute("name", "audiosink");
|
|
|
|
input.setAttribute("id", `audiosink_${index}`);
|
2024-12-11 11:48:25 +01:00
|
|
|
input.setAttribute("value", audioSink.device_name);
|
2024-09-15 14:16:45 +02:00
|
|
|
input.addEventListener("change", onCloseSelectAudioSinkDialogClicked);
|
|
|
|
if (audioSink.name == currentAudioSink) input.setAttribute("checked", "checked");
|
|
|
|
audioSinkSelectForm.appendChild(input);
|
|
|
|
|
|
|
|
const label = document.createElement("label");
|
|
|
|
label.setAttribute("for", `audiosink_${index}`);
|
2024-12-11 11:48:25 +01:00
|
|
|
label.textContent = audioSink.display_name;
|
2024-09-15 14:16:45 +02:00
|
|
|
audioSinkSelectForm.appendChild(label);
|
|
|
|
}
|
|
|
|
|
|
|
|
audioSinkSelectDialog.showModal();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCloseSelectAudioSinkDialogClicked() {
|
|
|
|
const selectedAudioSink = document.forms["audio-sink-select-dialog-form"].elements["audiosink"].value;
|
|
|
|
localStorage.setItem("audio-sink", selectedAudioSink);
|
|
|
|
changeAudioSink(selectedAudioSink);
|
|
|
|
setTimeout(() => audioSinkSelectDialog.close(), 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
function onShowOpenNewVideoDialogClicked() {
|
|
|
|
const link = document.querySelector("#open-new-video-dialog-link");
|
|
|
|
link.value = "";
|
|
|
|
openNewVideoDialog.showModal();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onOpenVideoButtonClicked() {
|
|
|
|
const link = document.forms["open-new-video-dialog-form"].elements["link"].value;
|
|
|
|
openVideo(link);
|
|
|
|
openNewVideoDialog.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onOpenVideoInBackgroundButtonClicked() {
|
|
|
|
const link = document.forms["open-new-video-dialog-form"].elements["link"].value;
|
|
|
|
openVideoInBackground(link);
|
|
|
|
openNewVideoDialog.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCloseOpenNewVideoDialogClicked() {
|
|
|
|
openNewVideoDialog.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
function askForCloseVideoConfirmation(videoID, videoTitle) {
|
|
|
|
const videoTitleElement = document.querySelector("#close-video-dialog-title");
|
|
|
|
videoTitleElement.textContent = videoTitle;
|
|
|
|
closeVideoDialogID = videoID;
|
|
|
|
closeVideoDialog.showModal();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCloseCloseVideoDialogClicked() {
|
|
|
|
closeVideoDialog.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCloseVideoButtonClicked() {
|
|
|
|
closeVideo(closeVideoDialogID)
|
|
|
|
closeVideoDialog.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCancelCloseVideoButtonClicked() {
|
|
|
|
closeVideoDialog.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatTimestamps(progress, duration) {
|
|
|
|
const progressHours = Math.floor(progress / 3600);
|
|
|
|
const progressRemaining = progress % 3600;
|
|
|
|
const progressMinutes = Math.floor(progressRemaining / 60);
|
|
|
|
const progressSeconds = progressRemaining % 60;
|
|
|
|
|
|
|
|
const durationHours = Math.floor(duration / 3600);
|
|
|
|
const durationRemaining = duration % 3600;
|
|
|
|
const durationMinutes = Math.floor(durationRemaining / 60);
|
|
|
|
const durationSeconds = durationRemaining % 60;
|
|
|
|
|
|
|
|
if (durationHours > 0) {
|
|
|
|
return {
|
|
|
|
progress: `${progressHours.pad(2)}:${progressMinutes.pad(2)}:${progressSeconds.pad(2)}`,
|
|
|
|
duration: `${durationHours.pad(2)}:${durationMinutes.pad(2)}:${durationSeconds.pad(2)}`
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return {
|
|
|
|
progress: `${progressMinutes.pad(2)}:${progressSeconds.pad(2)}`,
|
|
|
|
duration: `${durationMinutes.pad(2)}:${durationSeconds.pad(2)}`
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onPlayPauseButtonClicked() {
|
|
|
|
if (currentVideoData.paused) {
|
|
|
|
unpauseVideo(currentVideoData.id);
|
|
|
|
} else {
|
|
|
|
pauseVideo(currentVideoData.id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onReplayButtonClicked() {
|
|
|
|
seekVideoRelative(currentVideoData.id, -10);
|
|
|
|
}
|
|
|
|
|
|
|
|
function onForwardButtonClicked() {
|
|
|
|
seekVideoRelative(currentVideoData.id, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
function onSeekbarChanged() {
|
|
|
|
seekVideo(currentVideoData.id, parseInt(seekbar.value));
|
|
|
|
}
|
|
|
|
|
|
|
|
function onVolumeBarChanged() {
|
|
|
|
setVolume(parseFloat(volumeBar.value));
|
|
|
|
}
|