Skip to content

Commit

Permalink
add helix tags & search API methods
Browse files Browse the repository at this point in the history
  • Loading branch information
d-fischer committed Nov 16, 2020
1 parent 474e9fe commit 6021b7e
Show file tree
Hide file tree
Showing 9 changed files with 443 additions and 4 deletions.
6 changes: 4 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const memberNames = [
'^click_action$',
'^(image_)?url_\\dx$',
'^emoticon_sets?$',
'^is_(anonymous|gift|user_input_required|sub_only|enabled|paused|in_stock|previewable|playlist|(verified|known)_bot)$',
'^is_(anonymous|gift|user_input_required|sub_only|enabled|paused|in_stock|previewable|playlist|(verified|known)_bot|live|auto)$',
'^minimum_allowed_role$',
'^(chatter|view(er)?)_count$',
'^min_bits$',
Expand Down Expand Up @@ -58,10 +58,12 @@ const memberNames = [
'^average_fps$',
'^description_html$',
'^muted_segments$',
'^tag_list$',
'^tag_(ids|list)$',
'^cooldown_end_time$',
'^(last|top)_contributions?$',
'^(streak|cumulative)_months',
'^live_only$',
'^localization_(names|descriptions)',
// HTTP
'^Accept$'
];
Expand Down
2 changes: 1 addition & 1 deletion packages/twitch/src/API/Helix/Channel/HelixChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class HelixChannel {
}

/**
* Retrieves information about the game that is being played on this stream.
* Retrieves information about the game that is being played on the stream.
*/
async getGame(): Promise<HelixGame | null> {
return this._client.helix.games.getGameById(this._data.game_id);
Expand Down
9 changes: 9 additions & 0 deletions packages/twitch/src/API/Helix/HelixApiGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import HelixHypeTrainApi from './HypeTrain/HelixHypeTrainApi';
import { HelixModerationApi } from './Moderation/HelixModerationApi';
import { HelixStreamApi } from './Stream/HelixStreamApi';
import { HelixSubscriptionApi } from './Subscriptions/HelixSubscriptionApi';
import { HelixTagApi } from './Tag/HelixTagApi';
import { HelixUserApi } from './User/HelixUserApi';
import { HelixVideoApi } from './Video/HelixVideoApi';
import { HelixWebHooksApi } from './WebHooks/HelixWebHooksApi';
Expand Down Expand Up @@ -93,6 +94,14 @@ export class HelixApiGroup extends BaseApi {
return new HelixSubscriptionApi(this._client);
}

/**
* The Helix tag API methods.
*/
@CachedGetter()
get tags(): HelixTagApi {
return new HelixTagApi(this._client);
}

/**
* The Helix user API methods.
*/
Expand Down
108 changes: 108 additions & 0 deletions packages/twitch/src/API/Helix/Search/HelixChannelSearchResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Enumerable } from '@d-fischer/shared-utils';
import type { ApiClient } from '../../../ApiClient';
import type { HelixGame } from '../Game/HelixGame';
import type { HelixTag } from '../Tag/HelixTag';
import type { HelixUser } from '../User/HelixUser';

/** @private */
export interface HelixChannelSearchResultData {
broadcaster_language: string;
display_name: string;
game_id: string;
id: string;
is_live: boolean;
tag_ids: string[];
thumbnail_url: string;
title: string;
started_at: string;
}

/**
* The result of a channel search.
*/
export class HelixChannelSearchResult {
/** @private */
@Enumerable(false) protected readonly _client: ApiClient;

/** @private */
constructor(/** @private */ protected _data: HelixChannelSearchResultData, client: ApiClient) {
this._client = client;
}

/**
* The language of the channel.
*/
get language(): string {
return this._data.broadcaster_language;
}

/**
* The ID of the channel.
*/
get id(): string {
return this._data.id;
}

/**
* Retrieves additional information about the owner of the channel.
*/
async getUser(): Promise<HelixUser | null> {
return this._client.helix.users.getUserById(this._data.id);
}

/**
* The display name of the channel
*/
get displayName(): string {
return this._data.display_name;
}

/**
* The ID of the game currently played on the channel.
*/
get gameId(): string {
return this._data.game_id;
}

/**
* Retrieves information about the game that is being played on the stream.
*/
async getGame(): Promise<HelixGame | null> {
return this._client.helix.games.getGameById(this._data.game_id);
}

/**
* Whether the channel is currently live.
*/
get isLive(): boolean {
return this._data.is_live;
}

/**
* The IDs of the tags set on the channel.
*/
get tagIds(): string[] {
return this._data.tag_ids;
}

/**
* Retrieves the tags of the channel.
*/
async getTags(): Promise<HelixTag[]> {
return this._client.helix.tags.getStreamTagsByIds(this._data.tag_ids);
}

/**
* The thumbnail URL of the stream.
*/
get thumbnailUrl(): string {
return this._data.thumbnail_url;
}

/**
* The start date of the stream. Returns `null` if the stream is not live.
*/
get startDate(): Date | null {
return this._data.is_live ? new Date(this._data.started_at) : null;
}
}
130 changes: 130 additions & 0 deletions packages/twitch/src/API/Helix/Search/HelixSearchApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { TwitchApiCallType } from 'twitch-api-call';
import { BaseApi } from '../../BaseApi';
import type { HelixGameData } from '../Game/HelixGame';
import { HelixGame } from '../Game/HelixGame';
import { HelixPaginatedRequest } from '../HelixPaginatedRequest';
import type { HelixPaginatedResult } from '../HelixPaginatedResult';
import { createPaginatedResult } from '../HelixPaginatedResult';
import type { HelixForwardPagination } from '../HelixPagination';
import { makePaginationQuery } from '../HelixPagination';
import type { HelixPaginatedResponse } from '../HelixResponse';
import { HelixUser } from '../User/HelixUser';
import type { HelixUserData } from '../User/HelixUser';

/**
* Filters for a channel search.
*/
export interface HelixChannelSearchFilter {
/**
* Include only channels that are currently live.
*/
liveOnly?: boolean;
}

/** @inheritDoc */
export interface HelixPaginatedChannelSearchFilter extends HelixChannelSearchFilter, HelixForwardPagination {}

/**
* The Helix API methods that run searches.
*
* Can be accessed using `client.helix.search` on an {@ApiClient} instance.
*
* ## Example
* ```ts
* const api = new ApiClient(new StaticAuthProvider(clientId, accessToken));
* const channels = await api.helix.search.searchChannels('pear');
* ```
*/
export class HelixSearchApi extends BaseApi {
/**
* Search categories/games for an exact or partial match.
*
* @param query The search term.
* @param pagination
*
* @expandParams
*/
async searchCategories(
query: string,
pagination: HelixForwardPagination = {}
): Promise<HelixPaginatedResult<HelixGame>> {
const result = await this._client.callApi<HelixPaginatedResponse<HelixGameData>>({
type: TwitchApiCallType.Helix,
url: 'search/categories',
query: {
query,
...makePaginationQuery(pagination)
}
});

return createPaginatedResult(result, HelixGame, this._client);
}

/**
* Creates a paginator for a category/game search.
*
* @param query The search term.
*/
searchCategoriesPaginated(query: string): HelixPaginatedRequest<HelixGameData, HelixGame> {
return new HelixPaginatedRequest<HelixGameData, HelixGame>(
{
url: 'search/categories',
query: {
query
}
},
this._client,
data => new HelixGame(data, this._client)
);
}

/**
* Search channels for an exact or partial match.
*
* @param query The search term.
* @param filter
*
* @expandParams
*/
async searchChannels(
query: string,
filter: HelixPaginatedChannelSearchFilter = {}
): Promise<HelixPaginatedResult<HelixUser>> {
const result = await this._client.callApi<HelixPaginatedResponse<HelixUserData>>({
type: TwitchApiCallType.Helix,
url: 'search/channels',
query: {
query,
live_only: filter.liveOnly?.toString(),
...makePaginationQuery(filter)
}
});

return createPaginatedResult(result, HelixUser, this._client);
}

/**
* Creates a paginator for a channel search.
*
* @param query The search term.
* @param filter
*
* @expandParams
*/
searchChannelsPaginated(
query: string,
filter: HelixChannelSearchFilter = {}
): HelixPaginatedRequest<HelixUserData, HelixUser> {
return new HelixPaginatedRequest<HelixUserData, HelixUser>(
{
url: 'search/channels',
query: {
query,
live_only: filter.liveOnly?.toString()
}
},
this._client,
data => new HelixUser(data, this._client)
);
}
}
18 changes: 17 additions & 1 deletion packages/twitch/src/API/Helix/Stream/HelixStream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Enumerable } from '@d-fischer/shared-utils';
import type { ApiClient } from '../../../ApiClient';
import type { HelixGame } from '../Game/HelixGame';
import type { HelixTag } from '../Tag/HelixTag';
import type { HelixUser } from '../User/HelixUser';

