Skip to content

Commit e77e438

Browse files
committed
feat: add API call to update device name
1 parent 8968e00 commit e77e438

4 files changed

Lines changed: 67 additions & 6 deletions

File tree

api-spec.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ paths:
109109
type: boolean
110110
track:
111111
$ref: '#/components/schemas/track'
112+
/set_device_name:
113+
post:
114+
description: Set the player device name
115+
requestBody:
116+
content:
117+
application/json:
118+
schema:
119+
type: object
120+
required: [ name ]
121+
properties:
122+
name:
123+
description: The new device name
124+
type: string
125+
responses:
126+
200:
127+
description: Successful response
112128
/player/play:
113129
post:
114130
description: Starts playing new content

daemon/api_server.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const (
7474
ApiRequestTypeSetShufflingContext ApiRequestType = "shuffling_context"
7575
ApiRequestTypeAddToQueue ApiRequestType = "add_to_queue"
7676
ApiRequestTypeToken ApiRequestType = "token"
77+
ApiRequestSetDeviceName ApiRequestType = "set_device_name"
7778
)
7879

7980
type ApiEventType string
@@ -648,6 +649,27 @@ func (s *ConcreteApiServer) serve() {
648649

649650
s.handleRequest(ApiRequest{Type: ApiRequestTypeToken}, w)
650651
})
652+
m.HandleFunc("/set_device_name", func(w http.ResponseWriter, r *http.Request) {
653+
if r.Method != "POST" {
654+
w.WriteHeader(http.StatusMethodNotAllowed)
655+
return
656+
}
657+
658+
var data struct {
659+
Name string `json:"name"`
660+
}
661+
if err := jsonDecode(r, &data); err != nil {
662+
w.WriteHeader(http.StatusBadRequest)
663+
return
664+
}
665+
666+
if len(data.Name) == 0 {
667+
w.WriteHeader(http.StatusBadRequest)
668+
return
669+
}
670+
671+
s.handleRequest(ApiRequest{Type: ApiRequestSetDeviceName, Data: data.Name}, w)
672+
})
651673
m.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
652674
opts := &websocket.AcceptOptions{}
653675
if len(s.allowOrigin) > 0 {

daemon/app.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type App struct {
3030
client *http.Client
3131

3232
resolver *apresolve.ApResolver
33+
zeroconf *zeroconf.Zeroconf
3334

3435
deviceId string
3536
deviceType devicespb.DeviceType
@@ -129,6 +130,18 @@ func New(opts *Options) (*App, error) {
129130
return app, nil
130131
}
131132

133+
func (app *App) SetDeviceName(name string) {
134+
if app.cfg.DeviceName == name {
135+
return
136+
}
137+
138+
app.cfg.DeviceName = name
139+
140+
if app.zeroconf != nil {
141+
app.zeroconf.SetDeviceName(name)
142+
}
143+
}
144+
132145
// Run starts the daemon. It blocks until ctx is cancelled or an unrecoverable
133146
// error occurs. The credential type configured in cfg.Credentials.Type
134147
// determines which login flow is used.
@@ -306,7 +319,7 @@ func (app *App) withAppPlayer(ctx context.Context, appPlayerFunc func(context.Co
306319
return fmt.Errorf("failed getting endpoints from resolver: %w", err)
307320
}
308321

309-
z, err := zeroconf.NewZeroconf(app.log, app.cfg.ZeroconfPort, app.cfg.DeviceName, app.deviceId, app.deviceType, app.cfg.ZeroconfInterfacesToAdvertise, app.cfg.ZeroconfBackend == "avahi")
322+
app.zeroconf, err = zeroconf.NewZeroconf(app.log, app.cfg.ZeroconfPort, app.cfg.DeviceName, app.deviceId, app.deviceType, app.cfg.ZeroconfInterfacesToAdvertise, app.cfg.ZeroconfBackend == "avahi")
310323
if err != nil {
311324
return fmt.Errorf("failed initializing zeroconf: %w", err)
312325
}
@@ -325,7 +338,7 @@ func (app *App) withAppPlayer(ctx context.Context, appPlayerFunc func(context.Co
325338
apiCh = make(chan ApiRequest)
326339
go currentPlayer.Run(ctx, apiCh, app.mpris.Receive())
327340

328-
z.SetCurrentUser(currentPlayer.sess.Username())
341+
app.zeroconf.SetCurrentUser(currentPlayer.sess.Username())
329342
}
330343

331344
go func() {
@@ -363,16 +376,16 @@ func (app *App) withAppPlayer(ctx context.Context, appPlayerFunc func(context.Co
363376
if err != nil {
364377
app.log.WithError(err).Errorf("failed restoring session after logout")
365378

366-
z.SetCurrentUser("")
379+
app.zeroconf.SetCurrentUser("")
367380
} else if newAppPlayer == nil {
368-
z.SetCurrentUser("")
381+
app.zeroconf.SetCurrentUser("")
369382
} else {
370383
apiCh = make(chan ApiRequest)
371384
currentPlayer = newAppPlayer
372385

373386
go newAppPlayer.Run(ctx, apiCh, app.mpris.Receive())
374387

375-
z.SetCurrentUser(newAppPlayer.sess.Username())
388+
app.zeroconf.SetCurrentUser(newAppPlayer.sess.Username())
376389

377390
app.log.WithField("username", librespot.ObfuscateUsername(currentPlayer.sess.Username())).
378391
Debugf("restored session after logout")
@@ -381,7 +394,7 @@ func (app *App) withAppPlayer(ctx context.Context, appPlayerFunc func(context.Co
381394
}
382395
}()
383396

384-
return z.Serve(func(req zeroconf.NewUserRequest) bool {
397+
return app.zeroconf.Serve(func(req zeroconf.NewUserRequest) bool {
385398
if currentPlayer != nil {
386399
currentPlayer.Close()
387400
currentPlayer = nil

daemon/player.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,11 +593,21 @@ func (p *AppPlayer) handleApiRequest(ctx context.Context, req ApiRequest) (any,
593593
return &ApiResponseToken{
594594
Token: accessToken,
595595
}, nil
596+
case ApiRequestSetDeviceName:
597+
p.setDeviceName(ctx, req.Data.(string))
598+
return nil, nil
596599
default:
597600
return nil, fmt.Errorf("unknown request type: %s", req.Type)
598601
}
599602
}
600603

604+
func (p *AppPlayer) setDeviceName(ctx context.Context, name string) {
605+
p.app.SetDeviceName(name)
606+
607+
p.state.device.Name = name
608+
p.updateState(ctx)
609+
}
610+
601611
func pointer[T any](d T) *T {
602612
return &d
603613
}

0 commit comments

Comments
 (0)