Skip to content

Commit 1c04775

Browse files
committed
feat: Generalize TrackId into SpotifyId
This allows to parse both tracks and episodes and avoid crashing when we get an unknown Spotify uri.
1 parent 49b8edc commit 1c04775

7 files changed

Lines changed: 61 additions & 25 deletions

File tree

audio/provider.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,15 @@ func (p *KeyProvider) recvLoop() {
8989

9090
reqs[reqSeq] = req
9191

92+
// FIXME: this might not always be a track
93+
uri := librespot.SpotifyIdFromGid(librespot.SpotifyIdTypeTrack, req.gid).Uri()
9294
if err := p.ap.Send(ap.PacketTypeRequestKey, buf.Bytes()); err != nil {
9395
delete(reqs, reqSeq)
9496
req.resp <- keyResponse{err: fmt.Errorf("failed sending key request for file %s, track: %s: %w",
95-
hex.EncodeToString(req.fileId), librespot.TrackId(req.gid).Uri(), err)}
97+
hex.EncodeToString(req.fileId), uri, err)}
9698
}
9799

98-
log.Debugf("requested aes key for file %s, track: %s", hex.EncodeToString(req.fileId), librespot.TrackId(req.gid).Uri())
100+
log.Debugf("requested aes key for file %s, track: %s", hex.EncodeToString(req.fileId), uri)
99101
}
100102
}
101103
}

cmd/daemon/api_server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ func NewApiResponseStatusTrack(track *metadatapb.Track, prodInfo *ProductInfo, p
112112
}
113113

