feat: improvements to background music plugin

This commit is contained in:
SethBurkart123
2025-10-13 13:26:15 +11:00
parent f1b707ab25
commit 7192f41535
2 changed files with 42 additions and 23 deletions
@@ -24,10 +24,11 @@
async function handleFiles(files: FileList | null) { async function handleFiles(files: FileList | null) {
const file = files?.[0] const file = files?.[0]
if (!file) return if (!file) return
// Restrict to WAV only for best responsiveness // Accept WAV and MP3 files
const isWav = file.type === 'audio/wav' || file.name.toLowerCase().endsWith('.wav') const isSupported = file.type === 'audio/wav' || file.type === 'audio/mpeg' ||
if (!isWav) { file.name.toLowerCase().endsWith('.wav') || file.name.toLowerCase().endsWith('.mp3')
alert('Please select a .wav audio file') if (!isSupported) {
alert('Please select a .wav or .mp3 audio file')
return return
} }
@@ -76,7 +77,7 @@
</script> </script>
<div <div
class="flex relative justify-between items-center rounded-lg px-3 py-2 cursor-pointer select-none border border-zinc-300 dark:border-zinc-600 bg-white/20 dark:bg-zinc-800/30" class="relative cursor-pointer select-none"
onclick={() => triggerSelect()} onclick={() => triggerSelect()}
ondragover={(e) => { e.stopPropagation(); dragging = true }} ondragover={(e) => { e.stopPropagation(); dragging = true }}
ondragleave={() => dragging = false} ondragleave={() => dragging = false}
@@ -90,25 +91,27 @@
role="button" role="button"
tabindex="0" tabindex="0"
> >
<div class="flex items-center gap-3"> <div class="flex gap-3 items-center">
<div class="flex gap-2 items-center px-3 py-1 text-xs rounded-lg border border-dashed transition border-zinc-300 dark:border-zinc-600 text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-300">
<span class="text-lg font-IconFamily">{'\ued47'}</span>
<span>{filename ? 'Change audio' : 'Upload audio'}</span>
</div>
{#if filename} {#if filename}
<div class="text-xs text-zinc-600 dark:text-zinc-300"> <div class="flex items-center px-3 py-1 rounded-lg bg-zinc-200 dark:bg-zinc-800">
{filename}{#if durationText}{durationText}{/if} <div class="text-xs text-zinc-600 dark:text-zinc-300">
{filename}
<p>{durationText}</p>
</div>
<button
class="flex justify-center items-center m-1 text-lg dark:text-white size-7"
onclick={(e) => { e.stopPropagation(); removeAudio() }}
aria-label="Remove audio"
>&#215;</button>
</div>
{:else}
<div class="flex gap-2 items-center px-3 py-1 text-xs rounded-lg border border-dashed transition border-zinc-300 dark:border-zinc-600 text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-300 text-nowrap">
<span class="text-lg font-IconFamily">{'\ued47'}</span>
<span>Upload audio</span>
</div> </div>
{/if} {/if}
</div> </div>
{#if filename} <input type="file" accept="audio/wav,audio/mpeg" class="hidden" bind:this={fileInput} onchange={onFileChange} />
<button
class="flex justify-center items-center m-1 text-lg dark:text-white size-7"
onclick={(e) => { e.stopPropagation(); removeAudio() }}
aria-label="Remove audio"
>&#215;</button>
{/if}
<input type="file" accept="audio/wav" class="hidden" bind:this={fileInput} onchange={onFileChange} />
{#if dragging} {#if dragging}
<div class="absolute inset-0 rounded-lg bg-zinc-200/40 dark:bg-zinc-700/40"></div> <div class="absolute inset-0 rounded-lg bg-zinc-200/40 dark:bg-zinc-700/40"></div>
{/if} {/if}
+19 -3
View File
@@ -1,5 +1,5 @@
import type { Plugin } from "@/plugins/core/types"; import type { Plugin } from "@/plugins/core/types";
import { componentSetting, defineSettings, numberSetting } from "@/plugins/core/settingsHelpers"; import { componentSetting, defineSettings, numberSetting, booleanSetting } from "@/plugins/core/settingsHelpers";
import styles from "./styles.css?inline"; import styles from "./styles.css?inline";
import BackgroundMusicSetting from "./BackgroundMusicSetting.svelte"; import BackgroundMusicSetting from "./BackgroundMusicSetting.svelte";
import localforage from "localforage"; import localforage from "localforage";
@@ -7,7 +7,7 @@ import localforage from "localforage";
const settings = defineSettings({ const settings = defineSettings({
uploader: componentSetting({ uploader: componentSetting({
title: "Background Music", title: "Background Music",
description: "Upload a .wav audio file to play in the background.", description: "Upload a .wav or .mp3 audio file to play in the background.",
component: BackgroundMusicSetting, component: BackgroundMusicSetting,
}), }),
volume: numberSetting({ volume: numberSetting({
@@ -18,6 +18,11 @@ const settings = defineSettings({
max: 1, max: 1,
step: 0.05, step: 0.05,
}), }),
pauseOnHidden: booleanSetting({
title: "Pause when tab hidden",
description: "Pause music when switching to another tab or minimizing the browser",
default: true,
}),
}); });
const store = localforage.createInstance({ const store = localforage.createInstance({
@@ -110,6 +115,14 @@ const backgroundMusicPlugin: Plugin<typeof settings> = {
if (currentAudio) currentAudio.volume = Math.max(0, Math.min(1, vol)); if (currentAudio) currentAudio.volume = Math.max(0, Math.min(1, vol));
}); });
api.settings.onChange("pauseOnHidden" as any, (value: any) => {
const pauseOnHidden = (typeof value === "boolean" ? value : true) as boolean;
// If the setting is disabled and audio is currently paused due to tab being hidden, resume it
if (!pauseOnHidden && currentAudio && currentAudio.paused && document.visibilityState === "hidden") {
currentAudio.play().catch(() => {});
}
});
// Note: Stop button/event removed by user; no stop handling needed // Note: Stop button/event removed by user; no stop handling needed
// Start if we have audio and autoplay is enabled // Start if we have audio and autoplay is enabled
@@ -124,9 +137,12 @@ const backgroundMusicPlugin: Plugin<typeof settings> = {
(window as any).__betterseqta_bg_music_cancel__ = cancel; (window as any).__betterseqta_bg_music_cancel__ = cancel;
tryStart(); tryStart();
// Pause on tab hide, resume on show with a small delay // Pause on tab hide, resume on show with a small delay (if enabled)
const visHandler = () => { const visHandler = () => {
if (!currentAudio) return; if (!currentAudio) return;
const pauseOnHidden = (api.settings as any).pauseOnHidden ?? true;
if (!pauseOnHidden) return;
if (document.visibilityState === "hidden") { if (document.visibilityState === "hidden") {
if (visibilityResumeTimeout !== null) { if (visibilityResumeTimeout !== null) {
clearTimeout(visibilityResumeTimeout); clearTimeout(visibilityResumeTimeout);