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>
  );
}