aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.go59
1 files changed, 51 insertions, 8 deletions
diff --git a/main.go b/main.go
index 592a35d..e5da2ef 100644
--- a/main.go
+++ b/main.go
@@ -23,7 +23,8 @@ import (
const (
targetURI = "http://as-hls-%s-live.akamaized.net/pool_904/live/%s/" +
"%s/%s.isml/%s-audio%%3d%s.norewind.m3u8"
- metaURI = "https://rms.api.bbc.co.uk/v2/services/%s/segments/latest"
+ networksURI = "https://rms.api.bbc.co.uk/radio/networks.json"
+ metaURI = "https://rms.api.bbc.co.uk/v2/services/%s/segments/latest"
)
type meta struct {
@@ -31,6 +32,42 @@ type meta struct {
timeout uint // timeout for the next poll in ms
}
+// getServiceTitle returns a human-friendly identifier for a BBC service ID.
+func getServiceTitle(name string) (string, error) {
+ resp, err := http.Get(networksURI)
+ if resp != nil {
+ defer resp.Body.Close()
+ }
+ if err != nil {
+ return name, err
+ }
+ b, err := ioutil.ReadAll(resp.Body)
+
+ var v struct {
+ Results []struct {
+ Services []struct {
+ ID string `json:"id"`
+ Title string `json:"title"`
+ } `json:"services"`
+ } `json:"results"`
+ }
+ err = json.Unmarshal(b, &v)
+ if err != nil {
+ return name, errors.New("invalid metadata response")
+ }
+
+ for _, network := range v.Results {
+ for _, service := range network.Services {
+ if service.ID == name {
+ return service.Title, nil
+ }
+ }
+ }
+ return name, errors.New("unknown service")
+}
+
+var errNoSong = errors.New("no song is playing")
+
// getMeta retrieves and decodes metadata info from an independent webservice.
func getMeta(name string) (*meta, error) {
resp, err := http.Get(fmt.Sprintf(metaURI, name))
@@ -41,6 +78,9 @@ func getMeta(name string) (*meta, error) {
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
+ if os.Getenv("DEBUG") != "" {
+ log.Println(string(b))
+ }
// TODO: update more completely for the new OpenAPI
// - `broadcasts/poll/bbc_radio_one` looks almost useful
@@ -63,7 +103,7 @@ func getMeta(name string) (*meta, error) {
return nil, errors.New("invalid metadata response")
}
if len(v.Data) == 0 || !v.Data[0].Offset.NowPlaying {
- return nil, errors.New("no song is playing")
+ return nil, errNoSong
}
titles := v.Data[0].Titles
@@ -124,9 +164,10 @@ func metaProc(ctx context.Context, name string, out chan<- string) {
var interval time.Duration
for {
meta, err := getMeta(name)
- if err != nil {
- current = name + " - " + err.Error()
- interval = maxInterval
+ if err == errNoSong {
+ interval, current = maxInterval, ""
+ } else if err != nil {
+ interval, current = maxInterval, err.Error()
} else {
current = meta.title
interval = time.Duration(meta.timeout) * time.Millisecond
@@ -263,11 +304,10 @@ func proxy(w http.ResponseWriter, req *http.Request) {
}
defer conn.Close()
- // TODO: Retrieve some general information from somewhere?
- // There's nothing interesting in the playlist files.
+ serviceTitle, _ := getServiceTitle(name)
fmt.Fprintf(bufrw, "ICY 200 OK\r\n")
- fmt.Fprintf(bufrw, "icy-name:%s\r\n", name)
+ fmt.Fprintf(bufrw, "icy-name:%s\r\n", serviceTitle)
// BBC marks this as a video type, maybe just force audio/mpeg.
fmt.Fprintf(bufrw, "content-type:%s\r\n", resp.Header["Content-Type"][0])
fmt.Fprintf(bufrw, "icy-pub:%d\r\n", 0)
@@ -300,6 +340,9 @@ func proxy(w http.ResponseWriter, req *http.Request) {
for {
select {
case title := <-metaChan:
+ if title == "" {
+ title = serviceTitle
+ }
queuedMetaUpdate = []byte(fmt.Sprintf("StreamTitle='%s'",
strings.Replace(title, "'", "’", -1)))
case chunk, ok := <-chunkChan: