From 576f6f9bc1933056c0c0f669f37dbec67709c06b Mon Sep 17 00:00:00 2001 From: lelo Date: Mon, 24 Mar 2025 11:40:56 +0100 Subject: [PATCH] cleanup js --- static/app.css | 3 ++ static/app.js | 131 +++++++++++++++++++++++++++---------------------- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/static/app.css b/static/app.css index 69fd905..b4b64da 100644 --- a/static/app.css +++ b/static/app.css @@ -226,4 +226,7 @@ footer { #reload-button svg.rotate { animation: rotate-icon 0.5s linear; + transition: opacity 1s ease; + opacity: 0; + cursor: auto; } \ No newline at end of file diff --git a/static/app.js b/static/app.js index 730d554..6c352aa 100644 --- a/static/app.js +++ b/static/app.js @@ -175,99 +175,113 @@ function attachEventListeners() { }); }); +// Cache common DOM elements +const nowPlayingInfo = document.getElementById('nowPlayingInfo'); +const audioPlayer = document.getElementById('globalAudio'); +const playerButton = document.querySelector('.player-button'); +const audioPlayerContainer = document.getElementById('audioPlayerContainer'); +const footer = document.querySelector('footer'); + // Global variable to store the current fetch's AbortController. let currentFetchController = null; document.querySelectorAll('.play-file').forEach(link => { link.addEventListener('click', async function (event) { event.preventDefault(); - const fileType = this.getAttribute('data-file-type'); - const relUrl = this.getAttribute('data-url'); - const nowPlayingInfo = document.getElementById('nowPlayingInfo'); + const { fileType, url: relUrl, index } = this.dataset; + // Remove the class from all file items. document.querySelectorAll('.file-item').forEach(item => { item.classList.remove('currently-playing'); }); if (fileType === 'music') { - const idx = this.getAttribute('data-index'); - const audioPlayer = document.getElementById('globalAudio'); - const playerButton = document.querySelector('.player-button'); - - // Update currentMusicIndex based on the clicked element. - currentMusicIndex = idx !== null ? parseInt(idx) : -1; - - // Show the audio player container. - document.getElementById('audioPlayerContainer').style.display = "block" - - // Add the class to the clicked file item's parent. + // Update the current music index. + currentMusicIndex = index !== undefined ? parseInt(index) : -1; + + // Display the audio player container. + audioPlayerContainer.style.display = "block"; + + // Mark the clicked item as currently playing. this.closest('.file-item').classList.add('currently-playing'); - // Abort any previous fetch if it is still running. + // Abort any previous fetch if still running. if (currentFetchController) { currentFetchController.abort(); } - // Create a new AbortController for the current fetch. currentFetchController = new AbortController(); + // Pause the audio and clear its source. audioPlayer.pause(); - audioPlayer.src = ''; // Clear existing source. - // only show this if it takes longer. avoid flicker - let loaderTimeout = setTimeout(() => { + audioPlayer.src = ''; + + // Set a timeout to display a loader message if needed. + const loaderTimeout = setTimeout(() => { playerButton.innerHTML = playIcon; nowPlayingInfo.textContent = "Wird geladen..."; }, 500); - document.querySelector('footer').style.display = 'flex'; + + footer.style.display = 'flex'; - const mediaUrl = '/media/' + relUrl; + const mediaUrl = `/media/${relUrl}`; try { - // Pass the signal to the fetch so it can be aborted. + // Perform a HEAD request to verify media availability. const response = await fetch(mediaUrl, { method: 'HEAD', signal: currentFetchController.signal }); - clearTimeout(loaderTimeout); // done loading. stop timeout + clearTimeout(loaderTimeout); + if (response.status === 403) { nowPlayingInfo.textContent = "Fehler: Zugriff verweigert."; - window.location.href = '/'; // Redirect if forbidden. + window.location.href = '/'; + return; } else if (!response.ok) { nowPlayingInfo.textContent = `Fehler: Unerwarteter Status (${response.status}).`; console.error('Unexpected response status:', response.status); - } else { - audioPlayer.src = mediaUrl; - audioPlayer.load(); - audioPlayer.play(); - playerButton.innerHTML = pauseIcon; - const pathParts = relUrl.split('/'); - const folderName = pathParts[pathParts.length - 2]; - const fileName = pathParts.pop(); - const pathStr = pathParts.join('/'); - // write into hardware player - if ('mediaSession' in navigator) { - navigator.mediaSession.metadata = new MediaMetadata({ - title: currentMusicFiles[currentMusicIndex].title, - artist: folderName, - artwork: [ - { src: '/static/icons/logo-192x192.png', sizes: '192x192', type: 'image/png' } - ] - }); - }; - nowPlayingInfo.innerHTML = pathStr.replace(/\//g, ' > ') + '
' + fileName.replace('.mp3', '') + ''; - // Delay preloading to avoid blocking playback - setTimeout(preload_audio, 1000); - }; + return; + } + + // Set the media URL, load, and play the audio. + audioPlayer.src = mediaUrl; + audioPlayer.load(); + await audioPlayer.play(); + playerButton.innerHTML = pauseIcon; + + // Process file path for display. + const pathParts = relUrl.split('/'); + const folderName = pathParts[pathParts.length - 2]; + const fileName = pathParts.pop(); + const pathStr = pathParts.join('/'); + + // Update Media Session metadata if available. + if ('mediaSession' in navigator) { + navigator.mediaSession.metadata = new MediaMetadata({ + title: currentMusicFiles[currentMusicIndex].title, + artist: folderName, + artwork: [ + { src: '/static/icons/logo-192x192.png', sizes: '192x192', type: 'image/png' } + ] + }); + } + + nowPlayingInfo.innerHTML = pathStr.replace(/\//g, ' > ') + + '
' + + fileName.replace('.mp3', '') + ''; + + // Delay preloading to avoid blocking playback. + setTimeout(preload_audio, 1000); } catch (error) { - // If the fetch was aborted, error.name will be 'AbortError'. if (error.name === 'AbortError') { console.log('Previous fetch aborted.'); } else { console.error('Error fetching media:', error); nowPlayingInfo.textContent = "Fehler: Netzwerkproblem oder ungültige URL."; - }; - }; + } + } } else if (fileType === 'image') { // Open the gallery modal for image files. openGalleryModal(relUrl); - }; + } }); }); @@ -341,23 +355,20 @@ function reloadDirectory() { // Force reflow to reset the animation void reloadBtnSVG.offsetWidth; reloadBtnSVG.classList.add("rotate"); - - // Gradually fade out the button by reducing opacity over 500ms - setTimeout(() => { - reloadBtnSVG.classList.remove("rotate"); - reloadBtn.style.transition = 'opacity 0.5s ease'; - reloadBtn.style.opacity = '0'; - isReloadButtonVisible = false; // Update the visibility status. - }, 500); + isReloadButtonVisible = false; // Gradually fade back in after 10 seconds setTimeout(() => { + reloadBtnSVG.classList.remove("rotate"); reloadBtn.style.transition = 'opacity 0.5s ease'; reloadBtn.style.opacity = '1'; - isReloadButtonVisible = true; // Update the visibility status. + reloadBtn.style.pointer = 'cursor'; + isReloadButtonVisible = true; }, 10000); } + + if ('mediaSession' in navigator) { // Handler for the play action