Skip to content

Commit 5560ee8

Browse files
committed
Support friends + user presence by ID
Cleaner handling for the unique `dateUploaded` JSON tag for screenshots
1 parent 1d18258 commit 5560ee8

File tree

3 files changed

+175
-13
lines changed

3 files changed

+175
-13
lines changed

account.go

+70
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
"strconv"
7+
"strings"
78
)
89

910
const (
@@ -72,3 +73,72 @@ func (c *Client) GetAccount() (*Account, error) {
7273

7374
return response.ProfileUsers[0], nil
7475
}
76+
77+
// GenerateGamertags returns a list of generated gamertag options
78+
func (c *Client) GenerateGamertags(quantity int) ([]string, error) {
79+
if quantity <= 0 {
80+
return nil, errors.New("invalid quantity")
81+
}
82+
83+
request := struct {
84+
Algorithm int `json:"algorithm"`
85+
Count int `json:"count"`
86+
Seed string `json:"seed"`
87+
Locale string `json:"locale"`
88+
}{1, quantity, "", "en-US"}
89+
90+
response := struct {
91+
Gamertags []string `json:"Gamertags"`
92+
}{}
93+
94+
if _, err := c.makeRequest("POST", "generate/gamertag", request, &response); err != nil {
95+
return nil, err
96+
}
97+
98+
if len(response.Gamertags) == 0 {
99+
return nil, errors.New("failed to generate gamertags")
100+
}
101+
102+
return response.Gamertags, nil
103+
}
104+
105+
type Presence struct {
106+
ID string `json:"xuid"`
107+
Devices []struct {
108+
Type string `json:"type"`
109+
Titles []struct {
110+
ID string `json:"id"`
111+
Name string `json:"name"`
112+
Placement string `json:"placement"`
113+
State string `json:"state"`
114+
LastModified string `json:"lastModified"`
115+
} `json:"titles"`
116+
} `json:"devices"`
117+
LastSeen struct {
118+
DeviceType string `json:"deviceType"`
119+
TitleID string `json:"titleId"`
120+
TitleName string `json:"titleName"`
121+
Timestamp string `json:"timestamp"`
122+
} `json:"lastSeen"`
123+
State string `json:"state"`
124+
}
125+
126+
// GetPresenceForUser returns the current Presence for the given user ID
127+
func (c *Client) GetPresenceForUser(xboxIDs ...string) ([]*Presence, error) {
128+
if len(xboxIDs) == 0 {
129+
return nil, errors.New("missing xbox ID")
130+
131+
}
132+
133+
var response []*Presence
134+
135+
if _, err := c.makeRequest("GET", strings.Join(xboxIDs, ",")+"/presence", nil, &response); err != nil {
136+
return nil, err
137+
}
138+
139+
if len(response) == 0 {
140+
return nil, errors.New("failed to find user presences")
141+
}
142+
143+
return response, nil
144+
}

dvr.go

+19-13
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ type DVRCapture struct {
3838
TitleID int `json:"titleId"` // Game's ID
3939
TitleName string `json:"titleName"` // Game's name
4040
UploadDate time.Time `json:"uploadDate"`
41-
UploadDateRaw time.Time `json:"dateUploaded"` // For screenshots
4241
UploadLanguage string `json:"uploadLanguage"`
4342
UploadRegion string `json:"uploadRegion"`
4443
UploadTitleID int `json:"uploadTitleId"`
@@ -84,8 +83,8 @@ type Clip struct {
8483
FrameRate int `json:"frameRate"` // Only exists for clips
8584
}
8685

87-
func (c *Client) DeleteDVRClip(gameClipID string) error {
88-
if _, err := c.makeRequest("GET", "dvr/gameclips/delete/"+gameClipID, nil, nil); err != nil {
86+
func (c *Client) DeleteDVRClip(id string) error {
87+
if _, err := c.makeRequest("GET", "dvr/gameclips/delete/"+id, nil, nil); err != nil {
8988
return err
9089
}
9190

@@ -95,7 +94,7 @@ func (c *Client) DeleteDVRClip(gameClipID string) error {
9594
func (c *Client) GetDVRClips(continuationToken string) ([]*Clip, string, error) {
9695
response := struct {
9796
ContinuationToken string `json:"continuationToken"`
98-
GameClips []*Clip `json:"values"`
97+
Clips []*Clip `json:"values"`
9998
}{}
10099

101100
// if a continuation token (their version of pagination) is supplied, pass it to the API
@@ -108,15 +107,15 @@ func (c *Client) GetDVRClips(continuationToken string) ([]*Clip, string, error)
108107
return nil, "", err
109108
}
110109

111-
if len(response.GameClips) == 0 {
110+
if len(response.Clips) == 0 {
112111
return nil, "", errors.New("failed to find clips")
113112
}
114113

115-
for index := range response.GameClips {
116-
response.GameClips[index].Type = DVRCaptureTypeClip
114+
for index := range response.Clips {
115+
response.Clips[index].Type = DVRCaptureTypeClip
117116
}
118117

119-
return response.GameClips, response.ContinuationToken, nil
118+
return response.Clips, response.ContinuationToken, nil
120119
}
121120

122121
type Screenshot struct {
@@ -125,8 +124,11 @@ type Screenshot struct {
125124

126125
func (c *Client) GetDVRScreenshots(continuationToken string) ([]*Screenshot, string, error) {
127126
response := struct {
128-
ContinuationToken string `json:"continuationToken"`
129-
Screenshots []*Screenshot `json:"values"`
127+
ContinuationToken string `json:"continuationToken"`
128+
Screenshots []*struct {
129+
DVRCapture
130+
DateUploaded time.Time `json:"dateUploaded"`
131+
} `json:"values"`
130132
}{}
131133

132134
// if a continuation token (their version of pagination) is supplied, pass it to the API
@@ -143,12 +145,16 @@ func (c *Client) GetDVRScreenshots(continuationToken string) ([]*Screenshot, str
143145
return nil, "", errors.New("failed to find screenshots")
144146
}
145147

148+
screenshots := make([]*Screenshot, 0, len(response.Screenshots))
149+
146150
for index := range response.Screenshots {
147-
response.Screenshots[index].Type = DVRCaptureTypeScreenshot
148-
response.Screenshots[index].UploadDate = response.Screenshots[index].UploadDateRaw // workaround as the JSON tag is different for screenshots
151+
screenshot := Screenshot{DVRCapture: response.Screenshots[index].DVRCapture}
152+
screenshot.DVRCapture.Type = DVRCaptureTypeScreenshot
153+
screenshot.UploadDate = response.Screenshots[index].DateUploaded
154+
screenshots = append(screenshots, &screenshot)
149155
}
150156

151-
return response.Screenshots, response.ContinuationToken, nil
157+
return screenshots, response.ContinuationToken, nil
152158
}
153159

154160
func (c *Client) SetDVRPrivacy(privacy DVRPrivacy) error {

friends.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package openxbl
2+
3+
import (
4+
"errors"
5+
"time"
6+
)
7+
8+
type Friend struct {
9+
XUID string `json:"xuid"`
10+
IsFavorite bool `json:"isFavorite"`
11+
IsFollowingCaller bool `json:"isFollowingCaller"`
12+
IsFollowedByCaller bool `json:"isFollowedByCaller"`
13+
IsIdentityShared bool `json:"isIdentityShared"`
14+
AddedDateTimeUtc time.Time `json:"addedDateTimeUtc"`
15+
DisplayName string `json:"displayName"`
16+
RealName string `json:"realName"`
17+
DisplayPicURL string `json:"displayPicRaw"`
18+
UseAvatar bool `json:"useAvatar"`
19+
Gamertag string `json:"gamertag"`
20+
GamerScore string `json:"gamerScore"`
21+
XboxOneRep string `json:"xboxOneRep"`
22+
PresenceState string `json:"presenceState"`
23+
PresenceText string `json:"presenceText"`
24+
PresenceDevices interface{} `json:"presenceDevices"`
25+
IsBroadcasting bool `json:"isBroadcasting"`
26+
IsCloaked interface{} `json:"isCloaked"`
27+
IsQuarantined bool `json:"isQuarantined"`
28+
Suggestion interface{} `json:"suggestion"`
29+
Recommendation interface{} `json:"recommendation"`
30+
TitleHistory interface{} `json:"titleHistory"`
31+
MultiplayerSummary struct {
32+
InMultiplayerSession int `json:"InMultiplayerSession"`
33+
InParty int `json:"InParty"`
34+
} `json:"multiplayerSummary"`
35+
RecentPlayer interface{} `json:"recentPlayer"`
36+
Follower interface{} `json:"follower"`
37+
PreferredColor struct {
38+
PrimaryColor string `json:"primaryColor"`
39+
SecondaryColor string `json:"secondaryColor"`
40+
TertiaryColor string `json:"tertiaryColor"`
41+
} `json:"preferredColor"`
42+
PresenceDetails interface{} `json:"presenceDetails"`
43+
TitlePresence interface{} `json:"titlePresence"`
44+
TitleSummaries interface{} `json:"titleSummaries"`
45+
PresenceTitleIDs interface{} `json:"presenceTitleIds"`
46+
Detail interface{} `json:"detail"`
47+
CommunityManagerTitles interface{} `json:"communityManagerTitles"`
48+
SocialManager struct {
49+
TitleIDs []interface{} `json:"titleIds"`
50+
} `json:"socialManager"`
51+
Broadcast []interface{} `json:"broadcast"`
52+
TournamentSummary interface{} `json:"tournamentSummary"`
53+
Avatar interface{} `json:"avatar"`
54+
}
55+
56+
// GetFriends returns all friends
57+
func (c *Client) GetFriends() ([]*Friend, error) {
58+
response := struct {
59+
Friends []*Friend `json:"people"`
60+
}{}
61+
62+
if _, err := c.makeRequest("GET", "friends", nil, &response); err != nil {
63+
return nil, err
64+
}
65+
66+
if len(response.Friends) == 0 {
67+
return nil, errors.New("failed to find friends")
68+
}
69+
70+
return response.Friends, nil
71+
}
72+
73+
// GetPresenceForFriends returns the current Presence for your friends
74+
func (c *Client) GetPresenceForFriends() ([]*Presence, error) {
75+
var response []*Presence
76+
77+
if _, err := c.makeRequest("GET", "presence", nil, &response); err != nil {
78+
return nil, err
79+
}
80+
81+
if len(response) == 0 {
82+
return nil, errors.New("failed to find friend presences")
83+
}
84+
85+
return response, nil
86+
}

0 commit comments

Comments
 (0)