radio styling changes (add/fix mobile responsivity); WIP, player still does not function on iOS
This commit is contained in:
@@ -16,7 +16,12 @@ const STATIONS = {
|
||||
pop: { label: "Pop", streamPath: "/pop.ogg" },
|
||||
};
|
||||
|
||||
// Global interval tracking (required for Astro + client:only)
|
||||
// Detect iOS user agent (can refine if needed)
|
||||
const isIOS = (() => {
|
||||
if (typeof window === "undefined") return false;
|
||||
return /iP(ad|hone|od)/.test(navigator.userAgent);
|
||||
})();
|
||||
|
||||
let activeInterval = null;
|
||||
let currentStationForInterval = null;
|
||||
|
||||
@@ -50,13 +55,19 @@ export function Player() {
|
||||
|
||||
const progress = duration > 0 ? (elapsed / duration) * 100 : 0;
|
||||
|
||||
// Create Howl instance on activeStation change
|
||||
// UseEffect: create Howl on station change (as before)
|
||||
useEffect(() => {
|
||||
if (soundRef.current) {
|
||||
soundRef.current.unload();
|
||||
soundRef.current = null;
|
||||
}
|
||||
|
||||
// On iOS we defer creation until user plays, so skip creating Howl here
|
||||
if (isIOS) {
|
||||
setIsPlaying(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const streamUrl = "https://stream.codey.lol" + STATIONS[activeStation].streamPath;
|
||||
|
||||
const howl = new Howl({
|
||||
@@ -92,47 +103,80 @@ export function Player() {
|
||||
};
|
||||
}, [activeStation]);
|
||||
|
||||
const togglePlayback = () => {
|
||||
if (isPlaying) {
|
||||
if (soundRef.current) {
|
||||
soundRef.current.pause();
|
||||
}
|
||||
setIsPlaying(false);
|
||||
} else {
|
||||
// If a previous Howl exists, unload it
|
||||
if (soundRef.current) {
|
||||
soundRef.current.stop();
|
||||
soundRef.current.unload();
|
||||
// Toggle playback handler
|
||||
const togglePlayback = () => {
|
||||
if (isPlaying) {
|
||||
if (soundRef.current) {
|
||||
soundRef.current.pause();
|
||||
}
|
||||
setIsPlaying(false);
|
||||
} else {
|
||||
if (isIOS) {
|
||||
// On iOS, defer creation until user explicitly plays
|
||||
if (soundRef.current) {
|
||||
soundRef.current.stop();
|
||||
soundRef.current.unload();
|
||||
soundRef.current = null;
|
||||
}
|
||||
|
||||
const streamUrl =
|
||||
"https://stream.codey.lol" +
|
||||
STATIONS[activeStation].streamPath +
|
||||
`?t=${Date.now()}`; // Cache-busting param
|
||||
|
||||
const newHowl = new Howl({
|
||||
src: [streamUrl],
|
||||
html5: true,
|
||||
onend: () => newHowl.play(),
|
||||
onplay: () => {
|
||||
setIsPlaying(true);
|
||||
},
|
||||
onpause: () => setIsPlaying(false),
|
||||
onstop: () => setIsPlaying(false),
|
||||
onloaderror: (_, err) => console.error("Load error", err),
|
||||
onplayerror: (_, err) => {
|
||||
console.error("Play error", err);
|
||||
setTimeout(() => newHowl.play(), 1000);
|
||||
},
|
||||
});
|
||||
|
||||
soundRef.current = newHowl;
|
||||
newHowl.play();
|
||||
} else {
|
||||
// Desktop browsers: current logic
|
||||
if (soundRef.current) {
|
||||
soundRef.current.stop();
|
||||
soundRef.current.unload();
|
||||
}
|
||||
|
||||
const streamUrl =
|
||||
"https://stream.codey.lol" +
|
||||
STATIONS[activeStation].streamPath +
|
||||
`?t=${Date.now()}`; // Cache-busting param
|
||||
|
||||
const newHowl = new Howl({
|
||||
src: [streamUrl],
|
||||
html5: true,
|
||||
onend: () => newHowl.play(),
|
||||
onplay: () => {
|
||||
setIsPlaying(true);
|
||||
},
|
||||
onpause: () => setIsPlaying(false),
|
||||
onstop: () => setIsPlaying(false),
|
||||
onloaderror: (_, err) => console.error("Load error", err),
|
||||
onplayerror: (_, err) => {
|
||||
console.error("Play error", err);
|
||||
setTimeout(() => newHowl.play(), 1000);
|
||||
},
|
||||
});
|
||||
|
||||
soundRef.current = newHowl;
|
||||
newHowl.play();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const streamUrl =
|
||||
"https://stream.codey.lol" +
|
||||
STATIONS[activeStation].streamPath +
|
||||
`?t=${Date.now()}`; // Cache-busting param
|
||||
|
||||
const newHowl = new Howl({
|
||||
src: [streamUrl],
|
||||
html5: true,
|
||||
onend: () => newHowl.play(),
|
||||
onplay: () => {
|
||||
setIsPlaying(true);
|
||||
},
|
||||
onpause: () => setIsPlaying(false),
|
||||
onstop: () => setIsPlaying(false),
|
||||
onloaderror: (_, err) => console.error("Load error", err),
|
||||
onplayerror: (_, err) => {
|
||||
console.error("Play error", err);
|
||||
setTimeout(() => newHowl.play(), 1000);
|
||||
},
|
||||
});
|
||||
|
||||
soundRef.current = newHowl;
|
||||
newHowl.play();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Metadata fetcher: global-safe
|
||||
// Metadata fetcher (unchanged)
|
||||
useEffect(() => {
|
||||
clearGlobalMetadataInterval();
|
||||
|
||||
@@ -145,7 +189,6 @@ const togglePlayback = () => {
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
// Ignore stale interval calls
|
||||
if (currentStationForInterval !== activeStation) return;
|
||||
|
||||
if (data.artist === "N/A" && data.song === "N/A") {
|
||||
@@ -227,12 +270,8 @@ const togglePlayback = () => {
|
||||
<div id="length" style={{ width: `${progress}%` }}></div>
|
||||
</div>
|
||||
<div className="music-control">
|
||||
<div className="music-control__play" id="play">
|
||||
{!isPlaying ? (
|
||||
<Play onClick={togglePlayback} />
|
||||
) : (
|
||||
<Pause onClick={togglePlayback} />
|
||||
)}
|
||||
<div className="music-control__play" id="play" onClick={togglePlayback} role="button" tabIndex={0} aria-pressed={isPlaying}>
|
||||
{!isPlaying ? <Play /> : <Pause />}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
Reference in New Issue
Block a user