-
Notifications
You must be signed in to change notification settings - Fork 20
/
ids.go
120 lines (95 loc) · 2.64 KB
/
ids.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package go_librespot
import (
"encoding/hex"
"fmt"
"math/big"
"regexp"
"strings"
connectpb "github.com/devgianlu/go-librespot/proto/spotify/connectstate"
)
var UriRegexp = regexp.MustCompile("^spotify:([a-z]+):([0-9a-zA-Z]{21,22})$")
func InferSpotifyIdTypeFromContextUri(uri string) SpotifyIdType {
if strings.HasPrefix(uri, "spotify:episode:") || strings.HasPrefix(uri, "spotify:show:") {
return SpotifyIdTypeEpisode
}
return SpotifyIdTypeTrack
}
func ContextTrackToProvidedTrack(typ SpotifyIdType, track *connectpb.ContextTrack) *connectpb.ProvidedTrack {
var uri string
if len(track.Uri) > 0 {
uri = track.Uri
} else if len(track.Gid) > 0 {
uri = SpotifyIdFromGid(typ, track.Gid).Uri()
} else {
panic("invalid context track")
}
artistUri, _ := track.Metadata["artist_uri"]
albumUri, _ := track.Metadata["album_uri"]
provider := "context"
if val := track.Metadata["is_queued"]; val == "true" {
provider = "queue"
} else if val = track.Metadata["autoplay.is_autoplay"]; val == "true" {
provider = "autoplay"
}
return &connectpb.ProvidedTrack{
Uri: uri,
Uid: track.Uid,
Metadata: track.Metadata,
ArtistUri: artistUri,
AlbumUri: albumUri,
Provider: provider,
}
}
type SpotifyIdType string
const (
SpotifyIdTypeTrack SpotifyIdType = "track"
SpotifyIdTypeEpisode SpotifyIdType = "episode"
SpotifyIdTypePlaylist SpotifyIdType = "playlist"
)
type SpotifyId struct {
typ SpotifyIdType
id []byte
}
func (id SpotifyId) Type() SpotifyIdType {
return id.typ
}
func (id SpotifyId) Id() []byte {
return id.id
}
func (id SpotifyId) Hex() string {
return hex.EncodeToString(id.id)
}
func (id SpotifyId) Base62() string {
return GidToBase62(id.id)
}
func (id SpotifyId) Uri() string {
return fmt.Sprintf("spotify:%s:%s", id.Type(), id.Base62())
}
func (id SpotifyId) String() string {
return id.Uri()
}
func GidToBase62(id []byte) string {
s := new(big.Int).SetBytes(id).Text(62)
return strings.Repeat("0", 22-len(s)) + s
}
func SpotifyIdFromGid(typ SpotifyIdType, id []byte) SpotifyId {
if len(id) != 16 {
panic(fmt.Sprintf("invalid gid: %s", hex.EncodeToString(id)))
}
return SpotifyId{typ, id}
}
func SpotifyIdFromBase62(typ SpotifyIdType, id string) (*SpotifyId, error) {
var i big.Int
_, ok := i.SetString(id, 62)
if !ok {
return nil, fmt.Errorf("failed decoding base62: %s", id)
}
return &SpotifyId{typ, i.FillBytes(make([]byte, 16))}, nil
}
func SpotifyIdFromUri(uri string) (_ *SpotifyId, err error) {
matches := UriRegexp.FindStringSubmatch(uri)
if len(matches) == 0 {
return nil, fmt.Errorf("invalid uri: %s", uri)
}
return SpotifyIdFromBase62(SpotifyIdType(matches[1]), matches[2])
}