various changes
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import Hls from "hls.js";
|
||||
import React, { useState, useEffect, useRef, Suspense, lazy } from "react";
|
||||
import { metaData } from "../config";
|
||||
import Play from "@mui/icons-material/PlayArrow";
|
||||
import Pause from "@mui/icons-material/Pause";
|
||||
import "@styles/player.css";
|
||||
|
||||
const API_URL = "https://api.codey.lol";
|
||||
import { API_URL } from "@/config";
|
||||
|
||||
const STATIONS = {
|
||||
main: { label: "Main" },
|
||||
rock: { label: "Rock" },
|
||||
@@ -15,7 +15,7 @@ const STATIONS = {
|
||||
pop: { label: "Pop" },
|
||||
};
|
||||
|
||||
export function Player() {
|
||||
export default function Player() {
|
||||
const [activeStation, setActiveStation] = useState("main");
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [trackTitle, setTrackTitle] = useState("");
|
||||
@@ -40,60 +40,72 @@ export function Player() {
|
||||
return `${mins}:${secs}`;
|
||||
};
|
||||
|
||||
// Set page title based on current track and station
|
||||
const setPageTitle = (artist, song) => {
|
||||
document.title = `${metaData.title} - Radio - ${artist} - ${song} [${activeStation}]`;
|
||||
};
|
||||
|
||||
// Initialize or switch HLS stream
|
||||
const initializeStream = (station) => {
|
||||
const audio = audioElement.current;
|
||||
if (!audio) return;
|
||||
const streamUrl = `https://stream.codey.lol/hls/${station}/${station}.m3u8`;
|
||||
import('hls.js').then(({ default: Hls }) => {
|
||||
const audio = audioElement.current;
|
||||
if (!audio) return;
|
||||
const streamUrl = `https://stream.codey.lol/hls/${station}/${station}.m3u8`;
|
||||
|
||||
// Clean up previous HLS
|
||||
if (hlsInstance.current) {
|
||||
hlsInstance.current.destroy();
|
||||
hlsInstance.current = null;
|
||||
}
|
||||
audio.pause();
|
||||
audio.removeAttribute("src");
|
||||
audio.load();
|
||||
|
||||
// Handle audio load errors
|
||||
audio.onerror = () => {
|
||||
setTrackTitle("Offline");
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
if (audio.canPlayType("application/vnd.apple.mpegurl")) {
|
||||
audio.src = streamUrl;
|
||||
audio.load();
|
||||
audio.play().then(() => setIsPlaying(true)).catch(() => {
|
||||
setTrackTitle("Offline");
|
||||
setIsPlaying(false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Hls.isSupported()) {
|
||||
console.error("HLS not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
const hls = new Hls({ lowLatencyMode: true, abrEnabled: false });
|
||||
hlsInstance.current = hls;
|
||||
hls.attachMedia(audio);
|
||||
hls.on(Hls.Events.MEDIA_ATTACHED, () => hls.loadSource(streamUrl));
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
audio.play().then(() => setIsPlaying(true)).catch(() => {
|
||||
setTrackTitle("Offline");
|
||||
setIsPlaying(false);
|
||||
});
|
||||
});
|
||||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
console.warn("HLS error:", data);
|
||||
if (data.fatal) {
|
||||
hls.destroy();
|
||||
// Clean up previous HLS
|
||||
if (hlsInstance.current) {
|
||||
hlsInstance.current.destroy();
|
||||
hlsInstance.current = null;
|
||||
setTrackTitle("Offline");
|
||||
setIsPlaying(false);
|
||||
}
|
||||
audio.pause();
|
||||
audio.removeAttribute("src");
|
||||
audio.load();
|
||||
|
||||
// Handle audio load errors
|
||||
audio.onerror = () => {
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
if (audio.canPlayType("application/vnd.apple.mpegurl")) {
|
||||
audio.src = streamUrl;
|
||||
audio.load();
|
||||
audio.play().then(() => setIsPlaying(true)).catch(() => {
|
||||
setTrackTitle("Offline");
|
||||
setIsPlaying(false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Hls.isSupported()) {
|
||||
console.error("HLS not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
const hls = new Hls({
|
||||
lowLatencyMode: true,
|
||||
abrEnabled: false,
|
||||
liveSyncDuration: 3, // seconds behind live edge target
|
||||
liveMaxLatencyDuration: 10, // max allowed latency before catchup
|
||||
liveCatchUpPlaybackRate: 1.05, // playback speed when catching up
|
||||
});
|
||||
|
||||
hlsInstance.current = hls;
|
||||
hls.attachMedia(audio);
|
||||
hls.on(Hls.Events.MEDIA_ATTACHED, () => hls.loadSource(streamUrl));
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
audio.play().then(() => setIsPlaying(true)).catch(() => {
|
||||
setIsPlaying(false);
|
||||
});
|
||||
});
|
||||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
console.warn("HLS error:", data);
|
||||
if (data.fatal) {
|
||||
hls.destroy();
|
||||
hlsInstance.current = null;
|
||||
setTrackTitle("Offline");
|
||||
setIsPlaying(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -192,6 +204,7 @@ export function Player() {
|
||||
|
||||
setLyrics([]);
|
||||
setCurrentLyricIndex(0);
|
||||
setPageTitle(trackData.artist, trackData.song);
|
||||
|
||||
// Fetch lyrics as before
|
||||
const lyricsResponse = await fetch(`${API_URL}/lyric/search`, {
|
||||
@@ -231,6 +244,16 @@ export function Player() {
|
||||
return () => clearInterval(metadataInterval);
|
||||
}, [activeStation]);
|
||||
|
||||
const progress = (elapsedTime / trackDuration) * 100;
|
||||
const remaining = trackDuration - elapsedTime;
|
||||
|
||||
const progressColorClass =
|
||||
progress >= 90
|
||||
? "bg-red-500 dark:bg-red-400"
|
||||
: progress >= 75 || remaining <= 20
|
||||
? "bg-yellow-400 dark:bg-yellow-300"
|
||||
: "bg-blue-500 dark:bg-blue-400";
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -267,12 +290,13 @@ export function Player() {
|
||||
<p className="music-time__current">{formatTime(elapsedTime)}</p>
|
||||
<p className="music-time__last">{formatTime(trackDuration - elapsedTime)}</p>
|
||||
</div>
|
||||
<div className="progress-bar-container w-full h-2 rounded bg-neutral-300 overflow-hidden">
|
||||
<div className="progress-bar-container w-full h-2 rounded bg-neutral-300 dark:bg-neutral-700 overflow-hidden">
|
||||
<div
|
||||
className="progress-bar-fill h-full transition-all duration-200 bg-blue-500"
|
||||
style={{ width: `${(elapsedTime / trackDuration) * 100}%` }}
|
||||
/>
|
||||
className={`h-full transition-all duration-200 ${progressColorClass}`}
|
||||
style={{ width: `${progress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div className={`lrc-text ${lyrics.length === 0 ? 'empty' : ''}`}>
|
||||
{lyrics.map((lyricObj, index) => (
|
||||
<p
|
||||
|
Reference in New Issue
Block a user