web api version
This commit is contained in:
parent
8ebac4b864
commit
69eab07e9a
71
main.go
71
main.go
|
@ -1,71 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"player/player"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
stations := []player.Station{
|
|
||||||
{Name: "KEXP", URL: "https://kexp-mp3-128.streamguys1.com/kexp128.mp3"},
|
|
||||||
{Name: "StuBru", URL: "http://icecast.vrtcdn.be/stubru-high.mp3"},
|
|
||||||
{Name: "StuBru Bruut", URL: "http://icecast.vrtcdn.be/stubru_bruut-high.mp3"},
|
|
||||||
{Name: "StuBru Untz", URL: "http://icecast.vrtcdn.be/stubru_untz-high.mp3"},
|
|
||||||
{Name: "StuBru Hooray", URL: "http://icecast.vrtcdn.be/stubru_hiphophooray-high.mp3"},
|
|
||||||
}
|
|
||||||
|
|
||||||
radio := player.NewPlayer()
|
|
||||||
if err := radio.Init(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Stations:")
|
|
||||||
for i, stream := range stations {
|
|
||||||
fmt.Printf("%d: %s\n", i, stream.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
fmt.Println("Press a number to change stations, 9 to quit")
|
|
||||||
|
|
||||||
number, err := getNext()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if number == 9 {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
station := stations[number]
|
|
||||||
fmt.Printf("Playing %s\n", station.Name)
|
|
||||||
|
|
||||||
if err := radio.Select(station); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNext() (int, error) {
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
input, err := reader.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
return 9, err
|
|
||||||
}
|
|
||||||
|
|
||||||
number, err := strconv.Atoi(strings.TrimSpace(input))
|
|
||||||
if err != nil {
|
|
||||||
return 9, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return number, nil
|
|
||||||
}
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package player
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
radio *Player
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAPI(radio *Player) *API {
|
||||||
|
return &API{
|
||||||
|
radio: radio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
a.Status(w, r)
|
||||||
|
case http.MethodPost:
|
||||||
|
a.Select(w, r)
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) Status(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := json.Marshal(a.radio.Status())
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
fmt.Fprintf(w, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) Select(w http.ResponseWriter, r *http.Request) {
|
||||||
|
reqBody, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
command := struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Channel int `json:"channel"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(reqBody, &command); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if command.Action == "play" {
|
||||||
|
if err := a.radio.Select(command.Channel); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a.radio.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Status(w, r)
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package player
|
package player
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -14,17 +15,27 @@ type Station struct {
|
||||||
URL string
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Status struct {
|
||||||
|
Playing bool
|
||||||
|
Station string
|
||||||
|
Channels []string
|
||||||
|
}
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
|
stations []Station
|
||||||
|
current int
|
||||||
oldStreamer beep.StreamCloser
|
oldStreamer beep.StreamCloser
|
||||||
oldCtrl *beep.Ctrl
|
oldCtrl *beep.Ctrl
|
||||||
mixer *beep.Mixer
|
mixer *beep.Mixer
|
||||||
sr beep.SampleRate
|
sr beep.SampleRate
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlayer() *Player {
|
func NewPlayer(stations []Station) *Player {
|
||||||
return &Player{
|
return &Player{
|
||||||
mixer: &beep.Mixer{},
|
stations: stations,
|
||||||
sr: beep.SampleRate(48000),
|
current: -1,
|
||||||
|
mixer: &beep.Mixer{},
|
||||||
|
sr: beep.SampleRate(48000),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +50,12 @@ func (p *Player) Init() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) Select(station Station) error {
|
func (p *Player) Select(channel int) error {
|
||||||
res, err := http.Get(station.URL)
|
if channel < 0 || channel >= len(p.stations) {
|
||||||
|
return fmt.Errorf("unknown channel: %d", channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := http.Get(p.stations[channel].URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -53,6 +68,7 @@ func (p *Player) Select(station Station) error {
|
||||||
resampled := Resample(4, format.SampleRate, p.sr, streamer)
|
resampled := Resample(4, format.SampleRate, p.sr, streamer)
|
||||||
|
|
||||||
p.PlayStream(resampled)
|
p.PlayStream(resampled)
|
||||||
|
p.current = channel
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -80,3 +96,32 @@ func (p *Player) PlayStream(streamer beep.StreamCloser) {
|
||||||
p.oldCtrl = ctrl
|
p.oldCtrl = ctrl
|
||||||
p.oldStreamer = streamer
|
p.oldStreamer = streamer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Player) Stop() {
|
||||||
|
speaker.Lock()
|
||||||
|
if p.oldCtrl != nil {
|
||||||
|
p.oldCtrl.Paused = true
|
||||||
|
p.oldCtrl.Streamer = nil
|
||||||
|
p.oldStreamer.Close()
|
||||||
|
}
|
||||||
|
speaker.Unlock()
|
||||||
|
|
||||||
|
p.current = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Player) Status() Status {
|
||||||
|
channels := make([]string, len(p.stations))
|
||||||
|
for i, stat := range p.stations {
|
||||||
|
channels[i] = stat.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.current < 0 || p.current >= len(p.stations) {
|
||||||
|
return Status{Channels: channels}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status{
|
||||||
|
Playing: true,
|
||||||
|
Station: p.stations[p.current].Name,
|
||||||
|
Channels: channels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
package player
|
|
||||||
|
|
||||||
//
|
|
||||||
//type App struct {
|
|
||||||
// *Player
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func NewApp() *App {
|
|
||||||
// return &App{
|
|
||||||
// Player: NewPlayer(),
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (a *App) Run() error {
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"player/player"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
stations := []player.Station{
|
||||||
|
{Name: "KEXP", URL: "https://kexp-mp3-128.streamguys1.com/kexp128.mp3"},
|
||||||
|
{Name: "StuBru", URL: "http://icecast.vrtcdn.be/stubru-high.mp3"},
|
||||||
|
{Name: "StuBru Bruut", URL: "http://icecast.vrtcdn.be/stubru_bruut-high.mp3"},
|
||||||
|
{Name: "StuBru Untz", URL: "http://icecast.vrtcdn.be/stubru_untz-high.mp3"},
|
||||||
|
{Name: "StuBru Hooray", URL: "http://icecast.vrtcdn.be/stubru_hiphophooray-high.mp3"},
|
||||||
|
}
|
||||||
|
|
||||||
|
radio := player.NewPlayer(stations)
|
||||||
|
if err := radio.Init(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
go http.ListenAndServe(":8080", player.NewAPI(radio))
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-c
|
||||||
|
}
|
Loading…
Reference in New Issue