Cleanup of body response, add host to config, rename entries
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
b1a290e7d0
commit
853211cec8
|
@ -20,6 +20,10 @@ func getQueueEntryFromBody(body []byte) *QueueTrackEntry {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
err = json.Unmarshal(body, &entry.Metadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var val interface{}
|
var val interface{}
|
||||||
var strVal string
|
var strVal string
|
||||||
|
@ -29,26 +33,6 @@ func getQueueEntryFromBody(body []byte) *QueueTrackEntry {
|
||||||
entry.Path = strVal
|
entry.Path = strVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if val, ok = entry.original["title"]; ok {
|
|
||||||
if strVal, ok = val.(string); ok {
|
|
||||||
entry.Metadata.Title = strVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if val, ok = entry.original["album"]; ok {
|
|
||||||
if strVal, ok = val.(string); ok {
|
|
||||||
entry.Metadata.Album = strVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if val, ok = entry.original["artist"]; ok {
|
|
||||||
if strVal, ok = val.(string); ok {
|
|
||||||
entry.Metadata.Artist = strVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if val, ok = entry.original["art"]; ok {
|
|
||||||
if strVal, ok = val.(string); ok {
|
|
||||||
entry.Metadata.Art = strVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(entry.Path) > 0 {
|
if len(entry.Path) > 0 {
|
||||||
return entry
|
return entry
|
||||||
|
@ -89,6 +73,7 @@ func main() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -109,10 +94,13 @@ func main() {
|
||||||
sendNowRandom := func(nr *QueueTrackEntry) {
|
sendNowRandom := func(nr *QueueTrackEntry) {
|
||||||
if config.Queue.NowRandom != "" {
|
if config.Queue.NowRandom != "" {
|
||||||
jsonData, _ := json.Marshal(nr.original)
|
jsonData, _ := json.Marshal(nr.original)
|
||||||
_, err := http.DefaultClient.Post(config.Queue.NowRandom, "application/json; charset=utf-8", bytes.NewReader(jsonData))
|
response, err := http.DefaultClient.Post(config.Queue.NowRandom, "application/json; charset=utf-8", bytes.NewReader(jsonData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
|
if response != nil {
|
||||||
|
defer response.Body.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,10 +127,13 @@ func main() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for np := range queue.NowPlaying {
|
for np := range queue.NowPlaying {
|
||||||
jsonData, _ := json.Marshal(np.original)
|
jsonData, _ := json.Marshal(np.original)
|
||||||
_, err := http.DefaultClient.Post(config.Queue.NowPlaying, "application/json; charset=utf-8", bytes.NewReader(jsonData))
|
response, err := http.DefaultClient.Post(config.Queue.NowPlaying, "application/json; charset=utf-8", bytes.NewReader(jsonData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
|
if response != nil {
|
||||||
|
response.Body.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -151,7 +142,7 @@ func main() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
server := http.Server{
|
server := http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", config.Api.Port),
|
Addr: fmt.Sprintf("%s:%d", config.Api.Host, config.Api.Port),
|
||||||
Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
writer.Header().Set("Server", "MeteorLight/api")
|
writer.Header().Set("Server", "MeteorLight/api")
|
||||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
@ -162,16 +153,26 @@ func main() {
|
||||||
case "listeners":
|
case "listeners":
|
||||||
jsonData, _ := json.Marshal(queue.GetListeners())
|
jsonData, _ := json.Marshal(queue.GetListeners())
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
|
||||||
|
return
|
||||||
case "np":
|
case "np":
|
||||||
if e := queue.GetNowPlaying(); e != nil {
|
if e := queue.GetNowPlaying(); e != nil {
|
||||||
jsonData, _ := json.Marshal(e.original)
|
jsonData, _ := json.Marshal(e.original)
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
} else {
|
||||||
|
writer.Write([]byte{'{', '}'})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
case "random":
|
case "random":
|
||||||
if nr != nil {
|
if nr != nil {
|
||||||
jsonData, _ := json.Marshal(nr.original)
|
jsonData, _ := json.Marshal(nr.original)
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
} else {
|
||||||
|
writer.Write([]byte{'{', '}'})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
case "queue":
|
case "queue":
|
||||||
if len(pathSegments) == 2 {
|
if len(pathSegments) == 2 {
|
||||||
if request.Method != "GET" {
|
if request.Method != "GET" {
|
||||||
|
@ -183,6 +184,8 @@ func main() {
|
||||||
}
|
}
|
||||||
jsonData, _ := json.Marshal(blobs)
|
jsonData, _ := json.Marshal(blobs)
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
switch pathSegments[2] {
|
switch pathSegments[2] {
|
||||||
case "head":
|
case "head":
|
||||||
|
@ -255,6 +258,7 @@ func main() {
|
||||||
|
|
||||||
jsonData, _ := json.Marshal(result)
|
jsonData, _ := json.Marshal(result)
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if request.Method != "POST" {
|
if request.Method != "POST" {
|
||||||
|
@ -268,6 +272,7 @@ func main() {
|
||||||
|
|
||||||
jsonData, _ := json.Marshal(result)
|
jsonData, _ := json.Marshal(result)
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,11 +288,12 @@ func main() {
|
||||||
|
|
||||||
jsonData, _ := json.Marshal(result)
|
jsonData, _ := json.Marshal(result)
|
||||||
writer.Write(jsonData)
|
writer.Write(jsonData)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
writer.WriteHeader(http.StatusNotFound)
|
|
||||||
writer.Write([]byte{'{', '}'})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.WriteHeader(http.StatusNotFound)
|
||||||
|
writer.Write([]byte{'{', '}'})
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,13 @@ This project is a Work in Progress.
|
||||||
|
|
||||||
# Improvements / differences from Kawa
|
# Improvements / differences from Kawa
|
||||||
* Does not use libav ([see supported formats/codecs on Kirika](https://git.gammaspectra.live/S.O.N.G/Kirika#codecs-supported))
|
* Does not use libav ([see supported formats/codecs on Kirika](https://git.gammaspectra.live/S.O.N.G/Kirika#codecs-supported))
|
||||||
|
* No Vorbis support.
|
||||||
* Supports HTTP clients that have more than 16 HTTP request headers.
|
* Supports HTTP clients that have more than 16 HTTP request headers.
|
||||||
* Does not restart stream per-track, instead being a continuous stream without parameter changes.
|
* Does not restart stream per-track, instead being a continuous stream without parameter changes.
|
||||||
* Normalized channels / sample rates for mounts.
|
* Normalized channels / sample rates for mounts.
|
||||||
* Implements ICY metadata
|
* Implements ICY metadata
|
||||||
* Uses sample/timed packet buffers, instead of kawa byte buffers, which cause wild differences between endpoints. Mounts usually align within 0.2s of each other, depending on client.
|
* Uses sample/timed packet buffers, instead of kawa byte buffers, which cause wild differences between endpoints. Mounts usually align within 0.2s of each other, depending on client.
|
||||||
* Implements `queue.nr` and `/nr` (To be Deprecated/Changed)
|
* Implements `queue.nr` and `/random` (To be Deprecated/Changed)
|
||||||
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
@ -25,7 +26,7 @@ Kirika is a collection of audio utilities for decoding/encoding files and stream
|
||||||
Check its native dependencies that must be installed before usage.
|
Check its native dependencies that must be installed before usage.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
Start by copying example_config.toml to the location of your choice and reading through it. Of importance are `queue.fallback`, and `queue.random_song_api`.
|
Start by copying [example_config.toml](example_config.toml) to the location of your choice and reading through it. Of importance are `queue.fallback`, and `queue.random_song_api`.
|
||||||
|
|
||||||
MeteorLight will search for `config.toml` in its working directory. Alternatively you can pass `-config "/example/path/config.toml"` to specify a different location.
|
MeteorLight will search for `config.toml` in its working directory. Alternatively you can pass `-config "/example/path/config.toml"` to specify a different location.
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ import "github.com/BurntSushi/toml"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Api struct {
|
Api struct {
|
||||||
Port int `toml:"port"`
|
Host string `toml:"host"`
|
||||||
|
Port int `toml:"port"`
|
||||||
} `toml:"api"`
|
} `toml:"api"`
|
||||||
Queue struct {
|
Queue struct {
|
||||||
RandomSongApi string `toml:"random_song_api"`
|
RandomSongApi string `toml:"random_song_api"`
|
||||||
|
|
|
@ -2,50 +2,52 @@
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
#
|
#
|
||||||
# The HTTP port the Kawa API listens on. Kawa will listen on localhost.
|
# The HTTP port the MeteorLight API listens on.
|
||||||
port=4040
|
port=4040
|
||||||
|
# The HTTP bind address API will listen on.
|
||||||
|
host="127.0.0.1"
|
||||||
|
|
||||||
[queue]
|
[queue]
|
||||||
#
|
#
|
||||||
# An HTTP GET is sent to this URL when Kawa's queue is empty and it needs a new
|
# An HTTP GET is sent to this URL when MeteorLight's queue is empty and it needs a new
|
||||||
# random track to play. The expected response is an arbitrary JSON blob that
|
# random track to play. The expected response is an arbitrary JSON blob that
|
||||||
# Kawa stores in its queue. At a minimum, it must include the "path" property:
|
# MeteorLight stores in its queue. At a minimum, it must include the "path" property:
|
||||||
#
|
#
|
||||||
# {
|
# {
|
||||||
# "path": "/path/to/audio/file"
|
# "path": "/path/to/audio/file"
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# The path is the path to an audio file on the filesystem you want Kawa to play.
|
# The path is the path to an audio file on the filesystem you want MeteorLight to play.
|
||||||
random_song_api="http://localhost:8012/api/random"
|
random_song_api="http://localhost:8012/api/random"
|
||||||
#
|
#
|
||||||
# An HTTP POST is issued to this URL when Kawa starts playing a track. The body
|
# An HTTP POST is issued to this URL when MeteorLight starts playing a track. The body
|
||||||
# will be identical to the JSON blob in the queue.
|
# will be identical to the JSON blob in the queue.
|
||||||
np="http://localhost:8012/api/np"
|
np="http://localhost:8012/api/np"
|
||||||
#
|
#
|
||||||
# An HTTP POST is issued to this URL when Kawa fetches a random track. The body
|
# An HTTP POST is issued to this URL when MeteorLight fetches a random track. The body
|
||||||
# will be identical to the JSON blob in memory.
|
# will be identical to the JSON blob in memory.
|
||||||
nr="http://localhost:8012/api/nr"
|
nr="http://localhost:8012/api/nr"
|
||||||
#
|
#
|
||||||
# When no tracks are available for whatever reason (such as external service
|
# When no tracks are available for whatever reason (such as external service
|
||||||
# outages), this track will be played.
|
# outages), this track will be played.
|
||||||
fallback="/tmp/in.flac"
|
fallback="/tmp/in.flac"
|
||||||
# Length of buffer to maintain in KiB
|
# Length of buffer to maintain in KiB (not implemented)
|
||||||
buffer_len=4096
|
buffer_len=4096
|
||||||
|
|
||||||
[radio]
|
[radio]
|
||||||
#
|
#
|
||||||
# The port to stream actual audio on. Kawa will listen on localhost.
|
# The port to stream actual audio on. MeteorLight will listen on localhost.
|
||||||
port=8001
|
port=8001
|
||||||
# Name of the stream.
|
# Name of the stream.
|
||||||
name="my radio"
|
name="my radio"
|
||||||
|
|
||||||
#
|
#
|
||||||
# A list of streams to make available at [radio.port]/(mount) follows. The
|
# A list of streams to make available at [radio.port]/*(mount) follows. The
|
||||||
# following properties are available:
|
# following properties are available:
|
||||||
#
|
#
|
||||||
# mount: the HTTP address to serve the stream from
|
# mount: the HTTP address to serve the stream from
|
||||||
# container: the container format to use (ogg, flac, aac, or mp3)
|
# container: the container format to use (ogg, flac, aac, or mp3). See Kirika's supported format list.
|
||||||
# codec: the audio codec to use (opus, vorbis, flac, aac, do not specify for mp3 streams)
|
# codec: the audio codec to use (opus, flac, aac, do not specify for mp3 streams)
|
||||||
# bitrate: the desired bitrate of the stream in Kb/s, if not specified (or 0) an appropriate
|
# bitrate: the desired bitrate of the stream in Kb/s, if not specified (or 0) an appropriate
|
||||||
# bitrate will be automatically selected based on the container/codec
|
# bitrate will be automatically selected based on the container/codec
|
||||||
# MeteorLight extension: bitrate can be a string (for example, v0/v1/v2/v3 on MP3). codec can also be he-aacv2. No vorbis support
|
# MeteorLight extension: bitrate can be a string (for example, v0/v1/v2/v3 on MP3). codec can also be he-aacv2. No vorbis support
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.gammaspectra.live/S.O.N.G/MeteorLight
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220302151314-7b6b11dd6c5c
|
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220303091537-9e01c732f300
|
||||||
github.com/BurntSushi/toml v1.0.0
|
github.com/BurntSushi/toml v1.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
||||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220302151314-7b6b11dd6c5c h1:8Tcq/ueYofDoeRgovGwekXHhyH0i15vm79W5wK/WwpE=
|
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220303091537-9e01c732f300 h1:tBRw3QkXCkybDhZ5lwqjNDbyB4YfI2pJ8ZXR+pkago0=
|
||||||
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220302151314-7b6b11dd6c5c/go.mod h1:NYC/3wOINygtTYvAqEtMfgWBeJ/9Gfv0NvDxnWmg+yA=
|
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220303091537-9e01c732f300/go.mod h1:NYC/3wOINygtTYvAqEtMfgWBeJ/9Gfv0NvDxnWmg+yA=
|
||||||
git.gammaspectra.live/S.O.N.G/go-fdkaac v0.0.0-20220228131722-e9cb84c52f48 h1:MaKiBfXQl0keyfdCi1PxGOKRTiWhIs8PqCal5GhKDi0=
|
git.gammaspectra.live/S.O.N.G/go-fdkaac v0.0.0-20220228131722-e9cb84c52f48 h1:MaKiBfXQl0keyfdCi1PxGOKRTiWhIs8PqCal5GhKDi0=
|
||||||
git.gammaspectra.live/S.O.N.G/go-fdkaac v0.0.0-20220228131722-e9cb84c52f48/go.mod h1:pkWt//S9hLVEQaJDPu/cHHPk8vPpo/0+zHy0me4LIP4=
|
git.gammaspectra.live/S.O.N.G/go-fdkaac v0.0.0-20220228131722-e9cb84c52f48/go.mod h1:pkWt//S9hLVEQaJDPu/cHHPk8vPpo/0+zHy0me4LIP4=
|
||||||
git.gammaspectra.live/S.O.N.G/go-pus v0.0.0-20220227175608-6cc027f24dba h1:JEaxCVgdr3XXAuDCPAx7ttLFZaaHzTEzG+oRnVUtUKU=
|
git.gammaspectra.live/S.O.N.G/go-pus v0.0.0-20220227175608-6cc027f24dba h1:JEaxCVgdr3XXAuDCPAx7ttLFZaaHzTEzG+oRnVUtUKU=
|
||||||
|
|
8
queue.go
8
queue.go
|
@ -21,10 +21,10 @@ type QueueTrackEntry struct {
|
||||||
QueueIdentifier audio.QueueIdentifier
|
QueueIdentifier audio.QueueIdentifier
|
||||||
Path string
|
Path string
|
||||||
Metadata struct {
|
Metadata struct {
|
||||||
Title string
|
Title string `json:"title"`
|
||||||
Album string
|
Album string `json:"album"`
|
||||||
Artist string
|
Artist string `json:"artist"`
|
||||||
Art string
|
Art string `json:"art"`
|
||||||
}
|
}
|
||||||
|
|
||||||
original map[string]interface{}
|
original map[string]interface{}
|
||||||
|
|
Loading…
Reference in a new issue