mirror of
https://github.com/trafficlunar/jellyfin-spicetify.git
synced 2026-06-13 19:07:06 +00:00
feat: sync volume icons
This commit is contained in:
parent
2cdc4a92d4
commit
43eb8ff31f
1 changed files with 65 additions and 24 deletions
|
|
@ -27,6 +27,13 @@ const BITRATE_MAP: Record<string, string> = {
|
||||||
low: "128000",
|
low: "128000",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const VOLUME_ICONS: Record<string, string> = {
|
||||||
|
high: `<path d="M9.741.85a.75.75 0 0 1 .375.65v13a.75.75 0 0 1-1.125.65l-6.925-4a3.64 3.64 0 0 1-1.33-4.967 3.64 3.64 0 0 1 1.33-1.332l6.925-4a.75.75 0 0 1 .75 0zm-6.924 5.3a2.14 2.14 0 0 0 0 3.7l5.8 3.35V2.8zm8.683 4.29V5.56a2.75 2.75 0 0 1 0 4.88"></path><path d="M11.5 13.614a5.752 5.752 0 0 0 0-11.228v1.55a4.252 4.252 0 0 1 0 8.127z"></path>`,
|
||||||
|
medium: `<path d="M9.741.85a.75.75 0 0 1 .375.65v13a.75.75 0 0 1-1.125.65l-6.925-4a3.64 3.64 0 0 1-1.33-4.967 3.64 3.64 0 0 1 1.33-1.332l6.925-4a.75.75 0 0 1 .75 0zm-6.924 5.3a2.14 2.14 0 0 0 0 3.7l5.8 3.35V2.8zm8.683 6.087a4.502 4.502 0 0 0 0-8.474v1.65a3 3 0 0 1 0 5.175z"></path>`,
|
||||||
|
low: `<path d="M9.741.85a.75.75 0 0 1 .375.65v13a.75.75 0 0 1-1.125.65l-6.925-4a3.64 3.64 0 0 1-1.33-4.967 3.64 3.64 0 0 1 1.33-1.332l6.925-4a.75.75 0 0 1 .75 0zm-6.924 5.3a2.14 2.14 0 0 0 0 3.7l5.8 3.35V2.8zm8.683 4.29V5.56a2.75 2.75 0 0 1 0 4.88"></path>`,
|
||||||
|
muted: `<path d="M13.86 5.47a.75.75 0 0 0-1.061 0l-1.47 1.47-1.47-1.47A.75.75 0 0 0 8.8 6.53L10.269 8l-1.47 1.47a.75.75 0 1 0 1.06 1.06l1.47-1.47 1.47 1.47a.75.75 0 0 0 1.06-1.06L12.39 8l1.47-1.47a.75.75 0 0 0 0-1.06"></path><path d="M10.116 1.5A.75.75 0 0 0 8.991.85l-6.925 4a3.64 3.64 0 0 0-1.33 4.967 3.64 3.64 0 0 0 1.33 1.332l6.925 4a.75.75 0 0 0 1.125-.649v-1.906a4.7 4.7 0 0 1-1.5-.694v1.3L2.817 9.852a2.14 2.14 0 0 1-.781-2.92c.187-.324.456-.594.78-.782l5.8-3.35v1.3c.45-.313.956-.55 1.5-.694z"></path>`,
|
||||||
|
};
|
||||||
|
|
||||||
// Stop Jellfin audio
|
// Stop Jellfin audio
|
||||||
export function stop() {
|
export function stop() {
|
||||||
hijackActive.set(false);
|
hijackActive.set(false);
|
||||||
|
|
@ -117,7 +124,7 @@ export function registerEvents() {
|
||||||
|
|
||||||
const results = new Fuse(list, {
|
const results = new Fuse(list, {
|
||||||
keys: ["name", "artists"],
|
keys: ["name", "artists"],
|
||||||
threshold: 0.7,
|
threshold: 0.75,
|
||||||
}).search(`${trackName} ${artists}`);
|
}).search(`${trackName} ${artists}`);
|
||||||
|
|
||||||
console.debug(`[Jellyfin]: Query is "${trackName} ${artists}"`);
|
console.debug(`[Jellyfin]: Query is "${trackName} ${artists}"`);
|
||||||
|
|
@ -188,6 +195,7 @@ export function registerEvents() {
|
||||||
oldTime = event.data;
|
oldTime = event.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const volumeIcon: SVGElement | null = document.querySelector(".volume-bar__icon-button > span > svg");
|
||||||
const volumeSlider: HTMLDivElement | null = document.querySelector(".volume-bar__slider-container > div > div");
|
const volumeSlider: HTMLDivElement | null = document.querySelector(".volume-bar__slider-container > div > div");
|
||||||
const volumeSliderInput: HTMLInputElement | null = document.querySelector(".volume-bar__slider-container > div > label > input");
|
const volumeSliderInput: HTMLInputElement | null = document.querySelector(".volume-bar__slider-container > div > label > input");
|
||||||
|
|
||||||
|
|
@ -203,6 +211,7 @@ export function registerEvents() {
|
||||||
audio.volume = Math.pow(currentVolume, 3) * 0.425;
|
audio.volume = Math.pow(currentVolume, 3) * 0.425;
|
||||||
if (volumeSlider) volumeSlider.style.setProperty("--progress-bar-transform", `${currentVolume * 100}%`);
|
if (volumeSlider) volumeSlider.style.setProperty("--progress-bar-transform", `${currentVolume * 100}%`);
|
||||||
if (volumeSliderInput) volumeSliderInput.value = currentVolume.toString();
|
if (volumeSliderInput) volumeSliderInput.value = currentVolume.toString();
|
||||||
|
if (volumeIcon) volumeIcon.innerHTML = VOLUME_ICONS[getExpectedVolumeIcon()];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return Reflect.apply(target, thisArg, args);
|
return Reflect.apply(target, thisArg, args);
|
||||||
|
|
@ -210,8 +219,9 @@ export function registerEvents() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Spotify tries to set the volume on the slider to 0 when hijacked, this tries to revert it
|
// Spotify tries to set the volume on the slider to 0 when hijacked, this tries to revert it
|
||||||
if (!volumeSlider) return;
|
if (volumeSlider) {
|
||||||
const observer = new MutationObserver(() => {
|
const observer = new MutationObserver(() => {
|
||||||
|
if (!hijackActive.get()) return;
|
||||||
const transform = volumeSlider.style.getPropertyValue("--progress-bar-transform");
|
const transform = volumeSlider.style.getPropertyValue("--progress-bar-transform");
|
||||||
|
|
||||||
const currentPercent = currentVolume * 100;
|
const currentPercent = currentVolume * 100;
|
||||||
|
|
@ -224,17 +234,48 @@ export function registerEvents() {
|
||||||
observer.observe(volumeSlider, { attributes: true, attributeFilter: ["style"] });
|
observer.observe(volumeSlider, { attributes: true, attributeFilter: ["style"] });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(volumeSlider, { attributes: true, attributeFilter: ["style"] });
|
observer.observe(volumeSlider, { attributes: true, attributeFilter: ["style"] });
|
||||||
|
}
|
||||||
|
|
||||||
// Similar to the other observer, but for the input (you'll notice it when scrolling the volume slider)
|
// Similar to the other observer, but for the input (you'll notice it when scrolling the volume slider)
|
||||||
if (!volumeSliderInput) return;
|
if (volumeSliderInput) {
|
||||||
const inputObserver = new MutationObserver(() => {
|
const inputObserver = new MutationObserver(() => {
|
||||||
|
if (!hijackActive.get()) return;
|
||||||
|
|
||||||
// 0.1% tolerance (floating point)
|
// 0.1% tolerance (floating point)
|
||||||
if (Math.abs(currentVolume - volumeSliderInput.valueAsNumber) > 0.1) {
|
if (Math.abs(currentVolume - volumeSliderInput.valueAsNumber) > 0.1) {
|
||||||
inputObserver.disconnect(); // prevent re-triggering while we update
|
inputObserver.disconnect(); // prevent re-triggering while we update
|
||||||
volumeSliderInput.value = currentVolume.toString();
|
volumeSliderInput.value = currentVolume.toString();
|
||||||
inputObserver.observe(volumeSlider, { attributes: true, attributeFilter: ["value"] });
|
inputObserver.observe(volumeSliderInput, { attributes: true, attributeFilter: ["value"] });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
inputObserver.observe(volumeSlider, { attributes: true, attributeFilter: ["value"] });
|
|
||||||
|
inputObserver.observe(volumeSliderInput, { attributes: true, attributeFilter: ["value"] });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar, but for volume icon (tries to show up as muted)
|
||||||
|
if (volumeIcon) {
|
||||||
|
let currentIcon = "";
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
if (!hijackActive.get()) return;
|
||||||
|
|
||||||
|
const expectedIcon = getExpectedVolumeIcon();
|
||||||
|
if (currentIcon === expectedIcon) return;
|
||||||
|
|
||||||
|
observer.disconnect(); // prevent re-triggering while we update
|
||||||
|
currentIcon = expectedIcon;
|
||||||
|
volumeIcon.innerHTML = VOLUME_ICONS[getExpectedVolumeIcon()];
|
||||||
|
observer.observe(volumeIcon, { childList: true, subtree: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(volumeIcon, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExpectedVolumeIcon(): string {
|
||||||
|
if (currentVolume >= 0.66) return "high";
|
||||||
|
if (currentVolume >= 0.33) return "medium";
|
||||||
|
if (currentVolume !== 0) return "low";
|
||||||
|
return "muted";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue