diff --git a/.common/utils/helpers.js b/.common/utils/helpers.js index a54e3ae..3e2816e 100644 --- a/.common/utils/helpers.js +++ b/.common/utils/helpers.js @@ -411,4 +411,77 @@ async function LoadHTMLTemplate(name) { if (!document.getElementById(template.id)) { document.body.appendChild(template.cloneNode(true)); } +} + +// Calculate an accent color given an image +// async function GetAccentPalette(imageUrl, count = 20) { +// if (typeof ColorThief === 'undefined') { +// await new Promise((resolve, reject) => { +// const script = document.createElement('script'); +// script.src = "https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.2/color-thief.min.js"; +// script.onload = resolve; +// script.onerror = reject; +// document.head.appendChild(script); +// }); +// } + +// return new Promise((resolve) => { +// const img = new Image(); +// img.crossOrigin = "Anonymous"; +// img.src = imageUrl; + +// img.onload = () => { +// const colorThief = new ColorThief(); +// // Clamp count between 2 and 20 to ensure algorithm stability +// const safeCount = Math.max(2, Math.min(20, count)); +// const palette = colorThief.getPalette(img, safeCount); + +// // Convert RGB array to Hex +// const hexPalette = palette.map(([r, g, b]) => { +// return "#" + ((1 << 24) + (r << 16) + (g << 8) + b) +// .toString(16) +// .slice(1); +// }); + +// resolve(hexPalette); +// }; + +// img.onerror = () => resolve(["#ffffff"]); +// }); +// } + +async function GetAccentPalette(imageUrl) { + // 1. Dynamic Loader: Load Vibrant.js + if (typeof Vibrant === 'undefined') { + await new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = "https://cdnjs.cloudflare.com/ajax/libs/node-vibrant/3.1.6/vibrant.min.js"; + script.onload = resolve; + script.onerror = reject; + document.head.appendChild(script); + }); + } + + return new Promise((resolve) => { + // Vibrant can take the URL directly! + Vibrant.from(imageUrl).getPalette((err, palette) => { + if (err) { + console.warn("Vibrant failed, using fallback."); + return resolve({ + Vibrant: "#ffffff", + Muted: "#cccccc", + DarkVibrant: "#000000" + }); + } + + // Extract Hex from each swatch + const hexPalette = {}; + for (let role in palette) { + if (palette[role]) { + hexPalette[role] = palette[role].getHex(); + } + } + resolve(hexPalette); + }); + }); } \ No newline at end of file diff --git a/now-playing/index.html b/now-playing/index.html index 4d55e80..3a7bd47 100644 --- a/now-playing/index.html +++ b/now-playing/index.html @@ -13,6 +13,7 @@ + diff --git a/now-playing/style.css b/now-playing/style.css index ef982ed..49bd6c0 100644 --- a/now-playing/style.css +++ b/now-playing/style.css @@ -9,6 +9,135 @@ body { display: flex; justify-content: center; align-items: center; - height: 100vh; /* Full viewport height */ + height: 100vh; margin: 0.5em; +} + + +@keyframes fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +@keyframes slide-in-from-top { + 0% { + transform: translateY(-1em); + opacity: 0; + } + + 100% { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes slide-in-from-top { + 0% { + transform: translateY(-1em); + opacity: 0; + } + + 100% { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes slide-out-top { + 0% { + transform: translateY(0); + opacity: 1; + } + + 100% { + transform: translateY(-1em); + opacity: 0; + } +} + +@keyframes slide-in-from-bottom { + 0% { + transform: translateY(1em); + opacity: 0; + } + + 100% { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes slide-out-bottom { + 0% { + transform: translateY(0); + opacity: 1; + } + + 100% { + transform: translateY(1em); + opacity: 0; + } +} + +@keyframes slide-in-from-left { + 0% { + transform: translateX(-1em); + opacity: 0; + } + + 100% { + transform: translateX(0); + opacity: 1; + } +} + +@keyframes slide-out-left { + 0% { + transform: translateX(0); + opacity: 1; + } + + 100% { + transform: translateX(-1em); + opacity: 0; + } +} + +@keyframes slide-in-from-right { + 0% { + transform: translateX(1em); + opacity: 0; + } + + 100% { + transform: translateX(0); + opacity: 1; + } +} + +@keyframes slide-out-right { + 0% { + transform: translateX(0); + opacity: 1; + } + + 100% { + transform: translateX(1em); + opacity: 0; + } } \ No newline at end of file diff --git a/now-playing/themes/card/style.css b/now-playing/themes/card/style.css index ef95aad..0d44941 100644 --- a/now-playing/themes/card/style.css +++ b/now-playing/themes/card/style.css @@ -16,7 +16,7 @@ position: relative; background-size: cover; background-position: center; - margin: 0.5em 0em 1em 0em; + margin: 0em 0em 1em 0em; } #album-art-layer, @@ -81,7 +81,7 @@ position: relative; /* Keeps it in the document flow */ z-index: 2; /* Sits above the background-layer */ - padding: 1em 1.75em; + padding: 1.5em 1.25em; display: flex; flex-direction: column; gap: 0.3em; @@ -162,130 +162,4 @@ justify-content: space-between; font-size: 0.7em; opacity: 0.5; -} - -@keyframes fade-in { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@keyframes fade-out { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } -}@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-top { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-bottom { - 0% { - transform: translateY(1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-bottom { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(1em); - opacity: 0; - } -} - -@keyframes slide-in-from-left { - 0% { - transform: translateX(-1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-left { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-right { - 0% { - transform: translateX(1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-right { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(1em); - opacity: 0; - } } \ No newline at end of file diff --git a/now-playing/themes/compact/index.html b/now-playing/themes/compact/index.html index f93bd51..c691cde 100644 --- a/now-playing/themes/compact/index.html +++ b/now-playing/themes/compact/index.html @@ -1,12 +1,17 @@
-
+
+ +
-
-
+
+
+
\ No newline at end of file diff --git a/now-playing/themes/compact/script.js b/now-playing/themes/compact/script.js index 04a943f..acedc57 100644 --- a/now-playing/themes/compact/script.js +++ b/now-playing/themes/compact/script.js @@ -13,17 +13,13 @@ let hideTimeout = null; const mainWrapper = document.getElementById('main-wrapper'); const albumArtContainer = document.getElementById('album-art-container'); const songInfoContainer = document.getElementById('song-info-container'); -const albumArtLayer = document.getElementById('album-art-layer'); -const albumArtTransition = document.getElementById('album-art-transition-layer'); -const backgroundLayer = document.getElementById('background-layer'); -// const backgroundTransitionLayer = document.getElementById('background-transition-layer'); +const progressBar = document.getElementById('progress-bar'); const trackLabel = document.getElementById('track-label'); const artistLabel = document.getElementById('artist-label'); +const trackLabelBase = document.getElementById('track-label-background'); +const artistLabelBase = document.getElementById('artist-label-background'); const songLabel = document.getElementById('song-label'); -// const progressContainer = document.getElementById('progress-container'); -// const progressBarFill = document.getElementById('progress-bar-fill'); -// const currentTimeLabel = document.getElementById('current-time'); -// const durationLabel = document.getElementById('duration'); +const songLabelBackground = document.getElementById('song-label-background'); @@ -36,23 +32,6 @@ if (maxWidth > 0) else mainWrapper.style.width = `100%`; -// // Set album art style -// switch (albumArt) -// { -// case 'none': -// albumArtContainer.style.display = 'none'; -// break; -// case 'show': -// albumArtContainer.style.display = ''; -// break; -// case 'spinny': -// break; -// } - -// // Set progress bar visibility -// if (!showProgressBar) -// progressContainer.style.display = 'none'; - //////////////////// @@ -60,7 +39,7 @@ else //////////////////// // Each theme must implement the following -function UpdatePlayerState(data) { +async function UpdatePlayerState(data) { // Check if the user has provided a target application in the settings const isFiltering = targetApplication && targetApplication.trim() !== ""; @@ -81,6 +60,9 @@ function UpdatePlayerState(data) { const playbackInfo = targetSession.playback_info; const mediaProps = targetSession.media_properties; const timelineProps = targetSession.timeline_properties; + + // Calcualte an accent color + const accentColorPalette = await GetAccentPalette(mediaProps.Base64Image); // 1. Check if playback status has changed and update visibility accordingly if (playbackInfo.PlaybackStatus !== CurrentPlaybackStatus) { @@ -94,7 +76,7 @@ function UpdatePlayerState(data) { // 2. Check if the track name/artist have changed - this is our indicator that the next track has loaded const newTrackKey = `${mediaProps.Title}|${mediaProps.Artist}`; if (newTrackKey !== CurrentSong) { - ChangeTrack(mediaProps); // Now trigger your cross-fade logic here! + ChangeTrack(mediaProps, accentColorPalette); // Now trigger your cross-fade logic here! CurrentSong = newTrackKey; // Update the tracker with the string key } @@ -112,20 +94,20 @@ function UpdatePlayerState(data) { const isPlaying = (targetSession.playback_info.PlaybackStatus === PlaybackStatus.PLAYING); const currentPositionMs = isPlaying && timelineProps.EndTime > 0 ? timelineProps.Position + driftMs : timelineProps.Position; - // // Update the label using your naming convention - // currentTimeLabel.innerText = - // ConvertMillisecondsToMinutesSoThatItLooksBetterOnTheOverlay(currentPositionMs); - - // durationLabel.innerText = - // ConvertMillisecondsToMinutesSoThatItLooksBetterOnTheOverlay(timelineProps.EndTime); - // Set progressbar // Ensure we don't divide by zero or exceed 100% const durationMs = timelineProps.EndTime; let progressPercent = durationMs > 0 ? (currentPositionMs / durationMs) * 100 : 0; progressPercent = Math.min(100, Math.max(0, progressPercent)); - backgroundLayer.style.width = `${progressPercent}%`; - // progressBarFill.style.setProperty('--accent-color', mediaProps.AccentColor); + + // Calculate how much needs to be hidden (the right-side offset) + const clipRight = 100 - progressPercent; + + // Update the clip-path + progressBar.style.clipPath = `inset(0 ${clipRight}% 0 0)`; + + // const clipRight = progressPercent; + // progressBar.style.maskImage = `linear-gradient(to right, black calc(${clipRight}% - 4em), transparent ${clipRight}%)` } } else @@ -161,59 +143,55 @@ function SetVisibility(visible) { } } -async function ChangeTrack(mediaProps) { +async function ChangeTrack(mediaProps, accentColor) { // Fade in the overlay (shows the new text) songLabel.style.opacity = "0"; - // trackLabel.style.opacity = "0"; - // artistLabel.style.opacity = "0"; - // backgroundLayer.style.opacity = "0"; - // albumArtLayer.style.opacity = "0"; + songLabelBackground.style.opacity = "0"; // Wait for fade (0.5s), then swap the real text and hide overlay setTimeout(() => { trackLabel.innerText = mediaProps.Title; artistLabel.innerText = mediaProps.Artist; - // songLabel.innerText = `${mediaProps.Artist}${mediaProps.Title}` + trackLabelBase.innerText = mediaProps.Title; + artistLabelBase.innerText = mediaProps.Artist; // Extract the image source string (use fallback if Windows has no art) - // const newArtUrl = mediaProps.Base64Image; - const accent = mediaProps.AccentColor || "#ffffff"; // Set the pill color - backgroundLayer.style.background = accent; + songInfoContainer.style.background = accentColor.DarkMuted + "80"; + progressBar.style.background = accentColor.LightVibrant; + songLabel.style.color = accentColor.DarkVibrant; + songLabelBackground.style.color = accentColor.LightVibrant; - // Set the image - // backgroundLayer.style.backgroundImage = `url('${newArtUrl}')`; - // albumArtLayer.style.backgroundImage = `url('${newArtUrl}')`; - - // // Apply a tint: Use 30% opacity of the accent color + a dark overlay for contrast - // // 'rgba(0,0,0,0.6)' ensures the text stays readable - // backgroundLayer.style.backgroundColor = accent + "80"; // 80 is 50% opacity in hex - - // trackLabel.style.opacity = ""; - // artistLabel.style.opacity = ""; songLabel.style.opacity = ""; - // backgroundLayer.style.opacity = ""; - // albumArtLayer.style.opacity = ""; + songLabelBackground.style.opacity = ""; + + // // If text is too long, add a marquee + // requestAnimationFrame(() => { + // const containerWidth = songInfoContainer.clientWidth; + // const textWidth = trackLabel.clientWidth + artistLabel.clientWidth; + + + // console.log(containerWidth); + // console.log(textWidth); + + // if (textWidth > containerWidth) { + // songLabel.classList.add('scrolling-text'); + // songLabelBackground.classList.add('scrolling-text'); + // // Calculate speed: 50 pixels per second is a good standard + // const duration = (textWidth + containerWidth) / 50; + // console.log(duration); + // document.documentElement.style.setProperty('--scroll-duration', `${duration}s`); + // document.documentElement.style.setProperty('--container-width', `${textWidth}px`); + // document.documentElement.style.setProperty('--text-width', `-${textWidth}px`); + // } else { + // songLabel.classList.remove('scrolling-text'); + // songLabelBackground.classList.remove('scrolling-text'); + // } + // }); setTimeout(() => { - // // Set the image - // backgroundTransitionLayer.style.backgroundImage = `url('${newArtUrl}')`; - // albumArtTransition.style.backgroundImage = `url('${newArtUrl}')`; - - // // Apply a tint: Use 30% opacity of the accent color + a dark overlay for contrast - // // 'rgba(0,0,0,0.6)' ensures the text stays readable - // backgroundTransitionLayer.style.backgroundColor = accent + "80"; // 80 is 50% opacity in hex - SetVisibility(true); // Show the overlay for a few seconds if autoHide is enabled }, 250); }, 250); -} - -// function SetAlbumArtSize() { -// const height = songInfoContainer.offsetHeight; -// albumArtContainer.style.height = `${1.5 * height}px`; -// albumArtContainer.style.width = `${1.5 * height}px`; -// } - -// SetAlbumArtSize(); \ No newline at end of file +} \ No newline at end of file diff --git a/now-playing/themes/compact/style.css b/now-playing/themes/compact/style.css index a020f08..d6e8a01 100644 --- a/now-playing/themes/compact/style.css +++ b/now-playing/themes/compact/style.css @@ -2,7 +2,6 @@ width: 500px; display: flex; flex-direction: row; - /* This forces both containers to be the same height */ align-items: stretch; gap: 1em; opacity: 0; @@ -17,186 +16,76 @@ overflow: hidden; align-items: center; border-radius: 1em; - padding: 0.25em 0.75em; - background-color: #00000080; + transition: all 1s ease-in-out; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); /* Adds depth */ + + display: grid; + /* This creates a single cell that both children will occupy */ + grid-template-areas: "stack"; } /* The content sits on top */ -#song-info-wrapper { - position: relative; /* Keeps it in the document flow */ - z-index: 2; /* Sits above the background-layer */ - width: 100%; - /* padding: 1em 1.75em; - display: flex; - flex-direction: column; - gap: 0.3em; */ +#progress-bar { + grid-area: stack; + position: relative; + z-index: 2; /* Sits above the progress bar */ + transition: all 1s ease-in-out; + width: 100%; + /* mask-image: linear-gradient(to right, black calc(100% - 4em), transparent 100%); + -webkit-mask-image: linear-gradient(to right, black calc(100% - 4em), transparent 100%); */ } -#song-label { +.progress { + box-sizing: border-box; + padding: 0.25em 0.75em; + grid-area: stack; + display: flex; + /* justify-content: center; */ + min-width: 0; +} + +#song-label, +#song-label-background { font-size: 1em; - width: 100%; display: flex; flex-direction: row; align-items: baseline; gap: 0.5em; + min-width: 100%; + /* justify-content: center; */ + overflow: visible; } -#artist-label { +#artist-label, +#artist-label-background { font-size: 0.8em; font-weight: 400; opacity: 0.7; } -#track-label { +#track-label, +#track-label-background { font-weight: 700; } - .text-label { white-space: nowrap; - overflow: hidden; - mask-image: linear-gradient(to right, black calc(100% - 1em), transparent 100%); - -webkit-mask-image: linear-gradient(to right, black calc(100% - 1em), transparent 100%); + /* overflow: hidden; */ transition: opacity 0.25s ease-in-out; } -/* The background now fills the frame */ -#background-layer { - position: absolute; - top: 0; - left: 0; - width: 0%; - height: 100%; - z-index: 1; - transition: all 1s ease; - mask-image: linear-gradient(to right, black calc(100% - 1em), transparent 100%); - -webkit-mask-image: linear-gradient(to right, black calc(100% - 1em), transparent 100%); - transition: all 1s ease-in-out; - opacity: 0.7; + +/* TODO: Marquee doesn't work that well, disabling for now */ +/* .scrolling-text { + animation: marquee var(--scroll-duration, 15s) linear infinite; + display: inline-block; } -@keyframes fade-in { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@keyframes fade-out { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } -}@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-top { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-bottom { - 0% { - transform: translateY(1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-bottom { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(1em); - opacity: 0; - } -} - -@keyframes slide-in-from-left { - 0% { - transform: translateX(-1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-left { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-right { - 0% { - transform: translateX(1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-right { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(1em); - opacity: 0; - } -} \ No newline at end of file +@keyframes marquee { + 0% { + transform: translateX(var(--container-width)); + } + 100% { + transform: translateX(var(--text-width)); + } +} */ \ No newline at end of file diff --git a/now-playing/themes/simple/script.js b/now-playing/themes/simple/script.js index bad07b6..f2a0d69 100644 --- a/now-playing/themes/simple/script.js +++ b/now-playing/themes/simple/script.js @@ -174,7 +174,7 @@ async function ChangeTrack(mediaProps) { // Extract the image source string (use fallback if Windows has no art) const newArtUrl = mediaProps.Base64Image; - const accent = mediaProps.AccentColor || "#ffffff"; + // const accent = mediaProps.AccentColor || "#ffffff"; // Set the image // backgroundLayer.style.backgroundImage = `url('${newArtUrl}')`; diff --git a/now-playing/themes/simple/style.css b/now-playing/themes/simple/style.css index 4a5797c..ef70fe0 100644 --- a/now-playing/themes/simple/style.css +++ b/now-playing/themes/simple/style.css @@ -80,130 +80,4 @@ mask-image: linear-gradient(to right, black calc(100% - 1em), transparent 100%); -webkit-mask-image: linear-gradient(to right, black calc(100% - 1em), transparent 100%); transition: opacity 0.25s ease-in-out; -} - -@keyframes fade-in { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@keyframes fade-out { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } -}@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-top { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-bottom { - 0% { - transform: translateY(1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-bottom { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(1em); - opacity: 0; - } -} - -@keyframes slide-in-from-left { - 0% { - transform: translateX(-1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-left { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-right { - 0% { - transform: translateX(1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-right { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(1em); - opacity: 0; - } } \ No newline at end of file diff --git a/now-playing/themes/standard/script.js b/now-playing/themes/standard/script.js index 069da38..bf20bdb 100644 --- a/now-playing/themes/standard/script.js +++ b/now-playing/themes/standard/script.js @@ -59,7 +59,7 @@ if (!showProgressBar) //////////////////// // Each theme must implement the following -function UpdatePlayerState(data) { +async function UpdatePlayerState(data) { // Check if the user has provided a target application in the settings const isFiltering = targetApplication && targetApplication.trim() !== ""; @@ -80,6 +80,9 @@ function UpdatePlayerState(data) { const playbackInfo = targetSession.playback_info; const mediaProps = targetSession.media_properties; const timelineProps = targetSession.timeline_properties; + + // Calcualte an accent color + const accentColorPalette = await GetAccentPalette(mediaProps.Base64Image); // 1. Check if playback status has changed and update visibility accordingly if (playbackInfo.PlaybackStatus !== CurrentPlaybackStatus) { @@ -93,8 +96,8 @@ function UpdatePlayerState(data) { // 2. Check if the track name/artist have changed - this is our indicator that the next track has loaded const newTrackKey = `${mediaProps.Title}|${mediaProps.Artist}`; if (newTrackKey !== CurrentSong) { - ChangeTrack(mediaProps); // Now trigger your cross-fade logic here! - CurrentSong = newTrackKey; // Update the tracker with the string key + ChangeTrack(mediaProps, accentColorPalette.LightVibrant); // Now trigger your cross-fade logic here! + CurrentSong = newTrackKey; // Update the tracker with the string key } // 3. Update the progress info @@ -124,7 +127,7 @@ function UpdatePlayerState(data) { let progressPercent = durationMs > 0 ? (currentPositionMs / durationMs) * 100 : 0; progressPercent = Math.min(100, Math.max(0, progressPercent)); progressBarFill.style.width = `${progressPercent}%`; - progressBarFill.style.setProperty('--accent-color', mediaProps.AccentColor); + progressBarFill.style.setProperty('--accent-color', accentColorPalette.LightVibrant); } } else @@ -160,7 +163,7 @@ function SetVisibility(visible) { } } -async function ChangeTrack(mediaProps) { +async function ChangeTrack(mediaProps, tintColor) { // Fade in the overlay (shows the new text) trackLabel.style.opacity = "0"; artistLabel.style.opacity = "0"; @@ -168,13 +171,12 @@ async function ChangeTrack(mediaProps) { albumArtLayer.style.opacity = "0"; // Wait for fade (0.5s), then swap the real text and hide overlay - setTimeout(() => { + setTimeout(async () => { trackLabel.innerText = mediaProps.Title; artistLabel.innerText = mediaProps.Artist; // Extract the image source string (use fallback if Windows has no art) const newArtUrl = mediaProps.Base64Image; - const accent = mediaProps.AccentColor || "#ffffff"; // Set the image backgroundLayer.style.backgroundImage = `url('${newArtUrl}')`; @@ -182,7 +184,7 @@ async function ChangeTrack(mediaProps) { // Apply a tint: Use 30% opacity of the accent color + a dark overlay for contrast // 'rgba(0,0,0,0.6)' ensures the text stays readable - backgroundLayer.style.backgroundColor = accent + "80"; // 80 is 50% opacity in hex + backgroundLayer.style.backgroundColor = tintColor + "80"; // 80 is 50% opacity in hex trackLabel.style.opacity = ""; artistLabel.style.opacity = ""; @@ -196,7 +198,7 @@ async function ChangeTrack(mediaProps) { // Apply a tint: Use 30% opacity of the accent color + a dark overlay for contrast // 'rgba(0,0,0,0.6)' ensures the text stays readable - backgroundTransitionLayer.style.backgroundColor = accent + "80"; // 80 is 50% opacity in hex + backgroundTransitionLayer.style.backgroundColor = tintColor + "80"; // 80 is 50% opacity in hex SetVisibility(true); // Show the overlay for a few seconds if autoHide is enabled }, 250); @@ -209,4 +211,6 @@ function SetAlbumArtSize() { albumArtContainer.style.width = `${height}px`; } -SetAlbumArtSize(); \ No newline at end of file +requestAnimationFrame(() => { + SetAlbumArtSize(); +}); \ No newline at end of file diff --git a/now-playing/themes/standard/style.css b/now-playing/themes/standard/style.css index cdf4a74..dd36c5b 100644 --- a/now-playing/themes/standard/style.css +++ b/now-playing/themes/standard/style.css @@ -63,7 +63,7 @@ background-repeat: no-repeat; background-blend-mode: overlay; /* Or 'soft-light' for a subtler effect */ - filter: blur(0px) brightness(0.3); + filter: blur(0px) brightness(0.3) saturate(1.2); transform: scale(1.1); /* Slightly zoom in to cover edges when blurred */ } @@ -161,130 +161,4 @@ justify-content: space-between; font-size: 0.7em; opacity: 0.5; -} - -@keyframes fade-in { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@keyframes fade-out { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } -}@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-in-from-top { - 0% { - transform: translateY(-1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-top { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-bottom { - 0% { - transform: translateY(1em); - opacity: 0; - } - - 100% { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes slide-out-bottom { - 0% { - transform: translateY(0); - opacity: 1; - } - - 100% { - transform: translateY(1em); - opacity: 0; - } -} - -@keyframes slide-in-from-left { - 0% { - transform: translateX(-1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-left { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(-1em); - opacity: 0; - } -} - -@keyframes slide-in-from-right { - 0% { - transform: translateX(1em); - opacity: 0; - } - - 100% { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slide-out-right { - 0% { - transform: translateX(0); - opacity: 1; - } - - 100% { - transform: translateX(1em); - opacity: 0; - } } \ No newline at end of file