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}`); input.setAttribute("value", audioSink.device_name); 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}`); label.textContent = audioSink.display_name; 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)); }