hawk / commit
Introduce controls.js - this file has the methods that can be called from the page, for example the callbacks from various UI elements, like search or play/pause the current song.
public/index.html | 1 + public/js/controls.js | 153 ++++++++++++++++++++++++++++++++++++++++++++++ public/js/main.js | 164 +++----------------------------------------------- 3 files changed, 161 insertions(+), 157 deletions(-) diff --git a/public/index.html b/public/index.html index c1a6c65..d8f8632 100644 --- a/public/index.html +++ b/public/index.html @@ -197,6 +197,7 @@ <script src="js/api.js"></script> <script src="js/template.js"></script> <script src="js/collapsible.js"></script> + <script src="js/controls.js"></script> <script src="js/main.js"></script> </body> diff --git a/public/js/controls.js b/public/js/controls.js new file mode 100644 index 0000000..a0e0e67 --- /dev/null +++ b/public/js/controls.js @@ -0,0 +1,153 @@ +let statusText = ''; +setInterval(() => { + const statusDiv = document.getElementById('status'); + statusDiv.innerText = statusText; +}, 100); + +function reportStatus(text) { + statusText = text; +} + +async function pauseOrPlay() { + const currentTrack = await getPlayingTrack(); + if (currentTrack && currentTrack.is_playing) { + await pause(); + } else { + await play(); + } + setCurrentPlayingSong(); +} + +async function playChosenSong(trackName, trackId) { + try { + await playTrack(trackId); + } catch (e) { + console.log("Error playing track") + console.log(e); + reportStatus(e); + } + setCurrentPlayingSong(); +} + +async function searchForMatch() { + const searchButton = document.getElementById('search'); + searchButton.setAttribute('disabled', 'disabled'); + try { + const minutes = document.getElementById('minutes-input').value; + const seconds = document.getElementById('seconds-input').value; + const tracks = await findMatchingTracks(minutes, seconds); + const resultsDiv = document.getElementById('results'); + if (tracks.length == 0) { + resultsDiv.innerHTML = 'No songs found for that duration.'; + } else { + resultsDiv.innerHTML = ''; + tracks.forEach(track => { + const songItem = document.querySelector('#found-song-item'); + const html = interpolate(songItem.innerHTML, { + name: track.name, + artist: track.artists[0].name, + duration: formatDuration(track.duration_ms), + trackId: track.id, + trackHref: track.external_urls.spotify + }); + resultsDiv.innerHTML += html; + }); + } + } catch (e) { + console.error(e); + reportStatus(`Encountered error while searching: ${e}`); + } finally { + searchButton.removeAttribute('disabled'); + } +} + +async function findMatchingTracks(minutes, seconds) { + reportStatus(`Retrieving albums`); + const albums = await getAlbums((state) => { + const { processedCount, totalCount } = state; + if (totalCount <= 0) { + totalCount = "???" + } + reportStatus(`Retrieving albums: ${processedCount} of ${totalCount}`); + }); + + const checkTrack = function (track) { + const duration = track.duration_ms; + const durationInSeconds = Math.floor(duration / 1000); + const durationInMinutes = Math.floor(durationInSeconds / 60); + const durationInRemainingSeconds = durationInSeconds % 60; + + const isMatching = (durationInMinutes == minutes && durationInRemainingSeconds == seconds); + return isMatching; + } + + const tracks = await batchGetTracks(albums.map(album => album.album.id), null) + const foundTracks = tracks.filter(track => checkTrack(track)); + + reportStatus(`Found ${foundTracks.length} track(s)`); + return foundTracks; +} + +async function clearDb() { + await deleteDb(); + window.location.reload(); +} + +const hideOrShow = function (elementClass, show) { + const elements = document.getElementsByClassName(elementClass); + for (let i = 0; i < elements.length; i++) { + const element = elements[i]; + if (show) { + element.setAttribute('style', 'display: block'); + } else { + element.setAttribute('style', 'display: none'); + } + } +} + +function formatDuration(ms) { + // Convert milliseconds to total seconds + let totalSeconds = Math.floor(ms / 1000); + + // Calculate minutes and seconds + let minutes = Math.floor(totalSeconds / 60); + let seconds = totalSeconds % 60; + + // Ensure seconds are always 2 digits + let formattedSeconds = seconds.toString().padStart(2, '0'); + + // Return formatted string + return `${minutes}:${formattedSeconds}`; +} + +async function setCurrentPlayingSong() { + const currentSongSpan = document.getElementById('current-song'); + const currentTrack = await getPlayingTrack(); + let html; + if (!currentTrack) { + html = 'Nothing playing'; + } else { + const album = currentTrack.item.album; + const item = currentTrack.item; + const name = item.name; + const progressPercent = currentTrack.progress_ms / item.duration_ms * 100; + const images = album.images; + let smallestImage = images[images.length - 1]; + const albumArtUrl = smallestImage.url; + const songUrl = item.external_urls.spotify; + const progress = formatDuration(currentTrack.progress_ms); + const totalDuration = formatDuration(item.duration_ms); + + const songItem = document.querySelector('#playing-song'); + html = interpolate(songItem.innerHTML, { + name: name, + artist: album.artists[0].name, + albumArtUrl: albumArtUrl, + songUrl: songUrl, + progressPercent: progressPercent, + progress: progress, + duration: totalDuration + }); + } + currentSongSpan.innerHTML = html; +} diff --git a/public/js/main.js b/public/js/main.js index ceb9209..204af60 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,8 +1,10 @@ +// set favicon based on environment const isLocal = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1"; if (isLocal) { document.querySelector("link[rel='icon']").href = "images/favicon-local.png"; } +// set version and updated info const updateInfoDiv = document.getElementById("updated-info"); const updateInfoTemplate = document.querySelector("#updatedInfoTemplate"); if (updateInfoTemplate) { @@ -12,6 +14,7 @@ if (updateInfoTemplate) { }); } +// handle redirect from Spotify const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); const error = urlParams.get('error'); @@ -26,22 +29,11 @@ if (code) { window.location = getSpotifyRedirectURL(); } +// determine if the user is signed in or not +// hide and show appropriate elements, based on class names const accessToken = localStorage.getItem('access_token'); -const showSignInButton = !accessToken - -const hideOrShow = function (elementClass, show) { - const elements = document.getElementsByClassName(elementClass); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - if (show) { - element.setAttribute('style', 'display: block'); - } else { - element.setAttribute('style', 'display: none'); - } - } -} - -if (showSignInButton) { +const userIsSignedIn = !accessToken +if (userIsSignedIn) { hideOrShow('signedin', false); hideOrShow('signedout', true); } else { @@ -49,146 +41,4 @@ if (showSignInButton) { hideOrShow('signedout', false); setCurrentPlayingSong(); setInterval(setCurrentPlayingSong, 5 * 1000); -} - -async function setCurrentPlayingSong() { - const currentSongSpan = document.getElementById('current-song'); - const currentTrack = await getPlayingTrack(); - let html; - if (!currentTrack) { - html = 'Nothing playing'; - } else { - const album = currentTrack.item.album; - const item = currentTrack.item; - const name = item.name; - const progressPercent = currentTrack.progress_ms / item.duration_ms * 100; - const images = album.images; - let smallestImage = images[images.length - 1]; - const albumArtUrl = smallestImage.url; - const songUrl = item.external_urls.spotify; - const progress = formatDuration(currentTrack.progress_ms); - const totalDuration = formatDuration(item.duration_ms); - - const songItem = document.querySelector('#playing-song'); - html = interpolate(songItem.innerHTML, { - name: name, - artist: album.artists[0].name, - albumArtUrl: albumArtUrl, - songUrl: songUrl, - progressPercent: progressPercent, - progress: progress, - duration: totalDuration - }); - } - currentSongSpan.innerHTML = html; -} - -function formatDuration(ms) { - // Convert milliseconds to total seconds - let totalSeconds = Math.floor(ms / 1000); - - // Calculate minutes and seconds - let minutes = Math.floor(totalSeconds / 60); - let seconds = totalSeconds % 60; - - // Ensure seconds are always 2 digits - let formattedSeconds = seconds.toString().padStart(2, '0'); - - // Return formatted string - return `${minutes}:${formattedSeconds}`; -} - -async function searchForMatch() { - const searchButton = document.getElementById('search'); - searchButton.setAttribute('disabled', 'disabled'); - try { - const minutes = document.getElementById('minutes-input').value; - const seconds = document.getElementById('seconds-input').value; - const tracks = await search(minutes, seconds); - const resultsDiv = document.getElementById('results'); - if (tracks.length == 0) { - resultsDiv.innerHTML = 'No songs found for that duration.'; - } else { - resultsDiv.innerHTML = ''; - tracks.forEach(track => { - const songItem = document.querySelector('#found-song-item'); - const html = interpolate(songItem.innerHTML, { - name: track.name, - artist: track.artists[0].name, - duration: formatDuration(track.duration_ms), - trackId: track.id, - trackHref: track.external_urls.spotify - }); - resultsDiv.innerHTML += html; - }); - } - } catch (e) { - console.error(e); - reportStatus(`Encountered error while searching: ${e}`); - } finally { - searchButton.removeAttribute('disabled'); - } -} - -async function search(minutes, seconds) { - reportStatus(`Retrieving albums`); - const albums = await getAlbums((state) => { - const { processedCount, totalCount } = state; - if (totalCount <= 0) { - totalCount = "???" - } - reportStatus(`Retrieving albums: ${processedCount} of ${totalCount}`); - }); - - const checkTrack = function (track) { - const duration = track.duration_ms; - const durationInSeconds = Math.floor(duration / 1000); - const durationInMinutes = Math.floor(durationInSeconds / 60); - const durationInRemainingSeconds = durationInSeconds % 60; - - const isMatching = (durationInMinutes == minutes && durationInRemainingSeconds == seconds); - return isMatching; - } - - const tracks = await batchGetTracks(albums.map(album => album.album.id), null) - const foundTracks = tracks.filter(track => checkTrack(track)); - - reportStatus(`Found ${foundTracks.length} track(s)`); - return foundTracks; -} - -async function pauseOrPlay() { - const currentTrack = await getPlayingTrack(); - if (currentTrack && currentTrack.is_playing) { - await pause(); - } else { - await play(); - } - setCurrentPlayingSong(); -} - -async function playChosenSong(trackName, trackId) { - try { - await playTrack(trackId); - } catch (e) { - console.log("Error playing track") - console.log(e); - reportStatus(e); - } - setCurrentPlayingSong(); -} - -let statusText = ''; -setInterval(() => { - const statusDiv = document.getElementById('status'); - statusDiv.innerText = statusText; -}, 100); - -function reportStatus(text) { - statusText = text; -} - -async function clearDb() { - await deleteDb(); - window.location.reload(); } \ No newline at end of file