114114
return &ApiResponseStatusTrack{
115-
Uri: librespot.TrackId(track.Gid).Uri(),
115+
// FIXME: this might not always be a track
116+
Uri: librespot.SpotifyIdFromGid(librespot.SpotifyIdTypeTrack, track.Gid).Uri(),
116117
Name: *track.Name,
117118
ArtistNames: artists,
118119
AlbumName: *track.Album.Name,

cmd/daemon/controls.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,14 @@ func (s *Session) loadCurrentTrack(paused bool) error {
114114
s.stream = nil
115115
}
116116

117-
trackId := librespot.TrackIdFromUri(s.state.player.Track.Uri)
118-
trackPosition := s.state.trackPosition()
117+
spotId := librespot.SpotifyIdFromUri(s.state.player.Track.Uri)
118+
println("spot", spotId.Type(), spotId.Uri())
119+
if spotId.Type() != librespot.SpotifyIdTypeTrack {
120+
return fmt.Errorf("unsupported spotify type: %s", spotId.Type())
121+
}
119122

120-
log.Debugf("loading track %s (paused: %t, position: %dms)", trackId.Uri(), paused, trackPosition)
123+
trackPosition := s.state.trackPosition()
124+
log.Debugf("loading %s %s (paused: %t, position: %dms)", spotId.Type(), spotId.Uri(), paused, trackPosition)
121125

122126
s.state.player.IsPlaying = true
123127
s.state.player.IsBuffering = true
@@ -127,17 +131,17 @@ func (s *Session) loadCurrentTrack(paused bool) error {
127131
s.app.server.Emit(&ApiEvent{
128132
Type: ApiEventTypeWillPlay,
129133
Data: ApiEventDataWillPlay{
130-
Uri: trackId.Uri(),
134+
Uri: spotId.Uri(),
131135
PlayOrigin: s.state.playOrigin(),
132136
},
133137
})
134138

135-
stream, err := s.player.NewStream(trackId, s.app.cfg.Bitrate, trackPosition, paused)
139+
stream, err := s.player.NewStream(spotId, s.app.cfg.Bitrate, trackPosition, paused)
136140
if err != nil {
137141
return fmt.Errorf("failed creating stream: %w", err)
138142
}
139143

140-
log.Infof("loaded track \"%s\" (uri: %s, paused: %t, position: %dms, duration: %dms)", *stream.Track.Name, trackId.Uri(), paused, trackPosition, *stream.Track.Duration)
144+
log.Infof("loaded track \"%s\" (uri: %s, paused: %t, position: %dms, duration: %dms)", *stream.Track.Name, spotId.Uri(), paused, trackPosition, *stream.Track.Duration)
141145

142146
s.state.player.Duration = int64(*stream.Track.Duration)
143147
s.state.player.IsPlaying = true

cmd/daemon/session.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func (s *Session) handlePlayerCommand(req dealer.RequestPayload) error {
171171
return true
172172
} else if len(track.Uri) > 0 && track.Uri == currentTrack.Uri {
173173
return true
174-
} else if len(track.Gid) > 0 && librespot.TrackId(track.Gid).Uri() == currentTrack.Uri {
174+
} else if len(track.Gid) > 0 && librespot.SpotifyIdFromGid(librespot.SpotifyIdTypeTrack, track.Gid).Uri() == currentTrack.Uri /* FIXME: this might not always be a track */ {
175175
return true
176176
} else {
177177
return false

ids.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ var UriRegexp = regexp.MustCompile("^spotify:([a-z]+):([0-9a-zA-Z]{21,22})$")
1414
func ContextTrackToProvidedTrack(track *connectpb.ContextTrack) *connectpb.ProvidedTrack {
1515
var uri string
1616
if len(track.Gid) > 0 {
17-
uri = TrackId(track.Gid).Uri()
17+
// FIXME: this might not always be a track
18+
uri = SpotifyIdFromGid(SpotifyIdTypeTrack, track.Gid).Uri()
1819
} else if len(track.Uri) > 0 {
1920
uri = track.Uri
2021
} else {
@@ -34,27 +35,51 @@ func ContextTrackToProvidedTrack(track *connectpb.ContextTrack) *connectpb.Provi
3435
}
3536
}
3637

37-
type TrackId []byte
38+
type SpotifyIdType string
3839

39-
func (id TrackId) Hex() string {
40-
return hex.EncodeToString(id)
40+
const (
41+
SpotifyIdTypeTrack SpotifyIdType = "track"
42+
SpotifyIdTypeEpisode SpotifyIdType = "episode"
43+
)
44+
45+
type SpotifyId struct {
46+
typ SpotifyIdType
47+
id []byte
48+
}
49+
50+
func (id SpotifyId) Type() SpotifyIdType {
51+
return id.typ
52+
}
53+
54+
func (id SpotifyId) Id() []byte {
55+
return id.id
4156
}
4257

43-
func (id TrackId) Base62() string {
44-
s := new(big.Int).SetBytes(id).Text(62)
58+
func (id SpotifyId) Hex() string {
59+
return hex.EncodeToString(id.id)
60+
}
61+
62+
func (id SpotifyId) Base62() string {
63+
s := new(big.Int).SetBytes(id.id).Text(62)
4564
return strings.Repeat("0", 22-len(s)) + s
4665
}
4766

48-
func (id TrackId) Uri() string {
49-
return fmt.Sprintf("spotify:track:%s", id.Base62())
67+
func (id SpotifyId) Uri() string {
68+
return fmt.Sprintf("spotify:%s:%s", id.Type(), id.Base62())
69+
}
70+
71+
func SpotifyIdFromGid(typ SpotifyIdType, id []byte) SpotifyId {
72+
if len(id) != 16 {
73+
panic(fmt.Sprintf("invalid gid: %s", hex.EncodeToString(id)))
74+
}
75+
76+
return SpotifyId{typ, id}
5077
}
5178

52-
func TrackIdFromUri(uri string) TrackId {
79+
func SpotifyIdFromUri(uri string) SpotifyId {
5380
matches := UriRegexp.FindStringSubmatch(uri)
5481
if len(matches) == 0 {
5582
panic(fmt.Sprintf("invalid uri: %s", uri))
56-
} else if matches[1] != "track" {
57-
panic(fmt.Sprintf("invalid uri type for track: %s", matches[1]))
5883
}
5984

6085
var i big.Int
@@ -63,5 +88,5 @@ func TrackIdFromUri(uri string) TrackId {
6388
panic("failed decoding base62 track uri")
6489
}
6590

66-
return i.FillBytes(make([]byte, 16))
91+
return SpotifyId{SpotifyIdType(matches[1]), i.FillBytes(make([]byte, 16))}
6792
}

player/player.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func (p *Player) SetVolume(val uint32) {
221221

222222
const DisableCheckTrackRestricted = true
223223

224-
func (p *Player) NewStream(tid librespot.TrackId, bitrate int, trackPosition int64, paused bool) (*Stream, error) {
224+
func (p *Player) NewStream(tid librespot.SpotifyId, bitrate int, trackPosition int64, paused bool) (*Stream, error) {
225225
trackMeta, err := p.sp.MetadataForTrack(tid)
226226
if err != nil {
227227
return nil, fmt.Errorf("failed getting track metadata: %w", err)
@@ -248,7 +248,7 @@ func (p *Player) NewStream(tid librespot.TrackId, bitrate int, trackPosition int
248248

249249
log.Debugf("selected format %s for %s", file.Format.String(), tid.Uri())
250250

251-
audioKey, err := p.audioKey.Request(tid, file.FileId)
251+
audioKey, err := p.audioKey.Request(tid.Id(), file.FileId)
252252
if err != nil {
253253
return nil, fmt.Errorf("failed retrieving audio key: %w", err)
254254
}

spclient/spclient.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,11 @@ func (c *Spclient) ResolveStorageInteractive(fileId []byte, prefetch bool) (*sto
180180
return &protoResp, nil
181181
}
182182

183-
func (c *Spclient) MetadataForTrack(track librespot.TrackId) (*metadatapb.Track, error) {
183+
func (c *Spclient) MetadataForTrack(track librespot.SpotifyId) (*metadatapb.Track, error) {
184+
if track.Type() != librespot.SpotifyIdTypeTrack {
185+
panic(fmt.Sprintf("invalid type: %s", track.Type()))
186+
}
187+
184188
resp, err := c.request("GET", fmt.Sprintf("/metadata/4/track/%s", track.Hex()), nil, nil, nil)
185189
if err != nil {
186190
return nil, err

0 commit comments

Comments
 (0)