🎉 live server seems to be working now

This commit is contained in:
2026-05-14 14:29:57 +02:00
commit d72e439fd9
181 changed files with 47406 additions and 0 deletions

118
cmd/client/main.go Normal file
View File

@@ -0,0 +1,118 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"github.com/Sendspin/sendspin-go/pkg/sendspin"
"rpi-sendspin/internal/pipewire"
)
func main() {
server := flag.String("server", "localhost:8927", "server address")
name := flag.String("name", hostname(), "player name")
device := flag.String("device", "", "PipeWire sink node name (default: system default)")
listDevices := flag.Bool("list-devices", false, "list available PipeWire sinks and exit")
volume := flag.Int("volume", 80, "initial volume (0-100)")
flag.Parse()
if *listDevices {
sinks, err := pipewire.ListSinks()
if err != nil {
log.Fatalf("list sinks: %v", err)
}
if len(sinks) == 0 {
fmt.Println("no PipeWire sinks found")
return
}
fmt.Println("Available PipeWire sinks:")
for _, s := range sinks {
fmt.Printf(" %s\n", s)
}
return
}
idFile := clientIDFile()
savedID, _ := os.ReadFile(idFile)
clientID, err := sendspin.ResolveClientID("", string(savedID), func(id string) error {
if err := os.MkdirAll(filepath.Dir(idFile), 0700); err != nil {
return err
}
return os.WriteFile(idFile, []byte(id), 0600)
})
if err != nil {
log.Fatalf("resolve client ID: %v", err)
}
output := pipewire.NewOutput(*device, *name)
player, err := sendspin.NewPlayer(sendspin.PlayerConfig{
ServerAddr: *server,
PlayerName: *name,
ClientID: clientID,
Volume: *volume,
Output: output,
Reconnect: sendspin.ReconnectConfig{
Enabled: true,
InitialDelay: 2 * time.Second,
MaxDelay: 30 * time.Second,
Multiplier: 2.0,
},
OnMetadata: func(meta sendspin.Metadata) {
if meta.Artist != "" || meta.Title != "" {
log.Printf("now playing: %s — %s", meta.Artist, meta.Title)
}
},
OnError: func(err error) {
log.Printf("error: %v", err)
},
})
if err != nil {
log.Fatalf("create player: %v", err)
}
defer player.Close()
if *device != "" {
log.Printf("output: %s", *device)
} else {
log.Printf("output: PipeWire default sink")
}
log.Printf("connecting to %s as %q...", *server, *name)
if err := player.Connect(); err != nil {
log.Fatalf("connect: %v", err)
}
if err := player.Play(); err != nil {
log.Fatalf("play: %v", err)
}
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig
log.Println("stopping")
player.Stop()
}
func hostname() string {
h, _ := os.Hostname()
if h == "" {
return "sendspin-player"
}
return h
}
func clientIDFile() string {
dir, err := os.UserConfigDir()
if err != nil {
dir = os.TempDir()
}
return filepath.Join(dir, "rpi-sendspin", "client_id")
}