Initial release v1.0.0

This commit is contained in:
Kevin O'Neill
2025-12-25 18:58:06 -06:00
commit 021aec7a63
439 changed files with 116588 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
import { useState, useCallback, useEffect, useRef } from "react";
import { toast } from "sonner";
import { howlerEngine } from "@/lib/howler-engine";
export function usePreviewPlayer() {
const [currentPreview, setCurrentPreview] = useState<string | null>(null);
const [previewAudios, setPreviewAudios] = useState<
Map<string, HTMLAudioElement>
>(new Map());
const mainPlayerWasPausedRef = useRef(false);
// Cleanup audio on unmount
useEffect(() => {
return () => {
previewAudios.forEach((audio) => {
audio.pause();
audio.src = "";
});
// Resume main player if needed
if (mainPlayerWasPausedRef.current) {
howlerEngine.play();
mainPlayerWasPausedRef.current = false;
}
};
}, [previewAudios]);
const handleTogglePreview = useCallback(
(albumId: string, previewUrl: string) => {
if (!previewUrl) {
toast.error("No preview available for this album");
return;
}
// Stop currently playing preview if any
if (currentPreview && currentPreview !== albumId) {
const audio = previewAudios.get(currentPreview);
if (audio) {
audio.pause();
audio.currentTime = 0;
}
}
// Toggle the clicked preview
if (currentPreview === albumId) {
const audio = previewAudios.get(albumId);
if (audio) {
audio.pause();
audio.currentTime = 0;
}
setCurrentPreview(null);
// Resume main player if it was playing before
if (mainPlayerWasPausedRef.current) {
howlerEngine.play();
mainPlayerWasPausedRef.current = false;
}
} else {
// Pause the main player if it's playing
if (howlerEngine.isPlaying()) {
howlerEngine.pause();
mainPlayerWasPausedRef.current = true;
}
let audio = previewAudios.get(albumId);
if (!audio) {
audio = new Audio(previewUrl);
audio.onended = () => {
setCurrentPreview(null);
// Resume main player if it was playing before
if (mainPlayerWasPausedRef.current) {
howlerEngine.play();
mainPlayerWasPausedRef.current = false;
}
};
audio.onerror = () => {
toast.error("Failed to load preview");
setCurrentPreview(null);
};
const newMap = new Map(previewAudios);
newMap.set(albumId, audio);
setPreviewAudios(newMap);
}
audio
.play()
.then(() => {
setCurrentPreview(albumId);
})
.catch((error) => {
toast.error("Failed to play preview: " + error.message);
});
}
},
[currentPreview, previewAudios]
);
return {
currentPreview,
handleTogglePreview,
};
}