Skip to content

Instantly share code, notes, and snippets.

@jucrouzet
Last active March 4, 2024 15:53
Show Gist options
  • Save jucrouzet/3e59877c0b4352966e6220034f2b84ac to your computer and use it in GitHub Desktop.
Save jucrouzet/3e59877c0b4352966e6220034f2b84ac to your computer and use it in GitHub Desktop.
Extract an Icecast stream title (current song) with go (golang)
import (
"bufio"
"bytes"
"fmt"
"net/http"
"strconv"
)
// GetStreamTitle get the current song/show in an Icecast stream
func (r *Radio) GetStreamTitle(streamUrl string) (string, error) {
m, err := r.getStreamMetas(streamUrl)
if err != nil {
return "", err
}
// Should be at least "StreamTitle=' '"
if len(m) < 15 {
return "", nil
}
// Split meta by ';', trim it and search for StreamTitle
for _, m := range bytes.Split(m, []byte(";")) {
m = bytes.Trim(m, " \t")
if bytes.Compare(m[0:13], []byte("StreamTitle='")) != 0 {
continue
}
return string(m[13 : len(m)-1]), nil
}
return "", nil
}
// get stream metadatas
func (r *Radio) getStreamMetas(streamUrl string) ([]byte, error) {
client := &http.Client{}
req, _ := http.NewRequest("GET", streamUrl, nil)
req.Header.Set("Icy-MetaData", "1")
resp, err := client.Do(req)
if err != nil {
return nil, err
}
// We sent "Icy-MetaData", we should have a "icy-metaint" in return
ih := resp.Header.Get("icy-metaint")
if ih == "" {
return nil, fmt.Errorf("no metadata")
}
// "icy-metaint" is how often (in bytes) should we receive the meta
ib, err := strconv.Atoi(ih)
if err != nil {
return nil, err
}
reader := bufio.NewReader(resp.Body)
// skip the first mp3 frame
c, err := reader.Discard(ib)
if err != nil {
return nil, err
}
// If we didn't received ib bytes, the stream is ended
if c != ib {
return nil, fmt.Errorf("stream ended prematurally")
}
// get the size byte, that is the metadata length in bytes / 16
sb, err := reader.ReadByte()
if err != nil {
return nil, err
}
ms := int(sb * 16)
// read the ms first bytes it will contain metadata
m, err := reader.Peek(ms)
if err != nil {
return nil, err
}
return m, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment