Spaces:
Sleeping
Sleeping
File size: 3,232 Bytes
ce63e50 5bdead2 92bb2e0 ce63e50 5bdead2 ce63e50 5bdead2 92bb2e0 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 92bb2e0 5bdead2 92bb2e0 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 ce63e50 5bdead2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import React, { useEffect, useMemo, useState } from 'react';
import ReactPlayer from 'react-player';
import { getThumb, safeTitle } from './utils.js';
import { useToasts } from './Toasts.jsx';
export default function Player({ socket, roomId, state, isHost }) {
const { push } = useToasts();
const [useProxy, setUseProxy] = useState(false);
const mediaUrl = useMemo(() => {
if (!state?.track?.url) return '';
return useProxy
? `/api/proxy?url=${encodeURIComponent(state.track.url)}`
: state.track.url;
}, [state?.track?.url, useProxy]);
const title = state?.track ? safeTitle(state.track) : 'No track selected';
const thumb = state?.track?.thumb || getThumb(state?.track?.meta);
// Auto-advance when ended (host only)
const handleEnded = () => {
if (isHost) socket.emit('ended', { roomId });
};
const handleError = (e) => {
console.warn('ReactPlayer error', e);
if (!useProxy) {
setUseProxy(true);
push('CORS blocked direct URL, retrying via proxy…', 'warn', 3000);
} else {
push('Playback failed (even via proxy)', 'bad', 4000);
}
};
return (
<div style={{ position: 'relative' }}>
<div
className="hero-thumb"
style={{ backgroundImage: thumb ? `url("${thumb}")` : undefined }}
aria-hidden
/>
<div className="ambient"></div>
<div className="now-playing" style={{ marginBottom: 10 }}>
<div
className="thumb"
style={{
width: 72,
height: 72,
backgroundImage: thumb ? `url("${thumb}")` : undefined
}}
/>
<div style={{ minWidth: 0, flex: 1 }}>
<div
style={{
fontWeight: 700,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
>
{title}
</div>
<div
style={{
fontSize: 12,
color: 'var(--muted)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
>
{state?.track?.meta?.artists?.join?.(', ') ||
state?.track?.meta?.artist ||
state?.track?.meta?.album ||
state?.track?.kind?.toUpperCase()}
</div>
</div>
{!isHost && <div className="tag">Listener</div>}
</div>
{state?.track?.url ? (
<ReactPlayer
url={mediaUrl}
playing={state.isPlaying}
controls={isHost}
onEnded={handleEnded}
onError={handleError}
width="100%"
height={state.track.kind === 'video' ? '56vh' : '50px'}
config={{
file: {
attributes: {
crossOrigin: 'anonymous'
}
}
}}
/>
) : (
<div style={{ color: 'var(--muted)', padding: '12px 0' }}>
No track selected
</div>
)}
{useProxy && (
<div style={{ marginTop: 8, fontSize: 12, color: 'var(--muted)' }}>
Using proxy due to CORS on the original media URL.
</div>
)}
</div>
);
}
|