|
@@ -34,6 +34,7 @@ The file ending determines the content type which is send to the client.
|
|
|
package playlist
|
|
|
|
|
|
import (
|
|
|
+ "bytes"
|
|
|
"crypto/tls"
|
|
|
"encoding/json"
|
|
|
"io"
|
|
@@ -80,14 +81,15 @@ var FrameSize = dudeldu.FrameSize
|
|
|
FilePlaylistFactory data structure
|
|
|
*/
|
|
|
type FilePlaylistFactory struct {
|
|
|
- data map[string][]map[string]string
|
|
|
+ data map[string][]map[string]string
|
|
|
+ itemPathPrefix string
|
|
|
}
|
|
|
|
|
|
|
|
|
NewFilePlaylistFactory creates a new FilePlaylistFactory from a given definition
|
|
|
file.
|
|
|
*/
|
|
|
-func NewFilePlaylistFactory(path string) (*FilePlaylistFactory, error) {
|
|
|
+func NewFilePlaylistFactory(path string, itemPathPrefix string) (*FilePlaylistFactory, error) {
|
|
|
|
|
|
|
|
|
|
|
@@ -98,7 +100,10 @@ func NewFilePlaylistFactory(path string) (*FilePlaylistFactory, error) {
|
|
|
|
|
|
|
|
|
|
|
|
- ret := &FilePlaylistFactory{}
|
|
|
+ ret := &FilePlaylistFactory{
|
|
|
+ data: nil,
|
|
|
+ itemPathPrefix: itemPathPrefix,
|
|
|
+ }
|
|
|
|
|
|
err = json.Unmarshal(pl, &ret.data)
|
|
|
|
|
@@ -138,7 +143,7 @@ func (fp *FilePlaylistFactory) Playlist(path string, shuffle bool) dudeldu.Playl
|
|
|
data = shuffledData
|
|
|
}
|
|
|
|
|
|
- return &FilePlaylist{path, 0, data, nil, false,
|
|
|
+ return &FilePlaylist{path, fp.itemPathPrefix, 0, data, nil, false,
|
|
|
&sync.Pool{New: func() interface{} { return make([]byte, FrameSize, FrameSize) }}}
|
|
|
}
|
|
|
return nil
|
|
@@ -148,12 +153,13 @@ func (fp *FilePlaylistFactory) Playlist(path string, shuffle bool) dudeldu.Playl
|
|
|
FilePlaylist data structure
|
|
|
*/
|
|
|
type FilePlaylist struct {
|
|
|
- path string
|
|
|
- current int
|
|
|
- data []map[string]string
|
|
|
- stream io.ReadCloser
|
|
|
- finished bool
|
|
|
- framePool *sync.Pool
|
|
|
+ path string
|
|
|
+ pathPrefix string
|
|
|
+ current int
|
|
|
+ data []map[string]string
|
|
|
+ stream io.ReadCloser
|
|
|
+ finished bool
|
|
|
+ framePool *sync.Pool
|
|
|
}
|
|
|
|
|
|
|
|
@@ -231,7 +237,6 @@ func (fp *FilePlaylist) Frame() ([]byte, error) {
|
|
|
for n < len(frame) && err == nil {
|
|
|
|
|
|
nn, err = fp.stream.Read(frame[n:])
|
|
|
-
|
|
|
n += nn
|
|
|
|
|
|
|
|
@@ -293,7 +298,7 @@ func (fp *FilePlaylist) nextFile() error {
|
|
|
|
|
|
if fp.stream == nil {
|
|
|
|
|
|
- item := fp.currentItem()["path"]
|
|
|
+ item := fp.pathPrefix + fp.currentItem()["path"]
|
|
|
|
|
|
if _, err = url.ParseRequestURI(item); err == nil {
|
|
|
var resp *http.Response
|
|
@@ -304,8 +309,11 @@ func (fp *FilePlaylist) nextFile() error {
|
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
|
}}
|
|
|
|
|
|
- resp, err = client.Get(item)
|
|
|
- stream = resp.Body
|
|
|
+ if resp, err = client.Get(item); err == nil {
|
|
|
+ buf := &StreamBuffer{}
|
|
|
+ buf.ReadFrom(resp.Body)
|
|
|
+ stream = buf
|
|
|
+ }
|
|
|
|
|
|
} else {
|
|
|
|
|
@@ -359,3 +367,59 @@ func (fp *FilePlaylist) Close() error {
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+StreamBuffer is a buffer which implements io.ReadCloser and can be used to stream
|
|
|
+one stream into another. The buffer detects a potential underflow and waits
|
|
|
+until enough bytes were read from the source stream.
|
|
|
+*/
|
|
|
+type StreamBuffer struct {
|
|
|
+ bytes.Buffer
|
|
|
+ readFromOngoing bool
|
|
|
+}
|
|
|
+
|
|
|
+func (b *StreamBuffer) Read(p []byte) (int, error) {
|
|
|
+
|
|
|
+ if b.readFromOngoing && b.Buffer.Len() < len(p) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ time.Sleep(10 * time.Millisecond)
|
|
|
+ return b.Read(p)
|
|
|
+ }
|
|
|
+
|
|
|
+ n, err := b.Buffer.Read(p)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if err == nil {
|
|
|
+ if _, err = b.ReadByte(); err == nil {
|
|
|
+ b.UnreadByte()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ReadFrom reads the source stream into the buffer.
|
|
|
+*/
|
|
|
+func (b *StreamBuffer) ReadFrom(r io.Reader) (int64, error) {
|
|
|
+ b.readFromOngoing = true
|
|
|
+ go func() {
|
|
|
+ b.Buffer.ReadFrom(r)
|
|
|
+ b.readFromOngoing = false
|
|
|
+ }()
|
|
|
+ return 0, nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+Close does nothing but must be there to implement io.ReadCloser.
|
|
|
+*/
|
|
|
+func (b *StreamBuffer) Close() error {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|