79706410

Date: 2025-07-18 15:28:22
Score: 0.5
Natty:
Report link

You can do client side, on the condition that you can fetch the Icecast stream.

To make client-side playback and ICY metadata extraction work via fetch() in the browser, CORS (Cross-Origin Resource Sharing) requirements must be properly met by the radio stream server.

I wrote the @music-metadata/icy module for this occasion. Credits to Brad who encourage me to contribute to StackOverflow, while others gave me much reason to run away.

const STREAM_URL = 'https://audio-edge-kef8b.ams.s.radiomast.io/ref-128k-mp3-stereo';

const trackDisplay = document.getElementById('track');
const audioElement = document.getElementById('player');

const mediaSource = new MediaSource();
audioElement.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', async () => {
  const sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');

  try {
    // Dynamically import the ESM-only module
    const { parseIcyResponse } = await import('https://cdn.jsdelivr.net/npm/@music-metadata/[email protected]/+esm');

    const response = await fetch(STREAM_URL, {
      headers: { 'Icy-MetaData': '1' }
    });

    const audioStream = parseIcyResponse(response, metadata => {
      for (const [key, value] of metadata.entries()) {
        console.log(`Rx ICY Metadata: ${key}: ${value}`);
      }
      const title = metadata.get('StreamTitle');
      if (title) {
        trackDisplay.textContent = title;
      }
    });

    const reader = audioStream.getReader();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      if (value && !sourceBuffer.updating) {
        sourceBuffer.appendBuffer(value);
      } else {
        await new Promise(resolve => {
          sourceBuffer.addEventListener('updateend', resolve, { once: true });
        });
        sourceBuffer.appendBuffer(value);
      }
    }

    mediaSource.endOfStream();
  } catch (err) {
    console.error('Error streaming audio:', err.message);
    trackDisplay.textContent = 'Failed to load stream';
  }
});
<html lang="en">
<head>
  <title>ICY Stream Player</title>
  <style>
    body { font-family: sans-serif; text-align: center; margin-top: 2em; }
    audio { width: 100%; max-width: 500px; margin-top: 1em; }
    #track { font-weight: bold; margin-top: 1em; color: red; font-style: italic}
  </style>
</head>
<body>
  <h2>ICY Stream Player</h2>
  <div>Now playing: <span id="track">...</span></div>
  <audio id="player" controls autoplay></audio>
</body>
</html>

Reasons:
  • Blacklisted phrase (1): StackOverflow
  • Contains signature (1):
  • Long answer (-1):
  • Has code block (-0.5):
Posted by: Borewit