MeteorLight/MeteorLight.go

328 lines
7.1 KiB
Go
Raw Normal View History

2022-03-01 23:31:29 +00:00
package main
import (
2022-03-02 17:54:56 +00:00
"bytes"
2022-03-01 23:31:29 +00:00
"encoding/json"
"flag"
"fmt"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"io/ioutil"
"log"
"net/http"
2022-03-02 17:54:56 +00:00
"strconv"
2022-03-01 23:31:29 +00:00
"strings"
"sync"
)
func getQueueEntryFromBody(body []byte) *QueueTrackEntry {
entry := &QueueTrackEntry{}
err := json.Unmarshal(body, &entry.original)
if err != nil {
return nil
}
err = json.Unmarshal(body, &entry.Metadata)
if err != nil {
return nil
}
2022-03-01 23:31:29 +00:00
var val interface{}
var strVal string
var ok bool
if val, ok = entry.original["path"]; ok {
if strVal, ok = val.(string); ok {
entry.Path = strVal
}
}
if len(entry.Path) > 0 {
return entry
}
return nil
}
type resultResponse struct {
Success bool `json:"success"`
Reason error `json:"reason"`
}
2022-03-02 17:54:56 +00:00
type queueResultResponse struct {
resultResponse
QueueId audio.QueueIdentifier `json:"queue_id"`
}
2022-03-01 23:31:29 +00:00
func main() {
configPath := flag.String("config", "config.toml", "Config path")
flag.Parse()
2022-03-02 17:54:56 +00:00
config, err := GetConfig(*configPath)
2022-03-01 23:31:29 +00:00
if err != nil {
log.Panic(err)
}
var wg sync.WaitGroup
2022-03-02 17:54:56 +00:00
queue := NewQueue(config)
var nr *QueueTrackEntry
2022-03-02 17:54:56 +00:00
getRandomTrack := func() *QueueTrackEntry {
response, err := http.DefaultClient.Get(config.Queue.RandomSongApi)
if err != nil {
return nil
}
defer response.Body.Close()
2022-03-02 17:54:56 +00:00
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil
}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
return getQueueEntryFromBody(body)
}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
getFallbackTrack := func() *QueueTrackEntry {
m := make(map[string]interface{})
m["path"] = config.Queue.FallbackPath
return &QueueTrackEntry{
Path: config.Queue.FallbackPath,
original: m,
2022-03-01 23:31:29 +00:00
}
}
sendNowRandom := func(nr *QueueTrackEntry) {
if config.Queue.NowRandom != "" {
jsonData, _ := json.Marshal(nr.original)
response, err := http.DefaultClient.Post(config.Queue.NowRandom, "application/json; charset=utf-8", bytes.NewReader(jsonData))
if err != nil {
log.Print(err)
}
if response != nil {
defer response.Body.Close()
}
}
}
2022-03-02 17:54:56 +00:00
wg.Add(1)
go func() {
defer wg.Done()
defer close(queue.QueueEmpty)
//TODO: close properly
for {
if e := getRandomTrack(); e != nil {
queue.QueueEmpty <- e
nr = e
sendNowRandom(nr)
2022-03-02 17:54:56 +00:00
} else if e = getFallbackTrack(); e != nil {
queue.QueueEmpty <- e
nr = e
sendNowRandom(nr)
2022-03-02 17:54:56 +00:00
}
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for np := range queue.NowPlaying {
jsonData, _ := json.Marshal(np.original)
response, err := http.DefaultClient.Post(config.Queue.NowPlaying, "application/json; charset=utf-8", bytes.NewReader(jsonData))
2022-03-02 17:54:56 +00:00
if err != nil {
log.Print(err)
}
if response != nil {
response.Body.Close()
}
2022-03-02 17:54:56 +00:00
}
}()
2022-03-01 23:31:29 +00:00
wg.Add(1)
go func() {
defer wg.Done()
server := http.Server{
Addr: fmt.Sprintf("%s:%d", config.Api.Host, config.Api.Port),
2022-03-01 23:31:29 +00:00
Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Server", "MeteorLight/api")
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
2022-03-02 17:54:56 +00:00
pathSegments := strings.Split(request.URL.Path, "/")
if len(pathSegments) > 1 {
switch pathSegments[1] {
case "listeners":
jsonData, _ := json.Marshal(queue.GetListeners())
writer.Write(jsonData)
return
2022-03-02 17:54:56 +00:00
case "np":
if e := queue.GetNowPlaying(); e != nil {
jsonData, _ := json.Marshal(e.original)
writer.Write(jsonData)
} else {
writer.Write([]byte{'{', '}'})
2022-03-02 17:54:56 +00:00
}
return
2022-03-02 19:02:07 +00:00
case "random":
if nr != nil {
jsonData, _ := json.Marshal(nr.original)
writer.Write(jsonData)
} else {
writer.Write([]byte{'{', '}'})
}
return
2022-03-02 17:54:56 +00:00
case "queue":
if len(pathSegments) == 2 {
2022-03-02 19:06:22 +00:00
if request.Method != "GET" {
2022-03-02 17:54:56 +00:00
return
}
var blobs = make([]map[string]interface{}, 0, 1)
for _, e := range queue.GetQueue() {
blobs = append(blobs, e.original)
}
jsonData, _ := json.Marshal(blobs)
writer.Write(jsonData)
return
2022-03-02 17:54:56 +00:00
} else {
switch pathSegments[2] {
case "head":
if request.Method == "POST" {
result := queueResultResponse{}
if body, err := ioutil.ReadAll(request.Body); err == nil {
if e := getQueueEntryFromBody(body); e != nil {
if err = queue.AddTrack(e, false); err == nil {
result.Success = true
result.QueueId = e.QueueIdentifier
}
}
}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
return
} else if request.Method == "DELETE" {
result := resultResponse{}
if head := queue.GetHead(); head != nil {
result.Success = queue.Remove(head.QueueIdentifier)
}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
return
}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
case "tail":
if request.Method == "POST" {
result := queueResultResponse{}
if body, err := ioutil.ReadAll(request.Body); err == nil {
if e := getQueueEntryFromBody(body); e != nil {
if err = queue.AddTrack(e, true); err == nil {
result.Success = true
result.QueueId = e.QueueIdentifier
}
}
}
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
return
} else if request.Method == "DELETE" {
result := resultResponse{}
if head := queue.GetTail(); head != nil {
result.Success = queue.Remove(head.QueueIdentifier)
}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
return
}
case "clear":
if request.Method != "POST" {
return
}
result := resultResponse{}
for _, e := range queue.GetQueue() {
queue.Remove(e.QueueIdentifier)
}
result.Success = true
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
return
2022-03-02 17:54:56 +00:00
default:
if request.Method != "POST" {
return
}
if i, err := strconv.ParseInt(pathSegments[2], 10, 0); err == nil {
result := resultResponse{}
result.Success = queue.Remove(audio.QueueIdentifier(i))
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
return
2022-03-02 17:54:56 +00:00
}
}
2022-03-01 23:31:29 +00:00
}
2022-03-02 17:54:56 +00:00
case "skip":
if request.Method != "POST" {
return
}
result := resultResponse{}
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
result.Success = queue.SkipNowPlaying()
2022-03-01 23:31:29 +00:00
2022-03-02 17:54:56 +00:00
jsonData, _ := json.Marshal(result)
writer.Write(jsonData)
return
2022-03-02 17:54:56 +00:00
}
2022-03-01 23:31:29 +00:00
}
writer.WriteHeader(http.StatusNotFound)
writer.Write([]byte{'{', '}'})
2022-03-01 23:31:29 +00:00
}),
}
if err := server.ListenAndServe(); err != nil {
log.Panic(err)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
server := http.Server{
2022-03-02 17:54:56 +00:00
Addr: fmt.Sprintf(":%d", config.Radio.Port),
Handler: http.HandlerFunc(queue.HandleRadioRequest),
2022-03-01 23:31:29 +00:00
}
if err := server.ListenAndServe(); err != nil {
log.Panic(err)
}
}()
2022-03-02 17:54:56 +00:00
if e := getRandomTrack(); e != nil {
queue.AddTrack(e, false)
} else if e = getFallbackTrack(); e != nil {
queue.AddTrack(e, false)
}
2022-03-01 23:31:29 +00:00
wg.Wait()
2022-03-02 17:54:56 +00:00
queue.Wait()
2022-03-01 23:31:29 +00:00
}