Skip to content

Commit

Permalink
feat: support autoplay context in spclient
Browse files Browse the repository at this point in the history
  • Loading branch information
devgianlu committed Feb 19, 2024
1 parent ec31ca1 commit 0bff8f8
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 11 deletions.
10 changes: 10 additions & 0 deletions proto/autoplay_context_request.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto2";

package spotify.player;

option go_package = "go-librespot/proto/spotify/player";

message AutoplayContextRequest {
required string context_uri = 1;
repeated string recent_track_uri = 2;
}
156 changes: 156 additions & 0 deletions proto/spotify/player/autoplay_context_request.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 18 additions & 11 deletions spclient/context_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,34 @@ type ContextResolver struct {
ctx *connectpb.Context
}

func NewContextResolver(sp *Spclient, ctx *connectpb.Context) (*ContextResolver, error) {
func NewContextResolver(sp *Spclient, ctx *connectpb.Context) (_ *ContextResolver, err error) {
typ := librespot.InferSpotifyIdTypeFromContextUri(ctx.Uri)
if len(ctx.Pages) > 0 {
return &ContextResolver{sp, typ, ctx}, nil
} else {
newCtx, err := sp.ContextResolve(ctx.Uri)
if len(ctx.Pages) == 0 {
ctx, err = sp.ContextResolve(ctx.Uri)
if err != nil {
return nil, fmt.Errorf("failed resolving context %s: %w", ctx.Uri, err)
} else if newCtx.Loading {
return nil, fmt.Errorf("context %s is loading", newCtx.Uri)
} else if ctx.Loading {
return nil, fmt.Errorf("context %s is loading", ctx.Uri)
}

if newCtx.Metadata == nil {
newCtx.Metadata = map[string]string{}
if ctx.Metadata == nil {
ctx.Metadata = map[string]string{}
}
for key, val := range ctx.Metadata {
newCtx.Metadata[key] = val
ctx.Metadata[key] = val
}
}

return &ContextResolver{sp, typ, newCtx}, nil
autoplay := strings.HasPrefix(ctx.Uri, "spotify:station:")
for _, page := range ctx.Pages {
for _, track := range page.Tracks {
if autoplay {
track.Metadata["autoplay.is_autoplay"] = "true"
}
}
}

return &ContextResolver{sp, typ, ctx}, nil
}

func (r *ContextResolver) Type() librespot.SpotifyIdType {
Expand Down
31 changes: 31 additions & 0 deletions spclient/spclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
connectpb "go-librespot/proto/spotify/connectstate"
storagepb "go-librespot/proto/spotify/download"
metadatapb "go-librespot/proto/spotify/metadata"
playerpb "go-librespot/proto/spotify/player"
"google.golang.org/protobuf/proto"
"io"
"net/http"
Expand Down Expand Up @@ -272,3 +273,33 @@ func (c *Spclient) ContextResolve(uri string) (*connectpb.Context, error) {

return &context, nil
}

func (c *Spclient) ContextResolveAutoplay(reqProto *playerpb.AutoplayContextRequest) (*connectpb.Context, error) {
reqBody, err := proto.Marshal(reqProto)
if err != nil {
return nil, fmt.Errorf("failed marshalling AutoplayContextRequest: %w", err)
}

resp, err := c.request("POST", "/context-resolve/v1/autoplay", nil, nil, reqBody)
if err != nil {
return nil, err
}

defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != 200 {
return nil, fmt.Errorf("invalid status code from context resolve autoplay: %d", resp.StatusCode)
}

respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed reading response body: %w", err)
}

var context connectpb.Context
if err := json.Unmarshal(respBytes, &context); err != nil {
return nil, fmt.Errorf("failed json unmarshalling Context: %w", err)
}

return &context, nil
}

0 comments on commit 0bff8f8

Please sign in to comment.