/**
Expand Down Expand Up @@ -38,6 +39,7 @@ export interface HelixStreamData {
started_at: string;
language: string;
thumbnail_url: string;
tag_ids: string[];
}

/**
Expand Down Expand Up @@ -87,7 +89,7 @@ export class HelixStream {
}

/**
* Retrieves information about the game that is being played on this stream.
* Retrieves information about the game that is being played on the stream.
*/
async getGame(): Promise<HelixGame | null> {
return this._client.helix.games.getGameById(this._data.game_id);
Expand Down Expand Up @@ -134,4 +136,18 @@ export class HelixStream {
get thumbnailUrl(): string {
return this._data.thumbnail_url;
}

/**
* The IDs of the tags of the stream.
*/
get tagIds(): string[] {
return this._data.tag_ids;
}

/**
* Retrieves the tags of the stream.
*/
async getTags(): Promise<HelixTag[]> {
return this._client.helix.tags.getStreamTagsByIds(this._data.tag_ids);
}
}
40 changes: 40 additions & 0 deletions packages/twitch/src/API/Helix/Stream/HelixStreamApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { createPaginatedResult } from '../HelixPaginatedResult';
import type { HelixPagination } from '../HelixPagination';
import { makePaginationQuery } from '../HelixPagination';
import type { HelixPaginatedResponse, HelixResponse } from '../HelixResponse';
import type { HelixTagData } from '../Tag/HelixTag';
import { HelixTag } from '../Tag/HelixTag';
import type { HelixStreamData, HelixStreamType } from './HelixStream';
import { HelixStream } from './HelixStream';
import type { HelixStreamMarkerData } from './HelixStreamMarker';
Expand Down Expand Up @@ -222,6 +224,44 @@ export class HelixStreamApi extends BaseApi {
}
}

/**
* Retrieves the tags of a stream.
*
* @param broadcaster The broadcaster of the stream.
*/
async getStreamTags(broadcaster: UserIdResolvable): Promise<HelixTag[]> {
const result = await this._client.callApi<HelixResponse<HelixTagData>>({
type: TwitchApiCallType.Helix,
url: 'streams/tags',
query: {
broadcaster_id: extractUserId(broadcaster)
}
});

return result.data.map(data => new HelixTag(data, this._client));
}

/**
* Replaces the tags of a stream.
*
* @param broadcaster The broadcaster of the stream.
* @param tagIds The tags to set. If not given, removes all tags.
*/
async replaceStreamTags(broadcaster: UserIdResolvable, tagIds?: string[]): Promise<void> {
await this._client.callApi({
type: TwitchApiCallType.Helix,
url: 'streams/tags',
scope: 'user:edit:broadcast',
method: 'PUT',
query: {
broadcaster: extractUserId(broadcaster)
},
jsonBody: {
tag_ids: tagIds
}
});
}

private async _getStreamMarkers(
queryType: string,
id: string
Expand Down

0 comments on commit 6021b7e

Please sign in to comment.