|
@@ -21,22 +21,26 @@ a file. The definition file is expected to be a JSON encoded datastructure of th
|
|
|
{
|
|
|
"artist" : <artist>
|
|
|
"title" : <title>
|
|
|
- "path" : <file path>
|
|
|
+ "path" : <file path / url>
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
|
|
|
The web path is the absolute path which may be requested by the streaming
|
|
|
client (e.g. /foo/bar would be http://myserver:1234/foo/bar).
|
|
|
-The file path is a physical file reachable by the server process. The file
|
|
|
-ending determines the content type which is send to the client.
|
|
|
+The path is either a physical file or a web url reachable by the server process.
|
|
|
+The file ending determines the content type which is send to the client.
|
|
|
*/
|
|
|
package playlist
|
|
|
|
|
|
import (
|
|
|
+ "crypto/tls"
|
|
|
"encoding/json"
|
|
|
+ "io"
|
|
|
"io/ioutil"
|
|
|
"math/rand"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
"sync"
|
|
@@ -92,15 +96,21 @@ func NewFilePlaylistFactory(path string) (*FilePlaylistFactory, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- // Strip out comments
|
|
|
-
|
|
|
- pl = stringutil.StripCStyleComments(pl)
|
|
|
-
|
|
|
// Unmarshal json
|
|
|
|
|
|
ret := &FilePlaylistFactory{}
|
|
|
|
|
|
err = json.Unmarshal(pl, &ret.data)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+
|
|
|
+ // Try again and strip out comments
|
|
|
+
|
|
|
+ pl = stringutil.StripCStyleComments(pl)
|
|
|
+
|
|
|
+ err = json.Unmarshal(pl, &ret.data)
|
|
|
+ }
|
|
|
+
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -141,7 +151,7 @@ type FilePlaylist struct {
|
|
|
path string // Path of this playlist
|
|
|
current int // Pointer to the current playing item
|
|
|
data []map[string]string // Playlist items
|
|
|
- file *os.File // Current open file
|
|
|
+ stream io.ReadCloser // Current open stream
|
|
|
finished bool // Flag if this playlist has finished
|
|
|
framePool *sync.Pool // Pool for byte arrays
|
|
|
}
|
|
@@ -202,7 +212,7 @@ func (fp *FilePlaylist) Frame() ([]byte, error) {
|
|
|
return nil, dudeldu.ErrPlaylistEnd
|
|
|
}
|
|
|
|
|
|
- if fp.file == nil {
|
|
|
+ if fp.stream == nil {
|
|
|
|
|
|
// Make sure first file is loaded
|
|
|
|
|
@@ -220,13 +230,13 @@ func (fp *FilePlaylist) Frame() ([]byte, error) {
|
|
|
|
|
|
for n < len(frame) && err == nil {
|
|
|
|
|
|
- nn, err = fp.file.Read(frame[n:])
|
|
|
+ nn, err = fp.stream.Read(frame[n:])
|
|
|
|
|
|
n += nn
|
|
|
|
|
|
// Check if we need to read the next file
|
|
|
|
|
|
- if n < len(frame) {
|
|
|
+ if n < len(frame) || err == io.EOF {
|
|
|
err = fp.nextFile()
|
|
|
}
|
|
|
}
|
|
@@ -261,14 +271,16 @@ func (fp *FilePlaylist) Frame() ([]byte, error) {
|
|
|
nextFile jumps to the next file for the playlist.
|
|
|
*/
|
|
|
func (fp *FilePlaylist) nextFile() error {
|
|
|
+ var err error
|
|
|
+ var stream io.ReadCloser
|
|
|
|
|
|
// Except for the first call advance the current pointer
|
|
|
|
|
|
- if fp.file != nil {
|
|
|
+ if fp.stream != nil {
|
|
|
fp.current++
|
|
|
|
|
|
- fp.file.Close()
|
|
|
- fp.file = nil
|
|
|
+ fp.stream.Close()
|
|
|
+ fp.stream = nil
|
|
|
|
|
|
// Return special error if the end of the playlist has been reached
|
|
|
|
|
@@ -279,11 +291,29 @@ func (fp *FilePlaylist) nextFile() error {
|
|
|
|
|
|
// Check if a file is already open
|
|
|
|
|
|
- if fp.file == nil {
|
|
|
+ if fp.stream == nil {
|
|
|
|
|
|
- // Open a new file
|
|
|
+ item := fp.currentItem()["path"]
|
|
|
+
|
|
|
+ if _, err = url.ParseRequestURI(item); err == nil {
|
|
|
+ var resp *http.Response
|
|
|
+
|
|
|
+ // We got an url - access it without SSL verification
|
|
|
+
|
|
|
+ client := &http.Client{Transport: &http.Transport{
|
|
|
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
|
+ }}
|
|
|
+
|
|
|
+ resp, err = client.Get(item)
|
|
|
+ stream = resp.Body
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ // Open a new file
|
|
|
+
|
|
|
+ stream, err = os.Open(item)
|
|
|
+ }
|
|
|
|
|
|
- f, err := os.Open(fp.currentItem()["path"])
|
|
|
if err != nil {
|
|
|
|
|
|
// Jump to the next file if there is an error
|
|
@@ -293,10 +323,10 @@ func (fp *FilePlaylist) nextFile() error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- fp.file = f
|
|
|
+ fp.stream = stream
|
|
|
}
|
|
|
|
|
|
- return nil
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -320,9 +350,9 @@ Close any open files by this playlist and reset the current pointer. After this
|
|
|
call the playlist can be played again.
|
|
|
*/
|
|
|
func (fp *FilePlaylist) Close() error {
|
|
|
- if fp.file != nil {
|
|
|
- fp.file.Close()
|
|
|
- fp.file = nil
|
|
|
+ if fp.stream != nil {
|
|
|
+ fp.stream.Close()
|
|
|
+ fp.stream = nil
|
|
|
}
|
|
|
fp.current = 0
|
|
|
fp.finished = false
|