aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE3
-rw-r--r--main.go (renamed from bbc-on-ice.go)54
2 files changed, 28 insertions, 29 deletions
diff --git a/LICENSE b/LICENSE
index 3bc6282..7678a10 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,4 @@
-Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com>
-All rights reserved.
+Copyright (c) 2016 - 2017, Přemysl Janouch <p.janouch@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/bbc-on-ice.go b/main.go
index 57f5539..efd0978 100644
--- a/bbc-on-ice.go
+++ b/main.go
@@ -26,11 +26,13 @@ type meta struct {
func getMeta(name string) (*meta, error) {
const metaBaseURI = "http://polling.bbc.co.uk/radio/nhppolling/"
resp, err := http.Get(metaBaseURI + name)
+ if resp != nil {
+ defer resp.Body.Close()
+ }
if err != nil {
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
- resp.Body.Close()
if len(b) < 2 {
// There needs to be an enclosing () pair
return nil, errors.New("invalid metadata response")
@@ -38,19 +40,19 @@ func getMeta(name string) (*meta, error) {
// TODO: also retrieve richtracks/is_now_playing, see example file
type broadcast struct {
- Title string `json:"title"` // Title of the broadcast
- Percentage int `json:"percentage"` // How far we're in
+ Title string // Title of the broadcast
+ Percentage int // How far we're in
}
var v struct {
Packages struct {
OnAir struct {
- Broadcasts []broadcast `json:"broadcasts"`
- BroadcastNowIndex uint `json:"broadcastNowIndex"`
+ Broadcasts []broadcast
+ BroadcastNowIndex uint
} `json:"on-air"`
- } `json:"packages"`
+ }
Timeouts struct {
PollingTimeout uint `json:"polling_timeout"`
- } `json:"timeouts"`
+ }
}
err = json.Unmarshal(b[1:len(b)-1], &v)
if err != nil {
@@ -69,11 +71,13 @@ func getMeta(name string) (*meta, error) {
// Resolve an M3U8 playlist to the first link that seems to be playable
func resolveM3U8(target string) (out []string, err error) {
resp, err := http.Get(target)
+ if resp != nil {
+ defer resp.Body.Close()
+ }
if err != nil {
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
- resp.Body.Close()
if !utf8.Valid(b) {
return nil, errors.New("invalid UTF-8")
}
@@ -97,6 +101,8 @@ func resolveM3U8(target string) (out []string, err error) {
}
func metaProc(ctx context.Context, name string, out chan<- string) {
+ defer close(out)
+
var current, last string
var interval time.Duration
for {
@@ -108,10 +114,14 @@ func metaProc(ctx context.Context, name string, out chan<- string) {
current = meta.title
interval = time.Duration(meta.timeout)
}
- // TODO: select on the send? Can't close it in the main proc.
- // Also see https://blog.golang.org/pipelines
if current != last {
- out <- current
+ // TODO: see https://blog.golang.org/pipelines
+ // find out if we can do this better
+ select {
+ case out <- current:
+ case <-ctx.Done():
+ return
+ }
last = current
}
@@ -211,29 +221,19 @@ func proxy(w http.ResponseWriter, req *http.Request) {
}()
var queuedMeta []byte
- makeMetaChunk := func() []byte {
- meta := queuedMeta
- queuedMeta = nil
- for len(meta)%16 != 0 {
- meta = append(meta, 0)
- }
- if len(meta) > 16*255 {
- meta = meta[:16*255]
- }
- chunk := []byte{byte(len(meta) / 16)}
- return append(chunk, meta...)
- }
-
for {
select {
case title := <-metaChan:
queuedMeta = []byte(fmt.Sprintf("StreamTitle='%s'", title))
- case chunk, connected := <-chunkChan:
- if !connected {
+ case chunk, ok := <-chunkChan:
+ if !ok {
return
}
if wantMeta {
- chunk = append(chunk, makeMetaChunk()...)
+ var meta [1 + 16*255]byte
+ meta[0] = byte((copy(meta[1:], queuedMeta) + 15) / 16)
+ chunk = append(chunk, meta[:1+int(meta[0])*16]...)
+ queuedMeta = nil
}
if _, err := bufrw.Write(chunk); err != nil {
return