Add Users endpoints to API
This commit is contained in:
parent
55b5f772fe
commit
695e998b1f
|
@ -29,6 +29,7 @@ import (
|
||||||
"go.fifitido.net/twitch/api/streams"
|
"go.fifitido.net/twitch/api/streams"
|
||||||
"go.fifitido.net/twitch/api/subscriptions"
|
"go.fifitido.net/twitch/api/subscriptions"
|
||||||
"go.fifitido.net/twitch/api/teams"
|
"go.fifitido.net/twitch/api/teams"
|
||||||
|
"go.fifitido.net/twitch/api/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
const HelixBaseUrl = "https://api.twitch.tv/helix"
|
const HelixBaseUrl = "https://api.twitch.tv/helix"
|
||||||
|
@ -62,6 +63,7 @@ type API struct {
|
||||||
Streams *streams.Streams
|
Streams *streams.Streams
|
||||||
Subscriptions *subscriptions.Subscriptions
|
Subscriptions *subscriptions.Subscriptions
|
||||||
Teams *teams.Teams
|
Teams *teams.Teams
|
||||||
|
Users *users.Users
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(client *http.Client, baseUrl *url.URL) *API {
|
func New(client *http.Client, baseUrl *url.URL) *API {
|
||||||
|
@ -94,6 +96,7 @@ func New(client *http.Client, baseUrl *url.URL) *API {
|
||||||
Streams: streams.New(client, baseUrl),
|
Streams: streams.New(client, baseUrl),
|
||||||
Subscriptions: subscriptions.New(client, baseUrl),
|
Subscriptions: subscriptions.New(client, baseUrl),
|
||||||
Teams: teams.New(client, baseUrl),
|
Teams: teams.New(client, baseUrl),
|
||||||
|
Users: users.New(client, baseUrl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BlockUserParams struct {
|
||||||
|
// The ID of the user to block. The API ignores the request if the broadcaster has already blocked the user.
|
||||||
|
TargetUserID string `url:"target_user_id"`
|
||||||
|
|
||||||
|
// The location where the harassment took place that is causing the brodcaster to block the user. Possible values are:
|
||||||
|
//
|
||||||
|
// chat, whisper
|
||||||
|
SourceContext *string `url:"source_context,omitempty"`
|
||||||
|
|
||||||
|
// The reason that the broadcaster is blocking the user. Possible values are:
|
||||||
|
//
|
||||||
|
// harassment, spam, other
|
||||||
|
Reason *string `url:"reason,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocks the specified user from interacting with or having contact with the broadcaster.
|
||||||
|
// The user ID in the OAuth token identifies the broadcaster who is blocking the user.
|
||||||
|
//
|
||||||
|
// To learn more about blocking users,
|
||||||
|
// see Block Other Users on Twitch: https://help.twitch.tv/s/article/how-to-manage-harassment-in-chat?language=en_US#BlockWhispersandMessagesfromStrangers
|
||||||
|
//
|
||||||
|
// Requires a user access token that includes the user:manage:blocked_users scope.
|
||||||
|
func (u *Users) BlockUser(ctx context.Context, params *BlockUserParams) error {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/blocks", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetUserActiveExtensionsParams struct {
|
||||||
|
// The ID of the broadcaster whose active extensions you want to get.
|
||||||
|
//
|
||||||
|
// This parameter is required if you specify an app access token and is optional if you specify a user access token.
|
||||||
|
// If you specify a user access token and don’t specify this parameter, the API uses the user ID from the access token.
|
||||||
|
UserID string `url:"user_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserActiveExtensionsResponse struct {
|
||||||
|
// The active extensions that the broadcaster has installed.
|
||||||
|
Data []ActiveExtension `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the active extensions that the broadcaster has installed for each configuration.
|
||||||
|
//
|
||||||
|
// NOTE: To include extensions that you have under development,
|
||||||
|
// you must specify a user access token that includes the user:read:broadcast or user:edit:broadcast scope.
|
||||||
|
//
|
||||||
|
// Requires an app access token or user access token.
|
||||||
|
func (u *Users) GetUserActiveExtensions(ctx context.Context, params *GetUserActiveExtensionsParams) (*GetUserActiveExtensionsResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/extensions", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetUserActiveExtensionsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
"go.fifitido.net/twitch/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetUserBlockListParams struct {
|
||||||
|
// The ID of the broadcaster whose list of blocked users you want to get.
|
||||||
|
BroadcasterID string `url:"broadcaster_id"`
|
||||||
|
|
||||||
|
// The maximum number of items to return per page in the response.
|
||||||
|
// The minimum page size is 1 item per page and the maximum is 100.
|
||||||
|
// The default is 20.
|
||||||
|
First *int `url:"first,omitempty"`
|
||||||
|
|
||||||
|
// The cursor used to get the next page of results.
|
||||||
|
// The Pagination object in the response contains the cursor’s value.
|
||||||
|
// Read More: https://dev.twitch.tv/docs/api/guide#pagination
|
||||||
|
After *types.Cursor `url:"after,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserBlockListResponse struct {
|
||||||
|
// The list of blocked users. The list is in descending order by when the user was blocked.
|
||||||
|
Data []struct {
|
||||||
|
// An ID that identifies the blocked user.
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
|
||||||
|
// The blocked user’s login name.
|
||||||
|
UserLogin string `json:"user_login"`
|
||||||
|
|
||||||
|
// The blocked user’s display name.
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the list of users that the broadcaster has blocked.
|
||||||
|
// Read More: https://help.twitch.tv/s/article/how-to-manage-harassment-in-chat?language=en_US#BlockWhispersandMessagesfromStrangers
|
||||||
|
//
|
||||||
|
// Requires a user access token that includes the user:read:blocked_users scope.
|
||||||
|
func (u *Users) GetUserBlockList(ctx context.Context, params *GetUserBlockListParams) (*GetUserBlockListResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/blocks", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetUserBlockListResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetUserExtensionsResponse struct {
|
||||||
|
// The list of extensions that the user has installed.
|
||||||
|
Data []struct {
|
||||||
|
// An ID that identifies the extension.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// The extension's version.
|
||||||
|
Version string `json:"version"`
|
||||||
|
|
||||||
|
// The extension's name.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// A Boolean value that determines whether the extension is configured and can be activated. Is true if the extension is configured and can be activated.
|
||||||
|
CanActivate bool `json:"can_activate"`
|
||||||
|
|
||||||
|
// The extension types that you can activate for this extension. Possible values are:
|
||||||
|
//
|
||||||
|
// component, mobile, overlay, panel
|
||||||
|
Type []string `json:"type"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a list of all extensions (both active and inactive) that the broadcaster has installed.
|
||||||
|
// The user ID in the access token identifies the broadcaster.
|
||||||
|
//
|
||||||
|
// Requires a user access token that includes the user:read:broadcast or user:edit:broadcast scope.
|
||||||
|
// To include inactive extensions, you must include the user:edit:broadcast scope.
|
||||||
|
func (u *Users) GetUserExtensions(ctx context.Context) (*GetUserExtensionsResponse, error) {
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/extensions/list"})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetUserExtensionsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetUsersParams struct {
|
||||||
|
// The ID of the user to get.
|
||||||
|
// To specify more than one user, include the id parameter for each user to get. For example, id=1234&id=5678.
|
||||||
|
// The maximum number of IDs you may specify is 100.
|
||||||
|
IDs []string `url:"id,omitempty"`
|
||||||
|
|
||||||
|
// The login name of the user to get.
|
||||||
|
// To specify more than one user, include the login parameter for each user to get. For example, login=foo&login=bar.
|
||||||
|
// The maximum number of login names you may specify is 100.
|
||||||
|
Logins []string `url:"login,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUsersResponse struct {
|
||||||
|
// The list of users.
|
||||||
|
Data []User `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets information about one or more users.
|
||||||
|
//
|
||||||
|
// You may look up users using their user ID, login name, or both but the sum total of the number of users you may look up is 100.
|
||||||
|
// For example, you may specify 50 IDs and 50 names or 100 IDs or names, but you cannot specify 100 IDs and 100 names.
|
||||||
|
//
|
||||||
|
// If you don’t specify IDs or login names, the request returns information about the user in the access token if you specify a user access token.
|
||||||
|
//
|
||||||
|
// To include the user’s verified email address in the response, you must use a user access token that includes the user:read:email scope.
|
||||||
|
//
|
||||||
|
// Requires an app access token or user access token.
|
||||||
|
func (u *Users) GetUsers(ctx context.Context, params *GetUsersParams) (*GetUsersResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data GetUsersResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
// An ID that identifies the user.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// The user's login name.
|
||||||
|
Login string `json:"login"`
|
||||||
|
|
||||||
|
// The user's display name.
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
|
||||||
|
// The type of user. Possible values are:
|
||||||
|
//
|
||||||
|
// admin — Twitch administrator
|
||||||
|
//
|
||||||
|
// global_mod
|
||||||
|
//
|
||||||
|
// staff — Twitch staff
|
||||||
|
//
|
||||||
|
// "" — Normal user
|
||||||
|
Type Type `json:"type"`
|
||||||
|
|
||||||
|
// The type of broadcaster. Possible values are:
|
||||||
|
//
|
||||||
|
// affiliate — An affiliate broadcaster
|
||||||
|
//
|
||||||
|
// partner — A partner broadcaster
|
||||||
|
//
|
||||||
|
// "" — A normal broadcaster
|
||||||
|
BroadcasterType BroadcasterType `json:"broadcaster_type"`
|
||||||
|
|
||||||
|
// The user's description of their channel.
|
||||||
|
Description string `json:"description"`
|
||||||
|
|
||||||
|
// A URL to the user's profile image.
|
||||||
|
ProfileImageUrl string `json:"profile_image_url"`
|
||||||
|
|
||||||
|
// A URL to the user's offline image.
|
||||||
|
OfflineImageUrl string `json:"offline_image_url"`
|
||||||
|
|
||||||
|
// The user's verified email address. The object includes this field only if the user access token includes the user:read:email scope.
|
||||||
|
//
|
||||||
|
// If the request contains more than one user, only the user associated with the access token that provided consent will include an email address —
|
||||||
|
// the email address for all other users will be empty.
|
||||||
|
Email *string `json:"email"`
|
||||||
|
|
||||||
|
// The UTC date and time that the user's account was created. The timestamp is in RFC3339 format.
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Twitch administrator
|
||||||
|
TypeAdmin Type = "admin"
|
||||||
|
|
||||||
|
// Twitch global moderator
|
||||||
|
TypeGlobalMod Type = "global_mod"
|
||||||
|
|
||||||
|
// Twitch staff
|
||||||
|
TypeStaff Type = "staff"
|
||||||
|
|
||||||
|
// Normal user
|
||||||
|
TypeNormal Type = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
type BroadcasterType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// An affiliate broadcaster
|
||||||
|
BroadcasterTypeAffiliate BroadcasterType = "affiliate"
|
||||||
|
|
||||||
|
// A partner broadcaster
|
||||||
|
BroadcasterTypePartner BroadcasterType = "partner"
|
||||||
|
|
||||||
|
// A normal broadcaster
|
||||||
|
BroadcasterTypeNormal BroadcasterType = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
type ActiveExtension struct {
|
||||||
|
// A dictionary that contains the data for a panel extension.
|
||||||
|
// The dictionary’s key is a sequential number beginning with 1.
|
||||||
|
// The following fields contain the panel’s data for each key.
|
||||||
|
Panel map[string]ExtensionData `json:"panel"`
|
||||||
|
|
||||||
|
// A dictionary that contains the data for a video-overlay extension.
|
||||||
|
// The dictionary’s key is a sequential number beginning with 1.
|
||||||
|
// The following fields contain the overlay’s data for each key.
|
||||||
|
Overlay map[string]ExtensionData `json:"overlay"`
|
||||||
|
|
||||||
|
// A dictionary that contains the data for a video-component extension.
|
||||||
|
// The dictionary’s key is a sequential number beginning with 1.
|
||||||
|
// The following fields contain the component’s data for each key.
|
||||||
|
Component map[string]ComponentExtensionData `json:"component"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtensionData struct {
|
||||||
|
// A Boolean value that determines the extension’s activation state. If false, the user has not configured this panel extension.
|
||||||
|
Active bool `json:"active"`
|
||||||
|
|
||||||
|
// An ID that identifies the extension.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// The extension’s version.
|
||||||
|
Version string `json:"version"`
|
||||||
|
|
||||||
|
// The extension’s name.
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComponentExtensionData struct {
|
||||||
|
ExtensionData `json:",inline"`
|
||||||
|
|
||||||
|
// The x-coordinate where the extension is placed.
|
||||||
|
X int `json:"x"`
|
||||||
|
|
||||||
|
// The y-coordinate where the extension is placed.
|
||||||
|
Y int `json:"y"`
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Removes the user from the broadcaster’s list of blocked users.
|
||||||
|
// The user ID in the OAuth token identifies the broadcaster who’s removing the block.
|
||||||
|
//
|
||||||
|
// Requires a user access token that includes the user:manage:blocked_users scope.
|
||||||
|
func (u *Users) UnblockUser(ctx context.Context, targetUserID string) error {
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/blocks", RawQuery: url.Values{"target_user_id": {targetUserID}}.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/google/go-querystring/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateUserParams struct {
|
||||||
|
// The string to update the channel’s description to. The description is limited to a maximum of 300 characters.
|
||||||
|
//
|
||||||
|
// To remove the description, specify this parameter but don’t set it’s value (for example, ?description=).
|
||||||
|
Description *string `url:"description,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateUserResponse struct {
|
||||||
|
// A list contains the single user that you updated.
|
||||||
|
Data []User `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the specified user’s information. The user ID in the OAuth token identifies the user whose information you want to update.
|
||||||
|
//
|
||||||
|
// To include the user’s verified email address in the response, the user access token must also include the user:read:email scope.
|
||||||
|
//
|
||||||
|
// Requires a user access token that includes the user:edit scope.
|
||||||
|
func (u *Users) UpdateUser(ctx context.Context, params *UpdateUserParams) (*UpdateUserResponse, error) {
|
||||||
|
v, _ := query.Values(params)
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users", RawQuery: v.Encode()})
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPatch, endpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data UpdateUserResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateUserExtensionsRequest struct {
|
||||||
|
// The extensions to update. The data field is a dictionary of extension types.
|
||||||
|
// The dictionary’s possible keys are: panel, overlay, or component.
|
||||||
|
// The key’s value is a dictionary of extensions.
|
||||||
|
//
|
||||||
|
// For the extension’s dictionary, the key is a sequential number beginning with 1.
|
||||||
|
// For panel and overlay extensions, the key’s value is an object that contains the following fields:
|
||||||
|
// active (true/false), id (the extension’s ID), and version (the extension’s version).
|
||||||
|
//
|
||||||
|
// For component extensions, the key’s value includes the above fields plus the x and y fields,
|
||||||
|
// which identify the coordinate where the extension is placed.
|
||||||
|
Data map[string]map[string]interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateUserExtensionsResponse struct {
|
||||||
|
// The extensions that the broadcaster updated.
|
||||||
|
Data []ActiveExtension `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates an installed extension’s information. You can update the extension’s activation state, ID, and version number.
|
||||||
|
// The user ID in the access token identifies the broadcaster whose extensions you’re updating.
|
||||||
|
//
|
||||||
|
// NOTE: If you try to activate an extension under multiple extension types, the last write wins (and there is no guarantee of write order).
|
||||||
|
//
|
||||||
|
// Requires a user access token that includes the user:edit:broadcast scope.
|
||||||
|
func (u *Users) UpdateUserExtensions(ctx context.Context, body *UpdateUserExtensionsRequest) (*UpdateUserExtensionsResponse, error) {
|
||||||
|
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/extensions"})
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
} else {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPatch, endpoint.String(), r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data UpdateUserExtensionsResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Users struct {
|
||||||
|
client *http.Client
|
||||||
|
baseUrl *url.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(client *http.Client, baseUrl *url.URL) *Users {
|
||||||
|
return &Users{
|
||||||
|
client: client,
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue