stophy 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/dist/index.cjs +73 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1203 -377
- package/dist/index.d.ts +1203 -377
- package/dist/index.js +73 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -6,7 +6,7 @@ type ErrorResponse = {
|
|
|
6
6
|
*/
|
|
7
7
|
success: false;
|
|
8
8
|
/**
|
|
9
|
-
* Machine-readable error code.
|
|
9
|
+
* Machine-readable error code. `UPSTREAM_UNAVAILABLE` indicates the upstream YouTube/Innertube endpoint could not be reached or is currently blocked.
|
|
10
10
|
*/
|
|
11
11
|
code?: "UNAUTHORIZED" | "INSUFFICIENT_CREDITS" | "BAD_REQUEST" | "INVALID_INPUT" | "NOT_FOUND" | "CONCURRENCY_LIMITED" | "UPSTREAM_UNAVAILABLE" | "INTERNAL_ERROR";
|
|
12
12
|
/**
|
|
@@ -23,70 +23,96 @@ type Thumbnail = {
|
|
|
23
23
|
width: number;
|
|
24
24
|
height: number;
|
|
25
25
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
/**
|
|
27
|
+
* An MCP tool exposed by the Stophy MCP server.
|
|
28
|
+
*/
|
|
29
|
+
type McpTool = {
|
|
30
|
+
name?: "stophy_search_videos" | "stophy_get_video" | "stophy_get_channel" | "stophy_get_playlist" | "stophy_get_suggestions" | "stophy_music" | "stophy_kids" | "stophy_get_credits";
|
|
31
|
+
description?: string;
|
|
32
|
+
inputSchema?: {
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
};
|
|
34
35
|
};
|
|
35
|
-
type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
type VideoRequestVideoOp = {
|
|
37
|
+
type: "details" | "transcript" | "comments" | "livechat";
|
|
38
|
+
videoUrl: string;
|
|
39
|
+
/**
|
|
40
|
+
* Comment sort order: any (YouTube's default ordering), top, or latest. Only applies when type is 'comments'. Defaults to any.
|
|
41
|
+
*/
|
|
42
|
+
sortBy?: "any" | "top" | "latest";
|
|
43
|
+
chatType?: "top" | "live";
|
|
44
|
+
/**
|
|
45
|
+
* Preferred transcript language code. Only applies when type is transcript.
|
|
46
|
+
*/
|
|
47
|
+
lang?: string;
|
|
48
|
+
continuationToken?: string;
|
|
39
49
|
};
|
|
40
|
-
type
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
text: string;
|
|
44
|
-
empty?: EmptyState;
|
|
50
|
+
type VideoRequestReplies = {
|
|
51
|
+
type: "replies";
|
|
52
|
+
continuationToken: string;
|
|
45
53
|
};
|
|
46
|
-
type
|
|
47
|
-
|
|
54
|
+
type VideoDetail = {
|
|
55
|
+
/**
|
|
56
|
+
* Item type discriminator. Always `video` for this schema.
|
|
57
|
+
*/
|
|
48
58
|
type: "video";
|
|
59
|
+
id: string;
|
|
60
|
+
/**
|
|
61
|
+
* Canonical URL alias for the item.
|
|
62
|
+
*/
|
|
63
|
+
url: string;
|
|
49
64
|
videoUrl: string;
|
|
50
|
-
title: string
|
|
65
|
+
title: string;
|
|
51
66
|
author: string | null;
|
|
52
67
|
authorId: string | null;
|
|
53
|
-
category: string | null;
|
|
54
68
|
description: string | null;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
isLive: boolean;
|
|
69
|
+
viewCount: number | null;
|
|
70
|
+
viewCountText: string | null;
|
|
58
71
|
likeCount: number | null;
|
|
59
72
|
likeCountText: string | null;
|
|
73
|
+
durationSec: number | null;
|
|
74
|
+
durationText: string | null;
|
|
60
75
|
publishedAt: string | null;
|
|
61
76
|
tags: Array<string>;
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
chapters: Array<{
|
|
78
|
+
title: string;
|
|
79
|
+
startMs: number;
|
|
80
|
+
startSec: number;
|
|
81
|
+
}>;
|
|
82
|
+
isLive: boolean;
|
|
83
|
+
category: string | null;
|
|
64
84
|
thumbnails: Array<Thumbnail>;
|
|
65
85
|
};
|
|
66
86
|
type RelatedVideo = {
|
|
67
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Item type discriminator. Always `video` for this schema.
|
|
89
|
+
*/
|
|
68
90
|
type: "video";
|
|
91
|
+
id: string;
|
|
92
|
+
/**
|
|
93
|
+
* Canonical URL alias for the item.
|
|
94
|
+
*/
|
|
95
|
+
url: string;
|
|
69
96
|
videoUrl: string;
|
|
70
97
|
title: string | null;
|
|
71
98
|
author: string | null;
|
|
72
99
|
authorId: string | null;
|
|
100
|
+
viewCount: number | null;
|
|
101
|
+
viewCountText: string | null;
|
|
73
102
|
durationSec: number | null;
|
|
74
103
|
durationText: string | null;
|
|
75
104
|
publishedAt: string | null;
|
|
76
105
|
publishedAtText: string | null;
|
|
77
|
-
viewCount: number | null;
|
|
78
|
-
viewCountText: string | null;
|
|
79
106
|
thumbnails: Array<Thumbnail>;
|
|
80
107
|
};
|
|
81
|
-
type VideoDetailsData = {
|
|
82
|
-
video: VideoDetails;
|
|
83
|
-
related: Array<RelatedVideo>;
|
|
84
|
-
};
|
|
85
108
|
type Comment = {
|
|
86
|
-
id: string
|
|
87
|
-
text: string
|
|
109
|
+
id: string;
|
|
110
|
+
text: string;
|
|
88
111
|
author: string | null;
|
|
89
112
|
authorId: string | null;
|
|
113
|
+
/**
|
|
114
|
+
* URL of the commenter’s channel avatar. Plain string URL, not an object.
|
|
115
|
+
*/
|
|
90
116
|
authorThumbnail: string | null;
|
|
91
117
|
hasChannelOwnerReplied: boolean;
|
|
92
118
|
isChannelOwner: boolean;
|
|
@@ -99,314 +125,376 @@ type Comment = {
|
|
|
99
125
|
likeCountText: string | null;
|
|
100
126
|
replyCount: number | null;
|
|
101
127
|
replyCountText: string | null;
|
|
102
|
-
repliesToken: string | null;
|
|
103
|
-
};
|
|
104
|
-
type CommentsData = {
|
|
105
128
|
/**
|
|
106
|
-
*
|
|
129
|
+
* Token to fetch replies via type=replies.
|
|
107
130
|
*/
|
|
108
|
-
|
|
131
|
+
repliesToken: string | null;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Returned when type is 'details'.
|
|
135
|
+
*/
|
|
136
|
+
type VideoResponseDetails = {
|
|
137
|
+
videoId: string;
|
|
138
|
+
video: VideoDetail;
|
|
139
|
+
related: Array<RelatedVideo>;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Returned when type is 'transcript'.
|
|
143
|
+
*/
|
|
144
|
+
type VideoResponseTranscript = {
|
|
145
|
+
videoId: string;
|
|
146
|
+
language: {
|
|
147
|
+
code: string | null;
|
|
148
|
+
name: string | null;
|
|
149
|
+
isAutoGenerated: boolean;
|
|
150
|
+
};
|
|
151
|
+
isTranslated: boolean;
|
|
152
|
+
availableTracks: Array<{
|
|
153
|
+
languageCode: string;
|
|
154
|
+
languageName: string;
|
|
155
|
+
isAutoGenerated: boolean;
|
|
156
|
+
}>;
|
|
157
|
+
segments: Array<{
|
|
158
|
+
text: string;
|
|
159
|
+
/**
|
|
160
|
+
* Start time in seconds.
|
|
161
|
+
*/
|
|
162
|
+
start: number;
|
|
163
|
+
/**
|
|
164
|
+
* Duration in seconds.
|
|
165
|
+
*/
|
|
166
|
+
duration: number;
|
|
167
|
+
}>;
|
|
109
168
|
/**
|
|
110
|
-
*
|
|
169
|
+
* Concatenated transcript text.
|
|
111
170
|
*/
|
|
112
|
-
|
|
171
|
+
text: string;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Returned when type is 'comments'.
|
|
175
|
+
*/
|
|
176
|
+
type VideoResponseComments = {
|
|
177
|
+
videoId: string;
|
|
178
|
+
sortBy: "any" | "top" | "latest";
|
|
113
179
|
items: Array<Comment>;
|
|
114
180
|
continuationToken: string | null;
|
|
115
|
-
|
|
181
|
+
hasMore: boolean;
|
|
116
182
|
};
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
isModerator: boolean;
|
|
125
|
-
isVerified: boolean;
|
|
126
|
-
superChatAmount: string | null;
|
|
127
|
-
superChatCurrency: string | null;
|
|
183
|
+
/**
|
|
184
|
+
* Returned when type is 'replies'. Note: no videoId/sortBy; the parent video is implied. Reply items have no replyCount/replyCountText/repliesToken since replies cannot be threaded.
|
|
185
|
+
*/
|
|
186
|
+
type VideoResponseReplies = {
|
|
187
|
+
items: Array<Reply>;
|
|
188
|
+
continuationToken: string | null;
|
|
189
|
+
hasMore: boolean;
|
|
128
190
|
};
|
|
129
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Returned when type is 'livechat'.
|
|
193
|
+
*/
|
|
194
|
+
type VideoResponseLivechat = {
|
|
195
|
+
/**
|
|
196
|
+
* The YouTube video ID this live chat belongs to. Mirrors the `videoUrl` from the request.
|
|
197
|
+
*/
|
|
198
|
+
videoId: string;
|
|
130
199
|
status: "live" | "upcoming" | "replay" | "chat_disabled" | "not_live";
|
|
131
200
|
isLive: boolean;
|
|
132
201
|
concurrentViewers: number | null;
|
|
202
|
+
/**
|
|
203
|
+
* Suggested delay before next poll.
|
|
204
|
+
*/
|
|
133
205
|
pollIntervalMs: number | null;
|
|
134
|
-
messages: Array<
|
|
206
|
+
messages: Array<{
|
|
207
|
+
id: string;
|
|
208
|
+
text: string;
|
|
209
|
+
author: string | null;
|
|
210
|
+
authorId: string | null;
|
|
211
|
+
/**
|
|
212
|
+
* Message timestamp in microseconds.
|
|
213
|
+
*/
|
|
214
|
+
timestampUsec: string | null;
|
|
215
|
+
isOwner: boolean;
|
|
216
|
+
isModerator: boolean;
|
|
217
|
+
isVerified: boolean;
|
|
218
|
+
superChatAmount: string | null;
|
|
219
|
+
superChatCurrency: string | null;
|
|
220
|
+
}>;
|
|
135
221
|
continuationToken: string | null;
|
|
222
|
+
hasMore: boolean;
|
|
223
|
+
};
|
|
224
|
+
type EmptyState = {
|
|
225
|
+
code: string;
|
|
226
|
+
message: string;
|
|
227
|
+
};
|
|
228
|
+
type MusicArtistRef = {
|
|
229
|
+
id: string | null;
|
|
230
|
+
name: string;
|
|
231
|
+
};
|
|
232
|
+
type MusicAlbumRef = {
|
|
233
|
+
id: string | null;
|
|
234
|
+
name: string;
|
|
136
235
|
};
|
|
137
236
|
/**
|
|
138
|
-
*
|
|
237
|
+
* YouTube Music result item. URL fields are populated only when YouTube returns the matching identifier for that item type.
|
|
139
238
|
*/
|
|
140
|
-
type
|
|
141
|
-
type
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
videoUrl
|
|
239
|
+
type MusicItem = {
|
|
240
|
+
type: "song" | "video" | "album" | "artist" | "playlist" | "podcast" | "episode" | "profile";
|
|
241
|
+
id: string | null;
|
|
242
|
+
url: string | null;
|
|
243
|
+
videoUrl?: string | null;
|
|
244
|
+
playlistUrl?: string | null;
|
|
245
|
+
channelUrl?: string | null;
|
|
246
|
+
albumUrl?: string | null;
|
|
247
|
+
artistUrl?: string | null;
|
|
145
248
|
title: string;
|
|
146
249
|
author: string | null;
|
|
147
250
|
authorId: string | null;
|
|
148
|
-
|
|
251
|
+
album: MusicAlbumRef | null;
|
|
252
|
+
artists: Array<MusicArtistRef>;
|
|
149
253
|
duration: string | null;
|
|
150
254
|
durationSec: number | null;
|
|
151
255
|
durationText: string | null;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
isVerified: boolean;
|
|
155
|
-
viewCount: number | null;
|
|
156
|
-
viewCountText: string | null;
|
|
157
|
-
publishedAt: string | null;
|
|
158
|
-
publishedAtText: string | null;
|
|
256
|
+
isExplicit: boolean;
|
|
257
|
+
plays: string | null;
|
|
159
258
|
thumbnails: Array<Thumbnail>;
|
|
160
259
|
};
|
|
161
|
-
type
|
|
162
|
-
type: "short";
|
|
260
|
+
type MusicSong = {
|
|
163
261
|
id: string;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
viewCount: number | null;
|
|
167
|
-
viewCountText: string | null;
|
|
168
|
-
thumbnails: Array<Thumbnail>;
|
|
169
|
-
};
|
|
170
|
-
type SearchPlaylist = {
|
|
171
|
-
type: "playlist";
|
|
172
|
-
id: string;
|
|
173
|
-
playlistUrl: string;
|
|
262
|
+
url: string;
|
|
263
|
+
videoUrl: string;
|
|
174
264
|
title: string;
|
|
175
265
|
author: string | null;
|
|
176
266
|
authorId: string | null;
|
|
177
|
-
|
|
178
|
-
|
|
267
|
+
album: MusicAlbumRef | null;
|
|
268
|
+
artists: Array<MusicArtistRef>;
|
|
269
|
+
duration: string | null;
|
|
270
|
+
durationSec: number | null;
|
|
271
|
+
durationText: string | null;
|
|
272
|
+
isExplicit: boolean;
|
|
273
|
+
lyricsBrowseId: string | null;
|
|
274
|
+
relatedBrowseId: string | null;
|
|
179
275
|
thumbnails: Array<Thumbnail>;
|
|
180
276
|
};
|
|
181
|
-
type
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
subscriberCountText: string | null;
|
|
190
|
-
isVerified: boolean;
|
|
191
|
-
thumbnails: Array<Thumbnail>;
|
|
277
|
+
type MusicSearchData = {
|
|
278
|
+
items: Array<MusicItem>;
|
|
279
|
+
continuationToken: string | null;
|
|
280
|
+
hasMore: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Present only when the operation yields no results.
|
|
283
|
+
*/
|
|
284
|
+
empty?: EmptyState | null;
|
|
192
285
|
};
|
|
193
|
-
type
|
|
194
|
-
type?: "video";
|
|
195
|
-
} & SearchVideo) | ({
|
|
196
|
-
type?: "short";
|
|
197
|
-
} & SearchShort) | ({
|
|
198
|
-
type?: "playlist";
|
|
199
|
-
} & SearchPlaylist) | ({
|
|
200
|
-
type?: "channel";
|
|
201
|
-
} & SearchChannel);
|
|
202
|
-
type SearchQuery = {
|
|
286
|
+
type MusicSuggestData = {
|
|
203
287
|
q: string;
|
|
204
|
-
|
|
205
|
-
sortBy?: "relevance" | "popularity" | "date" | "rating";
|
|
206
|
-
uploadDate?: "today" | "week" | "month" | "year";
|
|
207
|
-
duration?: "short" | "medium" | "long";
|
|
208
|
-
features?: Array<string>;
|
|
209
|
-
};
|
|
210
|
-
type SearchData = {
|
|
211
|
-
query: SearchQuery;
|
|
212
|
-
items: Array<SearchItem>;
|
|
213
|
-
continuationToken: string | null;
|
|
214
|
-
estimatedResults?: number;
|
|
215
|
-
empty?: EmptyState;
|
|
288
|
+
suggestions: Array<string>;
|
|
216
289
|
};
|
|
217
|
-
type
|
|
218
|
-
|
|
219
|
-
|
|
290
|
+
type MusicSongData = {
|
|
291
|
+
song: MusicSong;
|
|
292
|
+
} | {
|
|
293
|
+
empty: EmptyState;
|
|
220
294
|
};
|
|
221
|
-
type
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
viewCount?: number | null;
|
|
232
|
-
viewCountText?: string | null;
|
|
233
|
-
isVerified: boolean;
|
|
234
|
-
country?: string | null;
|
|
235
|
-
joinedDate?: string | null;
|
|
236
|
-
thumbnails: Array<Thumbnail>;
|
|
237
|
-
banners: Array<Thumbnail>;
|
|
238
|
-
links?: Array<ChannelLink> | null;
|
|
295
|
+
type MusicLyricsData = {
|
|
296
|
+
videoId: string;
|
|
297
|
+
videoUrl: string;
|
|
298
|
+
lyrics: string | null;
|
|
299
|
+
source: string | null;
|
|
300
|
+
hasTimedLyrics: boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Present only when the operation yields no results.
|
|
303
|
+
*/
|
|
304
|
+
empty?: EmptyState | null;
|
|
239
305
|
};
|
|
240
|
-
type
|
|
241
|
-
|
|
306
|
+
type MusicAlbumData = {
|
|
307
|
+
album: {
|
|
308
|
+
id: string;
|
|
309
|
+
url: string | null;
|
|
310
|
+
albumUrl: string | null;
|
|
311
|
+
title: string;
|
|
312
|
+
artists: Array<MusicArtistRef>;
|
|
313
|
+
year: string | null;
|
|
314
|
+
trackCountText: string | null;
|
|
315
|
+
durationText: string | null;
|
|
316
|
+
thumbnails: Array<Thumbnail>;
|
|
317
|
+
};
|
|
318
|
+
items: Array<MusicItem>;
|
|
319
|
+
/**
|
|
320
|
+
* Present only when the operation yields no results.
|
|
321
|
+
*/
|
|
322
|
+
empty?: EmptyState | null;
|
|
323
|
+
};
|
|
324
|
+
type MusicArtistData = {
|
|
325
|
+
artist: {
|
|
326
|
+
id: string | null;
|
|
327
|
+
url: string | null;
|
|
328
|
+
channelUrl: string | null;
|
|
329
|
+
name: string;
|
|
330
|
+
description: string | null;
|
|
331
|
+
subscriberText: string | null;
|
|
332
|
+
thumbnails: Array<Thumbnail>;
|
|
333
|
+
};
|
|
334
|
+
sections: Array<{
|
|
335
|
+
title: string;
|
|
336
|
+
items: Array<{
|
|
337
|
+
id: string | null;
|
|
338
|
+
url: string | null;
|
|
339
|
+
videoUrl?: string;
|
|
340
|
+
channelUrl?: string;
|
|
341
|
+
kind: "watch" | "browse";
|
|
342
|
+
title: string;
|
|
343
|
+
subtitle: string | null;
|
|
344
|
+
thumbnails: Array<Thumbnail>;
|
|
345
|
+
}>;
|
|
346
|
+
}>;
|
|
347
|
+
/**
|
|
348
|
+
* Present only when the operation yields no results.
|
|
349
|
+
*/
|
|
350
|
+
empty?: EmptyState | null;
|
|
351
|
+
};
|
|
352
|
+
type MusicPlaylistData = {
|
|
353
|
+
playlist: {
|
|
354
|
+
id: string | null;
|
|
355
|
+
url: string | null;
|
|
356
|
+
playlistUrl: string | null;
|
|
357
|
+
title: string;
|
|
358
|
+
subtitle: string | null;
|
|
359
|
+
trackCountText: string | null;
|
|
360
|
+
durationText: string | null;
|
|
361
|
+
thumbnails: Array<Thumbnail>;
|
|
362
|
+
};
|
|
363
|
+
items: Array<MusicItem>;
|
|
364
|
+
continuationToken: string | null;
|
|
365
|
+
hasMore: boolean;
|
|
366
|
+
/**
|
|
367
|
+
* Present only when the operation yields no results.
|
|
368
|
+
*/
|
|
369
|
+
empty?: EmptyState | null;
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* Response payload varies by request `type`.
|
|
373
|
+
*/
|
|
374
|
+
type MusicResponseData = MusicSearchData | MusicSuggestData | MusicSongData | MusicLyricsData | MusicAlbumData | MusicArtistData | MusicPlaylistData;
|
|
375
|
+
type KidsVideoItem = {
|
|
242
376
|
type: "video";
|
|
243
|
-
|
|
377
|
+
id: string;
|
|
378
|
+
url: string;
|
|
244
379
|
videoUrl: string;
|
|
380
|
+
kidsUrl: string;
|
|
381
|
+
title: string;
|
|
245
382
|
author: string | null;
|
|
246
383
|
authorId: string | null;
|
|
384
|
+
authorUrl: string | null;
|
|
247
385
|
duration: string | null;
|
|
248
386
|
durationSec: number | null;
|
|
249
387
|
durationText: string | null;
|
|
250
|
-
isLive: boolean;
|
|
251
|
-
isUpcoming: boolean;
|
|
252
|
-
upcomingAt: string | null;
|
|
253
|
-
viewCount: number | null;
|
|
254
|
-
viewCountText: string | null;
|
|
255
388
|
publishedAt: string | null;
|
|
256
389
|
publishedAtText: string | null;
|
|
257
|
-
thumbnails: Array<Thumbnail>;
|
|
258
|
-
};
|
|
259
|
-
type ChannelShort = {
|
|
260
|
-
id: string;
|
|
261
|
-
type: "short";
|
|
262
|
-
shortUrl: string;
|
|
263
|
-
title: string | null;
|
|
264
|
-
author: string | null;
|
|
265
|
-
authorId: string | null;
|
|
266
390
|
viewCount: number | null;
|
|
267
391
|
viewCountText: string | null;
|
|
268
392
|
thumbnails: Array<Thumbnail>;
|
|
269
393
|
};
|
|
270
|
-
type
|
|
271
|
-
id: string;
|
|
272
|
-
type: "playlist";
|
|
273
|
-
playlistUrl: string;
|
|
274
|
-
title: string | null;
|
|
275
|
-
author: string | null;
|
|
276
|
-
authorId: string | null;
|
|
277
|
-
videoCount: string | null;
|
|
278
|
-
thumbnails: Array<Thumbnail>;
|
|
279
|
-
};
|
|
280
|
-
type ContentItem = ({
|
|
281
|
-
type?: "video";
|
|
282
|
-
} & ChannelVideo) | ({
|
|
283
|
-
type?: "short";
|
|
284
|
-
} & ChannelShort) | ({
|
|
285
|
-
type?: "playlist";
|
|
286
|
-
} & ChannelPlaylist);
|
|
287
|
-
type ChannelData = {
|
|
288
|
-
channel: ChannelProfile | null;
|
|
289
|
-
tab: "video" | "short" | "playlist" | "about";
|
|
290
|
-
items?: Array<ContentItem>;
|
|
291
|
-
continuationToken?: string | null;
|
|
292
|
-
empty?: EmptyState;
|
|
293
|
-
};
|
|
294
|
-
type PlaylistMeta = {
|
|
295
|
-
id: string;
|
|
296
|
-
type: "playlist";
|
|
297
|
-
playlistUrl: string;
|
|
298
|
-
title: string | null;
|
|
299
|
-
author: string | null;
|
|
300
|
-
authorId: string | null;
|
|
301
|
-
description: string | null;
|
|
302
|
-
videoCount: string | null;
|
|
303
|
-
thumbnails: Array<Thumbnail>;
|
|
304
|
-
};
|
|
305
|
-
type PlaylistItem = {
|
|
306
|
-
id: string;
|
|
394
|
+
type KidsVideoDetails = {
|
|
307
395
|
type: "video";
|
|
396
|
+
id: string;
|
|
397
|
+
url: string;
|
|
308
398
|
videoUrl: string;
|
|
309
|
-
|
|
399
|
+
kidsUrl: string;
|
|
400
|
+
title: string;
|
|
310
401
|
author: string | null;
|
|
311
402
|
authorId: string | null;
|
|
403
|
+
authorUrl: string | null;
|
|
404
|
+
description: string | null;
|
|
312
405
|
duration: string | null;
|
|
313
406
|
durationSec: number | null;
|
|
314
407
|
durationText: string | null;
|
|
315
|
-
index: number | null;
|
|
316
408
|
isLive: boolean;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
upcomingAt: string | null;
|
|
409
|
+
isLiveContent: boolean;
|
|
410
|
+
keywords: Array<string>;
|
|
320
411
|
viewCount: number | null;
|
|
321
412
|
viewCountText: string | null;
|
|
322
|
-
publishedAt: string | null;
|
|
323
|
-
publishedAtText: string | null;
|
|
324
413
|
thumbnails: Array<Thumbnail>;
|
|
325
414
|
};
|
|
326
|
-
type
|
|
327
|
-
|
|
328
|
-
items: Array<PlaylistItem>;
|
|
415
|
+
type KidsSearchData = {
|
|
416
|
+
items: Array<KidsVideoItem>;
|
|
329
417
|
continuationToken: string | null;
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
gl: string;
|
|
336
|
-
suggestions: Array<string>;
|
|
418
|
+
hasMore: boolean;
|
|
419
|
+
/**
|
|
420
|
+
* Present only when the operation yields no results.
|
|
421
|
+
*/
|
|
422
|
+
empty?: EmptyState | null;
|
|
337
423
|
};
|
|
338
|
-
type
|
|
339
|
-
|
|
424
|
+
type KidsVideoData = {
|
|
425
|
+
video: KidsVideoDetails;
|
|
426
|
+
related: Array<KidsVideoItem>;
|
|
427
|
+
} | {
|
|
428
|
+
empty: EmptyState;
|
|
340
429
|
};
|
|
341
|
-
|
|
430
|
+
/**
|
|
431
|
+
* Response payload varies by request `type`.
|
|
432
|
+
*/
|
|
433
|
+
type KidsResponseData = KidsSearchData | KidsVideoData;
|
|
434
|
+
/**
|
|
435
|
+
* A reply to a comment. Replies cannot be threaded, so there are no reply-count or repliesToken fields.
|
|
436
|
+
*/
|
|
437
|
+
type Reply = {
|
|
342
438
|
id: string;
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
totalPages: number;
|
|
360
|
-
endpoints: Array<string>;
|
|
361
|
-
};
|
|
362
|
-
type UsageItem = {
|
|
363
|
-
date: string;
|
|
364
|
-
credits: number;
|
|
365
|
-
requests: number;
|
|
366
|
-
};
|
|
367
|
-
type UsageData = {
|
|
368
|
-
items: Array<UsageItem>;
|
|
439
|
+
text: string;
|
|
440
|
+
author: string | null;
|
|
441
|
+
authorId: string | null;
|
|
442
|
+
/**
|
|
443
|
+
* URL of the commenter’s channel avatar. Plain string URL, not an object.
|
|
444
|
+
*/
|
|
445
|
+
authorThumbnail: string | null;
|
|
446
|
+
hasChannelOwnerReplied: boolean;
|
|
447
|
+
isChannelOwner: boolean;
|
|
448
|
+
isHearted: boolean;
|
|
449
|
+
isPinned: boolean;
|
|
450
|
+
isVerified: boolean;
|
|
451
|
+
publishedAt: string | null;
|
|
452
|
+
publishedAtText: string | null;
|
|
453
|
+
likeCount: number | null;
|
|
454
|
+
likeCountText: string | null;
|
|
369
455
|
};
|
|
370
|
-
type
|
|
456
|
+
type SearchVideosData = {
|
|
371
457
|
body: {
|
|
372
458
|
/**
|
|
373
|
-
*
|
|
459
|
+
* Search query.
|
|
374
460
|
*/
|
|
375
|
-
|
|
461
|
+
q: string;
|
|
376
462
|
/**
|
|
377
|
-
*
|
|
463
|
+
* Filter by content type.
|
|
378
464
|
*/
|
|
379
|
-
|
|
465
|
+
type?: "video" | "short" | "channel" | "playlist" | "movie";
|
|
466
|
+
/**
|
|
467
|
+
* Sort order. Defaults to relevance.
|
|
468
|
+
*/
|
|
469
|
+
sortBy?: "relevance" | "popularity" | "date" | "rating";
|
|
380
470
|
/**
|
|
381
|
-
*
|
|
471
|
+
* Filter by upload date.
|
|
382
472
|
*/
|
|
383
|
-
|
|
473
|
+
uploadDate?: "today" | "week" | "month" | "year";
|
|
384
474
|
/**
|
|
385
|
-
*
|
|
475
|
+
* Duration filter. Not applicable when type is short.
|
|
386
476
|
*/
|
|
387
|
-
|
|
477
|
+
duration?: "short" | "medium" | "long";
|
|
388
478
|
/**
|
|
389
|
-
*
|
|
479
|
+
* Filter by video features.
|
|
390
480
|
*/
|
|
391
|
-
|
|
392
|
-
} | {
|
|
393
|
-
type: "replies";
|
|
481
|
+
features?: Array<"live" | "4k" | "hd" | "subtitles" | "creativeCommons" | "360" | "vr180" | "3d" | "hdr" | "location" | "purchased">;
|
|
394
482
|
/**
|
|
395
|
-
*
|
|
483
|
+
* Token from a previous response to fetch the next page.
|
|
396
484
|
*/
|
|
397
|
-
continuationToken
|
|
485
|
+
continuationToken?: string;
|
|
398
486
|
};
|
|
399
487
|
path?: never;
|
|
400
488
|
query?: never;
|
|
401
|
-
url: "/v1/
|
|
489
|
+
url: "/v1/search";
|
|
402
490
|
};
|
|
403
|
-
type
|
|
491
|
+
type SearchVideosErrors = {
|
|
404
492
|
/**
|
|
405
493
|
* Validation error
|
|
406
494
|
*/
|
|
407
495
|
400: ErrorResponse;
|
|
408
496
|
/**
|
|
409
|
-
*
|
|
497
|
+
* Unauthorized
|
|
410
498
|
*/
|
|
411
499
|
401: ErrorResponse;
|
|
412
500
|
/**
|
|
@@ -414,11 +502,7 @@ type GetVideoErrors = {
|
|
|
414
502
|
*/
|
|
415
503
|
402: ErrorResponse;
|
|
416
504
|
/**
|
|
417
|
-
*
|
|
418
|
-
*/
|
|
419
|
-
404: ErrorResponse;
|
|
420
|
-
/**
|
|
421
|
-
* Rate limited
|
|
505
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
422
506
|
*/
|
|
423
507
|
429: ErrorResponse;
|
|
424
508
|
/**
|
|
@@ -426,67 +510,154 @@ type GetVideoErrors = {
|
|
|
426
510
|
*/
|
|
427
511
|
500: ErrorResponse;
|
|
428
512
|
/**
|
|
429
|
-
*
|
|
513
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
430
514
|
*/
|
|
431
515
|
503: ErrorResponse;
|
|
432
516
|
};
|
|
433
|
-
type
|
|
434
|
-
type
|
|
517
|
+
type SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
|
|
518
|
+
type SearchVideosResponses = {
|
|
435
519
|
/**
|
|
436
|
-
*
|
|
520
|
+
* Search results
|
|
437
521
|
*/
|
|
438
522
|
200: {
|
|
439
|
-
success
|
|
440
|
-
requestId
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
523
|
+
success?: true;
|
|
524
|
+
requestId?: string;
|
|
525
|
+
cacheState?: "hit" | "miss";
|
|
526
|
+
creditsUsed?: number;
|
|
527
|
+
creditsRemaining?: number;
|
|
528
|
+
/**
|
|
529
|
+
* When no results match, the response includes `data.empty = { code: 'EMPTY_SEARCH_RESULTS', message }`.
|
|
530
|
+
*/
|
|
531
|
+
data?: {
|
|
532
|
+
/**
|
|
533
|
+
* Search results. The shape of each item depends on the `type` filter (or on the item's intrinsic type if `type` was not specified).
|
|
534
|
+
*/
|
|
535
|
+
items: Array<{
|
|
536
|
+
type: "video";
|
|
537
|
+
id: string;
|
|
538
|
+
/**
|
|
539
|
+
* Canonical URL alias for the item.
|
|
540
|
+
*/
|
|
541
|
+
url: string;
|
|
542
|
+
videoUrl: string;
|
|
543
|
+
title: string;
|
|
544
|
+
author: string | null;
|
|
545
|
+
authorId: string | null;
|
|
546
|
+
description: string | null;
|
|
547
|
+
duration: string | null;
|
|
548
|
+
durationSec: number | null;
|
|
549
|
+
durationText: string | null;
|
|
550
|
+
isLive: boolean;
|
|
551
|
+
isUpcoming: boolean;
|
|
552
|
+
isVerified: boolean;
|
|
553
|
+
viewCount: number | null;
|
|
554
|
+
viewCountText: string | null;
|
|
555
|
+
publishedAt: string | null;
|
|
556
|
+
publishedAtText: string | null;
|
|
557
|
+
thumbnails: Array<Thumbnail>;
|
|
558
|
+
} | {
|
|
559
|
+
type: "short";
|
|
560
|
+
id: string;
|
|
561
|
+
/**
|
|
562
|
+
* Canonical URL alias for the item.
|
|
563
|
+
*/
|
|
564
|
+
url: string;
|
|
565
|
+
shortUrl: string;
|
|
566
|
+
title: string;
|
|
567
|
+
viewCount: number | null;
|
|
568
|
+
viewCountText: string | null;
|
|
569
|
+
thumbnails: Array<Thumbnail>;
|
|
570
|
+
} | {
|
|
571
|
+
type: "channel";
|
|
572
|
+
id: string;
|
|
573
|
+
/**
|
|
574
|
+
* Canonical URL alias for the item.
|
|
575
|
+
*/
|
|
576
|
+
url: string;
|
|
577
|
+
channelUrl: string;
|
|
578
|
+
name: string;
|
|
579
|
+
handle: string | null;
|
|
580
|
+
description: string | null;
|
|
581
|
+
subscriberCount: number | null;
|
|
582
|
+
subscriberCountText: string | null;
|
|
583
|
+
isVerified: boolean;
|
|
584
|
+
thumbnails: Array<Thumbnail>;
|
|
585
|
+
} | {
|
|
586
|
+
type: "playlist";
|
|
587
|
+
id: string;
|
|
588
|
+
/**
|
|
589
|
+
* Canonical URL alias for the item.
|
|
590
|
+
*/
|
|
591
|
+
url: string;
|
|
592
|
+
playlistUrl: string;
|
|
593
|
+
title: string;
|
|
594
|
+
thumbnails: Array<Thumbnail>;
|
|
595
|
+
author: string | null;
|
|
596
|
+
authorId: string | null;
|
|
597
|
+
videoCount: number | null;
|
|
598
|
+
videoCountText: string | null;
|
|
599
|
+
}>;
|
|
600
|
+
continuationToken: string | null;
|
|
601
|
+
hasMore: boolean;
|
|
602
|
+
/**
|
|
603
|
+
* Estimated total from YouTube on the first page; null when YouTube omits it or for continuation pages.
|
|
604
|
+
*/
|
|
605
|
+
estimatedResults: number | null;
|
|
606
|
+
/**
|
|
607
|
+
* Present only when the operation yields no results.
|
|
608
|
+
*/
|
|
609
|
+
empty?: {
|
|
610
|
+
code?: string;
|
|
611
|
+
message?: string;
|
|
612
|
+
} | null;
|
|
613
|
+
};
|
|
445
614
|
};
|
|
446
615
|
};
|
|
447
|
-
type
|
|
448
|
-
type
|
|
616
|
+
type SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
|
|
617
|
+
type GetVideoData = {
|
|
449
618
|
body: {
|
|
450
619
|
/**
|
|
451
|
-
*
|
|
452
|
-
*/
|
|
453
|
-
q: string;
|
|
454
|
-
/**
|
|
455
|
-
* Filter by content type.
|
|
620
|
+
* The type of data to retrieve.
|
|
456
621
|
*/
|
|
457
|
-
type
|
|
622
|
+
type: "details" | "transcript" | "comments" | "livechat";
|
|
458
623
|
/**
|
|
459
|
-
*
|
|
624
|
+
* Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...).
|
|
460
625
|
*/
|
|
461
|
-
|
|
626
|
+
videoUrl: string;
|
|
462
627
|
/**
|
|
463
|
-
*
|
|
628
|
+
* Comment sort order: any (YouTube's default ordering), top, or latest. Only applies when type is 'comments'. Defaults to any.
|
|
464
629
|
*/
|
|
465
|
-
|
|
630
|
+
sortBy?: "any" | "top" | "latest";
|
|
466
631
|
/**
|
|
467
|
-
*
|
|
632
|
+
* Live chat mode. Only applies when type is 'livechat'. 'top' = Top chat (moderated, default), 'live' = all messages. Applied on the first call; later polls keep the chosen mode.
|
|
468
633
|
*/
|
|
469
|
-
|
|
634
|
+
chatType?: "top" | "live";
|
|
470
635
|
/**
|
|
471
|
-
*
|
|
636
|
+
* Preferred transcript language code. Only applies when type is 'transcript'.
|
|
472
637
|
*/
|
|
473
|
-
|
|
638
|
+
lang?: string;
|
|
474
639
|
/**
|
|
475
|
-
*
|
|
640
|
+
* Pagination token. For 'livechat', pass the continuationToken from a previous livechat response to poll for new messages.
|
|
476
641
|
*/
|
|
477
642
|
continuationToken?: string;
|
|
643
|
+
} | {
|
|
644
|
+
type: "replies";
|
|
645
|
+
/**
|
|
646
|
+
* The repliesToken from a previous comments response.
|
|
647
|
+
*/
|
|
648
|
+
continuationToken: string;
|
|
478
649
|
};
|
|
479
650
|
path?: never;
|
|
480
651
|
query?: never;
|
|
481
|
-
url: "/v1/
|
|
652
|
+
url: "/v1/video";
|
|
482
653
|
};
|
|
483
|
-
type
|
|
654
|
+
type GetVideoErrors = {
|
|
484
655
|
/**
|
|
485
656
|
* Validation error
|
|
486
657
|
*/
|
|
487
658
|
400: ErrorResponse;
|
|
488
659
|
/**
|
|
489
|
-
*
|
|
660
|
+
* Invalid or missing API key
|
|
490
661
|
*/
|
|
491
662
|
401: ErrorResponse;
|
|
492
663
|
/**
|
|
@@ -494,29 +665,46 @@ type SearchVideosErrors = {
|
|
|
494
665
|
*/
|
|
495
666
|
402: ErrorResponse;
|
|
496
667
|
/**
|
|
497
|
-
*
|
|
668
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
498
669
|
*/
|
|
499
670
|
429: ErrorResponse;
|
|
500
671
|
/**
|
|
501
672
|
* Internal error
|
|
502
673
|
*/
|
|
503
674
|
500: ErrorResponse;
|
|
675
|
+
/**
|
|
676
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
677
|
+
*/
|
|
678
|
+
503: ErrorResponse;
|
|
504
679
|
};
|
|
505
|
-
type
|
|
506
|
-
type
|
|
680
|
+
type GetVideoError = GetVideoErrors[keyof GetVideoErrors];
|
|
681
|
+
type GetVideoResponses = {
|
|
507
682
|
/**
|
|
508
|
-
*
|
|
683
|
+
* Successful response
|
|
509
684
|
*/
|
|
510
685
|
200: {
|
|
511
|
-
success
|
|
512
|
-
requestId
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
686
|
+
success?: true;
|
|
687
|
+
requestId?: string;
|
|
688
|
+
cacheState?: "hit" | "miss";
|
|
689
|
+
creditsUsed?: number;
|
|
690
|
+
creditsRemaining?: number;
|
|
691
|
+
/**
|
|
692
|
+
* Per-type response payload. See oneOf branches. If the operation yields no results, the response may include a `data.empty` object instead of the expected payload: `{ code: string, message: string }`. Codes: `EMPTY_TRANSCRIPT_SEGMENTS`, `EMPTY_COMMENTS`, `EMPTY_COMMENT_REPLIES`.
|
|
693
|
+
*/
|
|
694
|
+
data?: ({
|
|
695
|
+
_kind?: "details";
|
|
696
|
+
} & VideoResponseDetails) | ({
|
|
697
|
+
_kind?: "transcript";
|
|
698
|
+
} & VideoResponseTranscript) | ({
|
|
699
|
+
_kind?: "comments";
|
|
700
|
+
} & VideoResponseComments) | ({
|
|
701
|
+
_kind?: "replies";
|
|
702
|
+
} & VideoResponseReplies) | ({
|
|
703
|
+
_kind?: "livechat";
|
|
704
|
+
} & VideoResponseLivechat);
|
|
517
705
|
};
|
|
518
706
|
};
|
|
519
|
-
type
|
|
707
|
+
type GetVideoResponse = GetVideoResponses[keyof GetVideoResponses];
|
|
520
708
|
type GetChannelData = {
|
|
521
709
|
body: {
|
|
522
710
|
/**
|
|
@@ -526,7 +714,11 @@ type GetChannelData = {
|
|
|
526
714
|
/**
|
|
527
715
|
* Content tab to fetch. Defaults to video.
|
|
528
716
|
*/
|
|
529
|
-
tab?: "video" | "short" | "playlist" | "about";
|
|
717
|
+
tab?: "video" | "short" | "live" | "playlist" | "post" | "community" | "course" | "about";
|
|
718
|
+
/**
|
|
719
|
+
* Search query within the channel. When supplied, tab is ignored.
|
|
720
|
+
*/
|
|
721
|
+
query?: string;
|
|
530
722
|
/**
|
|
531
723
|
* Token from a previous response to fetch the next page.
|
|
532
724
|
*/
|
|
@@ -554,13 +746,17 @@ type GetChannelErrors = {
|
|
|
554
746
|
*/
|
|
555
747
|
402: ErrorResponse;
|
|
556
748
|
/**
|
|
557
|
-
*
|
|
749
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
558
750
|
*/
|
|
559
751
|
429: ErrorResponse;
|
|
560
752
|
/**
|
|
561
753
|
* Internal error
|
|
562
754
|
*/
|
|
563
755
|
500: ErrorResponse;
|
|
756
|
+
/**
|
|
757
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
758
|
+
*/
|
|
759
|
+
503: ErrorResponse;
|
|
564
760
|
};
|
|
565
761
|
type GetChannelError = GetChannelErrors[keyof GetChannelErrors];
|
|
566
762
|
type GetChannelResponses = {
|
|
@@ -568,12 +764,183 @@ type GetChannelResponses = {
|
|
|
568
764
|
* Channel data
|
|
569
765
|
*/
|
|
570
766
|
200: {
|
|
571
|
-
success
|
|
572
|
-
requestId
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
767
|
+
success?: true;
|
|
768
|
+
requestId?: string;
|
|
769
|
+
cacheState?: "hit" | "miss";
|
|
770
|
+
creditsUsed?: number;
|
|
771
|
+
creditsRemaining?: number;
|
|
772
|
+
/**
|
|
773
|
+
* All tabs return the same top-level fields. For `tab: "about"`, `items` is empty, `continuationToken` is null, and `hasMore` is false. When a content tab has no items, the response also includes `data.empty`.
|
|
774
|
+
*/
|
|
775
|
+
data?: {
|
|
776
|
+
/**
|
|
777
|
+
* The channel profile. Always returned for the 'about' tab; may be null on continuation requests for other tabs.
|
|
778
|
+
*/
|
|
779
|
+
channel: {
|
|
780
|
+
type: "channel";
|
|
781
|
+
/**
|
|
782
|
+
* YouTube channel ID (UC...).
|
|
783
|
+
*/
|
|
784
|
+
id: string | null;
|
|
785
|
+
/**
|
|
786
|
+
* Canonical URL alias for the channel.
|
|
787
|
+
*/
|
|
788
|
+
url: string | null;
|
|
789
|
+
/**
|
|
790
|
+
* Canonical URL of the channel.
|
|
791
|
+
*/
|
|
792
|
+
channelUrl: string | null;
|
|
793
|
+
/**
|
|
794
|
+
* Display name of the channel.
|
|
795
|
+
*/
|
|
796
|
+
name: string | null;
|
|
797
|
+
/**
|
|
798
|
+
* Channel handle without the @ symbol (e.g. 'mkbhd').
|
|
799
|
+
*/
|
|
800
|
+
handle: string | null;
|
|
801
|
+
/**
|
|
802
|
+
* Channel description / about text.
|
|
803
|
+
*/
|
|
804
|
+
description: string | null;
|
|
805
|
+
/**
|
|
806
|
+
* Parsed subscriber count as a number.
|
|
807
|
+
*/
|
|
808
|
+
subscriberCount: number | null;
|
|
809
|
+
/**
|
|
810
|
+
* Formatted subscriber count string as displayed on YouTube (e.g. '21M subscribers').
|
|
811
|
+
*/
|
|
812
|
+
subscriberCountText: string | null;
|
|
813
|
+
/**
|
|
814
|
+
* Parsed total video count as a number.
|
|
815
|
+
*/
|
|
816
|
+
videoCount: number | null;
|
|
817
|
+
/**
|
|
818
|
+
* Formatted video count string (e.g. '1.2K videos').
|
|
819
|
+
*/
|
|
820
|
+
videoCountText: string | null;
|
|
821
|
+
/**
|
|
822
|
+
* Whether the channel has a verification badge.
|
|
823
|
+
*/
|
|
824
|
+
isVerified: boolean;
|
|
825
|
+
/**
|
|
826
|
+
* Channel avatar thumbnails.
|
|
827
|
+
*/
|
|
828
|
+
thumbnails: Array<Thumbnail>;
|
|
829
|
+
/**
|
|
830
|
+
* Channel banner images.
|
|
831
|
+
*/
|
|
832
|
+
banners: Array<Thumbnail>;
|
|
833
|
+
/**
|
|
834
|
+
* Channel country from the About tab; null when unavailable or on other tabs.
|
|
835
|
+
*/
|
|
836
|
+
country: string | null;
|
|
837
|
+
/**
|
|
838
|
+
* Date the channel was created; null when unavailable or on other tabs.
|
|
839
|
+
*/
|
|
840
|
+
joinedDate: string | null;
|
|
841
|
+
/**
|
|
842
|
+
* Total channel view count from the About tab; null when unavailable or on other tabs.
|
|
843
|
+
*/
|
|
844
|
+
viewCount: number | null;
|
|
845
|
+
/**
|
|
846
|
+
* Formatted total view count from the About tab; null when unavailable or on other tabs.
|
|
847
|
+
*/
|
|
848
|
+
viewCountText: string | null;
|
|
849
|
+
/**
|
|
850
|
+
* External links from the About tab; null when unavailable or on other tabs.
|
|
851
|
+
*/
|
|
852
|
+
links: Array<{
|
|
853
|
+
title: string;
|
|
854
|
+
url: string;
|
|
855
|
+
}> | null;
|
|
856
|
+
} | null;
|
|
857
|
+
tab: string;
|
|
858
|
+
/**
|
|
859
|
+
* Tab-specific items. Shape varies by `tab`; empty for `tab: "about"`.
|
|
860
|
+
*/
|
|
861
|
+
items: Array<{
|
|
862
|
+
type: "video";
|
|
863
|
+
id: string;
|
|
864
|
+
/**
|
|
865
|
+
* Canonical URL alias for the item.
|
|
866
|
+
*/
|
|
867
|
+
url: string;
|
|
868
|
+
videoUrl: string;
|
|
869
|
+
title: string | null;
|
|
870
|
+
author: string | null;
|
|
871
|
+
authorId: string | null;
|
|
872
|
+
viewCount: number | null;
|
|
873
|
+
viewCountText: string | null;
|
|
874
|
+
duration: string | null;
|
|
875
|
+
durationSec: number | null;
|
|
876
|
+
durationText: string | null;
|
|
877
|
+
isLive: boolean;
|
|
878
|
+
isUpcoming: boolean;
|
|
879
|
+
upcomingAt: string | null;
|
|
880
|
+
publishedAt: string | null;
|
|
881
|
+
publishedAtText: string | null;
|
|
882
|
+
thumbnails: Array<Thumbnail>;
|
|
883
|
+
} | {
|
|
884
|
+
type: "short";
|
|
885
|
+
id: string;
|
|
886
|
+
/**
|
|
887
|
+
* Canonical URL alias for the item.
|
|
888
|
+
*/
|
|
889
|
+
url: string;
|
|
890
|
+
shortUrl: string;
|
|
891
|
+
title: string | null;
|
|
892
|
+
author: string | null;
|
|
893
|
+
authorId: string | null;
|
|
894
|
+
viewCount: number | null;
|
|
895
|
+
viewCountText: string | null;
|
|
896
|
+
thumbnails: Array<Thumbnail>;
|
|
897
|
+
} | {
|
|
898
|
+
type: "playlist";
|
|
899
|
+
id: string;
|
|
900
|
+
/**
|
|
901
|
+
* Canonical URL alias for the item.
|
|
902
|
+
*/
|
|
903
|
+
url: string;
|
|
904
|
+
playlistUrl: string;
|
|
905
|
+
title: string | null;
|
|
906
|
+
author: string | null;
|
|
907
|
+
authorId: string | null;
|
|
908
|
+
/**
|
|
909
|
+
* Parsed playlist video count.
|
|
910
|
+
*/
|
|
911
|
+
videoCount: number | null;
|
|
912
|
+
/**
|
|
913
|
+
* Raw formatted playlist video count string from YouTube.
|
|
914
|
+
*/
|
|
915
|
+
videoCountText: string | null;
|
|
916
|
+
thumbnails: Array<Thumbnail>;
|
|
917
|
+
} | {
|
|
918
|
+
type: "post";
|
|
919
|
+
id: string;
|
|
920
|
+
url: string;
|
|
921
|
+
content: string | null;
|
|
922
|
+
publishedTimeText: string | null;
|
|
923
|
+
likeCountText: string | null;
|
|
924
|
+
commentCountText: string | null;
|
|
925
|
+
images: Array<{
|
|
926
|
+
thumbnails: Array<Thumbnail>;
|
|
927
|
+
}>;
|
|
928
|
+
video: {
|
|
929
|
+
id: string;
|
|
930
|
+
title: string | null;
|
|
931
|
+
url: string;
|
|
932
|
+
} | null;
|
|
933
|
+
}>;
|
|
934
|
+
continuationToken: string | null;
|
|
935
|
+
hasMore: boolean;
|
|
936
|
+
/**
|
|
937
|
+
* Present only when the operation yields no results.
|
|
938
|
+
*/
|
|
939
|
+
empty?: {
|
|
940
|
+
code?: string;
|
|
941
|
+
message?: string;
|
|
942
|
+
} | null;
|
|
943
|
+
};
|
|
577
944
|
};
|
|
578
945
|
};
|
|
579
946
|
type GetChannelResponse = GetChannelResponses[keyof GetChannelResponses];
|
|
@@ -606,13 +973,17 @@ type GetPlaylistErrors = {
|
|
|
606
973
|
*/
|
|
607
974
|
402: ErrorResponse;
|
|
608
975
|
/**
|
|
609
|
-
*
|
|
976
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
610
977
|
*/
|
|
611
978
|
429: ErrorResponse;
|
|
612
979
|
/**
|
|
613
980
|
* Internal error
|
|
614
981
|
*/
|
|
615
982
|
500: ErrorResponse;
|
|
983
|
+
/**
|
|
984
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
985
|
+
*/
|
|
986
|
+
503: ErrorResponse;
|
|
616
987
|
};
|
|
617
988
|
type GetPlaylistError = GetPlaylistErrors[keyof GetPlaylistErrors];
|
|
618
989
|
type GetPlaylistResponses = {
|
|
@@ -620,19 +991,83 @@ type GetPlaylistResponses = {
|
|
|
620
991
|
* Playlist items
|
|
621
992
|
*/
|
|
622
993
|
200: {
|
|
623
|
-
success
|
|
624
|
-
requestId
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
994
|
+
success?: true;
|
|
995
|
+
requestId?: string;
|
|
996
|
+
cacheState?: "hit" | "miss";
|
|
997
|
+
creditsUsed?: number;
|
|
998
|
+
creditsRemaining?: number;
|
|
999
|
+
/**
|
|
1000
|
+
* When the playlist has no videos, the response includes `data.empty = { code: 'EMPTY_PLAYLIST_VIDEOS', message }`.
|
|
1001
|
+
*/
|
|
1002
|
+
data?: {
|
|
1003
|
+
playlist: {
|
|
1004
|
+
type: "playlist";
|
|
1005
|
+
id: string;
|
|
1006
|
+
/**
|
|
1007
|
+
* Canonical URL alias for the item.
|
|
1008
|
+
*/
|
|
1009
|
+
url: string;
|
|
1010
|
+
playlistUrl: string;
|
|
1011
|
+
title: string;
|
|
1012
|
+
author: string | null;
|
|
1013
|
+
authorId: string | null;
|
|
1014
|
+
description: string | null;
|
|
1015
|
+
/**
|
|
1016
|
+
* Parsed video count, e.g. 52.
|
|
1017
|
+
*/
|
|
1018
|
+
videoCount: number | null;
|
|
1019
|
+
thumbnails: Array<Thumbnail>;
|
|
1020
|
+
/**
|
|
1021
|
+
* Raw formatted string from YouTube, e.g. "52 videos".
|
|
1022
|
+
*/
|
|
1023
|
+
videoCountText: string | null;
|
|
1024
|
+
} | null;
|
|
1025
|
+
/**
|
|
1026
|
+
* Playlist video items. Supports both legacy playlistVideoRenderer and new lockupViewModel layout.
|
|
1027
|
+
*/
|
|
1028
|
+
items: Array<{
|
|
1029
|
+
type: "video";
|
|
1030
|
+
id: string;
|
|
1031
|
+
/**
|
|
1032
|
+
* Canonical URL alias for the item.
|
|
1033
|
+
*/
|
|
1034
|
+
url: string;
|
|
1035
|
+
videoUrl: string;
|
|
1036
|
+
title: string;
|
|
1037
|
+
author: string | null;
|
|
1038
|
+
authorId: string | null;
|
|
1039
|
+
duration: string | null;
|
|
1040
|
+
durationSec: number | null;
|
|
1041
|
+
durationText: string | null;
|
|
1042
|
+
/**
|
|
1043
|
+
* 1-based playlist index; null for lockup items.
|
|
1044
|
+
*/
|
|
1045
|
+
index: number | null;
|
|
1046
|
+
isLive: boolean;
|
|
1047
|
+
isPlayable: boolean;
|
|
1048
|
+
isUpcoming: boolean;
|
|
1049
|
+
upcomingAt: string | null;
|
|
1050
|
+
viewCount: number | null;
|
|
1051
|
+
viewCountText: string | null;
|
|
1052
|
+
publishedAt: string | null;
|
|
1053
|
+
publishedAtText: string | null;
|
|
1054
|
+
thumbnails: Array<Thumbnail>;
|
|
1055
|
+
}>;
|
|
1056
|
+
continuationToken: string | null;
|
|
1057
|
+
hasMore: boolean;
|
|
1058
|
+
/**
|
|
1059
|
+
* Present only when the operation yields no results.
|
|
1060
|
+
*/
|
|
1061
|
+
empty?: {
|
|
1062
|
+
code?: string;
|
|
1063
|
+
message?: string;
|
|
1064
|
+
} | null;
|
|
1065
|
+
};
|
|
629
1066
|
};
|
|
630
1067
|
};
|
|
631
1068
|
type GetPlaylistResponse = GetPlaylistResponses[keyof GetPlaylistResponses];
|
|
632
1069
|
type GetSuggestionsData = {
|
|
633
|
-
body
|
|
634
|
-
path?: never;
|
|
635
|
-
query: {
|
|
1070
|
+
body: {
|
|
636
1071
|
/**
|
|
637
1072
|
* Search query.
|
|
638
1073
|
*/
|
|
@@ -646,6 +1081,8 @@ type GetSuggestionsData = {
|
|
|
646
1081
|
*/
|
|
647
1082
|
gl?: string;
|
|
648
1083
|
};
|
|
1084
|
+
path?: never;
|
|
1085
|
+
query?: never;
|
|
649
1086
|
url: "/v1/suggest";
|
|
650
1087
|
};
|
|
651
1088
|
type GetSuggestionsErrors = {
|
|
@@ -658,13 +1095,21 @@ type GetSuggestionsErrors = {
|
|
|
658
1095
|
*/
|
|
659
1096
|
401: ErrorResponse;
|
|
660
1097
|
/**
|
|
661
|
-
*
|
|
1098
|
+
* Insufficient credits
|
|
1099
|
+
*/
|
|
1100
|
+
402: ErrorResponse;
|
|
1101
|
+
/**
|
|
1102
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
662
1103
|
*/
|
|
663
1104
|
429: ErrorResponse;
|
|
664
1105
|
/**
|
|
665
1106
|
* Internal error
|
|
666
1107
|
*/
|
|
667
1108
|
500: ErrorResponse;
|
|
1109
|
+
/**
|
|
1110
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
1111
|
+
*/
|
|
1112
|
+
503: ErrorResponse;
|
|
668
1113
|
};
|
|
669
1114
|
type GetSuggestionsError = GetSuggestionsErrors[keyof GetSuggestionsErrors];
|
|
670
1115
|
type GetSuggestionsResponses = {
|
|
@@ -672,15 +1117,161 @@ type GetSuggestionsResponses = {
|
|
|
672
1117
|
* Autocomplete suggestions
|
|
673
1118
|
*/
|
|
674
1119
|
200: {
|
|
675
|
-
success
|
|
676
|
-
requestId
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
1120
|
+
success?: true;
|
|
1121
|
+
requestId?: string;
|
|
1122
|
+
cacheState?: "hit" | "miss";
|
|
1123
|
+
creditsUsed?: number;
|
|
1124
|
+
creditsRemaining?: number;
|
|
1125
|
+
data?: {
|
|
1126
|
+
suggestions: Array<string>;
|
|
1127
|
+
};
|
|
681
1128
|
};
|
|
682
1129
|
};
|
|
683
1130
|
type GetSuggestionsResponse = GetSuggestionsResponses[keyof GetSuggestionsResponses];
|
|
1131
|
+
type YoutubeMusicData = {
|
|
1132
|
+
body: {
|
|
1133
|
+
/**
|
|
1134
|
+
* Music resource to fetch.
|
|
1135
|
+
*/
|
|
1136
|
+
type: "search" | "suggest" | "song" | "lyrics" | "album" | "artist" | "playlist";
|
|
1137
|
+
/**
|
|
1138
|
+
* Search or suggestion query. Required for type search and suggest.
|
|
1139
|
+
*/
|
|
1140
|
+
q?: string;
|
|
1141
|
+
/**
|
|
1142
|
+
* Music search result type. Used only when type is search.
|
|
1143
|
+
*/
|
|
1144
|
+
searchType?: "song" | "video" | "album" | "artist" | "playlist" | "podcast" | "episode" | "profile";
|
|
1145
|
+
/**
|
|
1146
|
+
* YouTube / YouTube Music video URL or bare video ID. Required for type song and lyrics.
|
|
1147
|
+
*/
|
|
1148
|
+
videoUrl?: string;
|
|
1149
|
+
/**
|
|
1150
|
+
* YouTube Music album URL or bare MPRE/OLAK album ID. Required for type album.
|
|
1151
|
+
*/
|
|
1152
|
+
albumUrl?: string;
|
|
1153
|
+
/**
|
|
1154
|
+
* YouTube Music artist URL or bare UC/MPAD artist ID. Required for type artist.
|
|
1155
|
+
*/
|
|
1156
|
+
artistUrl?: string;
|
|
1157
|
+
/**
|
|
1158
|
+
* YouTube / YouTube Music playlist URL or bare playlist ID. Required for type playlist.
|
|
1159
|
+
*/
|
|
1160
|
+
playlistUrl?: string;
|
|
1161
|
+
/**
|
|
1162
|
+
* Token from a previous music search or playlist response.
|
|
1163
|
+
*/
|
|
1164
|
+
continuationToken?: string;
|
|
1165
|
+
};
|
|
1166
|
+
path?: never;
|
|
1167
|
+
query?: never;
|
|
1168
|
+
url: "/v1/music";
|
|
1169
|
+
};
|
|
1170
|
+
type YoutubeMusicErrors = {
|
|
1171
|
+
/**
|
|
1172
|
+
* Validation error
|
|
1173
|
+
*/
|
|
1174
|
+
400: ErrorResponse;
|
|
1175
|
+
/**
|
|
1176
|
+
* Unauthorized
|
|
1177
|
+
*/
|
|
1178
|
+
401: ErrorResponse;
|
|
1179
|
+
/**
|
|
1180
|
+
* Insufficient credits
|
|
1181
|
+
*/
|
|
1182
|
+
402: ErrorResponse;
|
|
1183
|
+
/**
|
|
1184
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
1185
|
+
*/
|
|
1186
|
+
429: ErrorResponse;
|
|
1187
|
+
/**
|
|
1188
|
+
* Internal error
|
|
1189
|
+
*/
|
|
1190
|
+
500: ErrorResponse;
|
|
1191
|
+
/**
|
|
1192
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
1193
|
+
*/
|
|
1194
|
+
503: ErrorResponse;
|
|
1195
|
+
};
|
|
1196
|
+
type YoutubeMusicError = YoutubeMusicErrors[keyof YoutubeMusicErrors];
|
|
1197
|
+
type YoutubeMusicResponses = {
|
|
1198
|
+
/**
|
|
1199
|
+
* Success
|
|
1200
|
+
*/
|
|
1201
|
+
200: {
|
|
1202
|
+
success?: true;
|
|
1203
|
+
requestId?: string;
|
|
1204
|
+
cacheState?: "hit" | "miss";
|
|
1205
|
+
creditsUsed?: number;
|
|
1206
|
+
creditsRemaining?: number;
|
|
1207
|
+
data?: MusicResponseData;
|
|
1208
|
+
};
|
|
1209
|
+
};
|
|
1210
|
+
type YoutubeMusicResponse = YoutubeMusicResponses[keyof YoutubeMusicResponses];
|
|
1211
|
+
type YoutubeKidsData = {
|
|
1212
|
+
body: {
|
|
1213
|
+
/**
|
|
1214
|
+
* Kids resource to fetch.
|
|
1215
|
+
*/
|
|
1216
|
+
type: "search" | "video";
|
|
1217
|
+
/**
|
|
1218
|
+
* YouTube Kids search query. Required for type search.
|
|
1219
|
+
*/
|
|
1220
|
+
q?: string;
|
|
1221
|
+
/**
|
|
1222
|
+
* YouTube Kids / YouTube video URL or bare video ID. Required for type video.
|
|
1223
|
+
*/
|
|
1224
|
+
videoUrl?: string;
|
|
1225
|
+
/**
|
|
1226
|
+
* Token from a previous YouTube Kids search response.
|
|
1227
|
+
*/
|
|
1228
|
+
continuationToken?: string;
|
|
1229
|
+
};
|
|
1230
|
+
path?: never;
|
|
1231
|
+
query?: never;
|
|
1232
|
+
url: "/v1/kids";
|
|
1233
|
+
};
|
|
1234
|
+
type YoutubeKidsErrors = {
|
|
1235
|
+
/**
|
|
1236
|
+
* Validation error
|
|
1237
|
+
*/
|
|
1238
|
+
400: ErrorResponse;
|
|
1239
|
+
/**
|
|
1240
|
+
* Unauthorized
|
|
1241
|
+
*/
|
|
1242
|
+
401: ErrorResponse;
|
|
1243
|
+
/**
|
|
1244
|
+
* Insufficient credits
|
|
1245
|
+
*/
|
|
1246
|
+
402: ErrorResponse;
|
|
1247
|
+
/**
|
|
1248
|
+
* Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
|
|
1249
|
+
*/
|
|
1250
|
+
429: ErrorResponse;
|
|
1251
|
+
/**
|
|
1252
|
+
* Internal error
|
|
1253
|
+
*/
|
|
1254
|
+
500: ErrorResponse;
|
|
1255
|
+
/**
|
|
1256
|
+
* Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
|
|
1257
|
+
*/
|
|
1258
|
+
503: ErrorResponse;
|
|
1259
|
+
};
|
|
1260
|
+
type YoutubeKidsError = YoutubeKidsErrors[keyof YoutubeKidsErrors];
|
|
1261
|
+
type YoutubeKidsResponses = {
|
|
1262
|
+
/**
|
|
1263
|
+
* Success
|
|
1264
|
+
*/
|
|
1265
|
+
200: {
|
|
1266
|
+
success?: true;
|
|
1267
|
+
requestId?: string;
|
|
1268
|
+
cacheState?: "hit" | "miss";
|
|
1269
|
+
creditsUsed?: number;
|
|
1270
|
+
creditsRemaining?: number;
|
|
1271
|
+
data?: KidsResponseData;
|
|
1272
|
+
};
|
|
1273
|
+
};
|
|
1274
|
+
type YoutubeKidsResponse = YoutubeKidsResponses[keyof YoutubeKidsResponses];
|
|
684
1275
|
type GetCreditsData = {
|
|
685
1276
|
body?: never;
|
|
686
1277
|
path?: never;
|
|
@@ -699,12 +1290,59 @@ type GetCreditsResponses = {
|
|
|
699
1290
|
* Credit balance
|
|
700
1291
|
*/
|
|
701
1292
|
200: {
|
|
702
|
-
success
|
|
703
|
-
requestId
|
|
704
|
-
data
|
|
1293
|
+
success?: true;
|
|
1294
|
+
requestId?: string;
|
|
1295
|
+
data?: {
|
|
1296
|
+
/**
|
|
1297
|
+
* Current credit balance.
|
|
1298
|
+
*/
|
|
1299
|
+
credits?: number;
|
|
1300
|
+
};
|
|
705
1301
|
};
|
|
706
1302
|
};
|
|
707
1303
|
type GetCreditsResponse = GetCreditsResponses[keyof GetCreditsResponses];
|
|
1304
|
+
type GetUsageData = {
|
|
1305
|
+
body?: never;
|
|
1306
|
+
path?: never;
|
|
1307
|
+
query?: {
|
|
1308
|
+
/**
|
|
1309
|
+
* Time window: 'today', the last 7 days, or the last 30 days.
|
|
1310
|
+
*/
|
|
1311
|
+
days?: "today" | "7" | "30";
|
|
1312
|
+
/**
|
|
1313
|
+
* Timezone offset in minutes used to bucket activity into days. Defaults to UTC.
|
|
1314
|
+
*/
|
|
1315
|
+
tz?: string;
|
|
1316
|
+
};
|
|
1317
|
+
url: "/v1/usage";
|
|
1318
|
+
};
|
|
1319
|
+
type GetUsageErrors = {
|
|
1320
|
+
/**
|
|
1321
|
+
* Unauthorized
|
|
1322
|
+
*/
|
|
1323
|
+
401: ErrorResponse;
|
|
1324
|
+
};
|
|
1325
|
+
type GetUsageError = GetUsageErrors[keyof GetUsageErrors];
|
|
1326
|
+
type GetUsageResponses = {
|
|
1327
|
+
/**
|
|
1328
|
+
* Daily usage
|
|
1329
|
+
*/
|
|
1330
|
+
200: {
|
|
1331
|
+
success?: true;
|
|
1332
|
+
requestId?: string;
|
|
1333
|
+
data?: {
|
|
1334
|
+
items?: Array<{
|
|
1335
|
+
/**
|
|
1336
|
+
* e.g. 2026-05-28
|
|
1337
|
+
*/
|
|
1338
|
+
date?: string;
|
|
1339
|
+
credits?: number;
|
|
1340
|
+
requests?: number;
|
|
1341
|
+
}>;
|
|
1342
|
+
};
|
|
1343
|
+
};
|
|
1344
|
+
};
|
|
1345
|
+
type GetUsageResponse = GetUsageResponses[keyof GetUsageResponses];
|
|
708
1346
|
type GetLogsData = {
|
|
709
1347
|
body?: never;
|
|
710
1348
|
path?: never;
|
|
@@ -736,68 +1374,251 @@ type GetLogsResponses = {
|
|
|
736
1374
|
* Request logs
|
|
737
1375
|
*/
|
|
738
1376
|
200: {
|
|
739
|
-
success
|
|
740
|
-
requestId
|
|
741
|
-
data
|
|
1377
|
+
success?: true;
|
|
1378
|
+
requestId?: string;
|
|
1379
|
+
data?: {
|
|
1380
|
+
logs?: Array<{
|
|
1381
|
+
id?: string;
|
|
1382
|
+
userId?: string;
|
|
1383
|
+
apiKeyId?: string | null;
|
|
1384
|
+
apiKeyName?: string | null;
|
|
1385
|
+
/**
|
|
1386
|
+
* e.g. /video
|
|
1387
|
+
*/
|
|
1388
|
+
endpoint?: string;
|
|
1389
|
+
/**
|
|
1390
|
+
* e.g. POST
|
|
1391
|
+
*/
|
|
1392
|
+
method?: string;
|
|
1393
|
+
status?: number;
|
|
1394
|
+
credits?: number;
|
|
1395
|
+
durationMs?: number | null;
|
|
1396
|
+
/**
|
|
1397
|
+
* Serialized response body.
|
|
1398
|
+
*/
|
|
1399
|
+
response?: string | null;
|
|
1400
|
+
createdAt?: string;
|
|
1401
|
+
}>;
|
|
1402
|
+
/**
|
|
1403
|
+
* Total number of matching log entries.
|
|
1404
|
+
*/
|
|
1405
|
+
total?: number;
|
|
1406
|
+
/**
|
|
1407
|
+
* Zero-based page index that was returned.
|
|
1408
|
+
*/
|
|
1409
|
+
page?: number;
|
|
1410
|
+
/**
|
|
1411
|
+
* Fixed page size (50).
|
|
1412
|
+
*/
|
|
1413
|
+
pageSize?: number;
|
|
1414
|
+
totalPages?: number;
|
|
1415
|
+
/**
|
|
1416
|
+
* Distinct endpoints seen for this account, useful for building filters.
|
|
1417
|
+
*/
|
|
1418
|
+
endpoints?: Array<string>;
|
|
1419
|
+
};
|
|
742
1420
|
};
|
|
743
1421
|
};
|
|
744
1422
|
type GetLogsResponse = GetLogsResponses[keyof GetLogsResponses];
|
|
745
|
-
type
|
|
746
|
-
|
|
1423
|
+
type McpTransportHeaderData = {
|
|
1424
|
+
/**
|
|
1425
|
+
* JSON-RPC 2.0 request envelope with jsonrpc, id, method, and params fields.
|
|
1426
|
+
*/
|
|
1427
|
+
body: {
|
|
1428
|
+
jsonrpc: "2.0";
|
|
1429
|
+
/**
|
|
1430
|
+
* Request identifier echoed in the response.
|
|
1431
|
+
*/
|
|
1432
|
+
id: unknown;
|
|
1433
|
+
/**
|
|
1434
|
+
* JSON-RPC method, e.g. initialize, tools/list, tools/call.
|
|
1435
|
+
*/
|
|
1436
|
+
method: string;
|
|
1437
|
+
params?: {
|
|
1438
|
+
[key: string]: unknown;
|
|
1439
|
+
};
|
|
1440
|
+
[key: string]: unknown | "2.0" | string | {
|
|
1441
|
+
[key: string]: unknown;
|
|
1442
|
+
} | undefined;
|
|
1443
|
+
};
|
|
747
1444
|
path?: never;
|
|
748
|
-
query?:
|
|
1445
|
+
query?: never;
|
|
1446
|
+
url: "/v1/mcp";
|
|
1447
|
+
};
|
|
1448
|
+
type McpTransportHeaderErrors = {
|
|
1449
|
+
/**
|
|
1450
|
+
* Unauthorized
|
|
1451
|
+
*/
|
|
1452
|
+
401: ErrorResponse;
|
|
1453
|
+
/**
|
|
1454
|
+
* Method not allowed. Use POST.
|
|
1455
|
+
*/
|
|
1456
|
+
405: ErrorResponse;
|
|
1457
|
+
};
|
|
1458
|
+
type McpTransportHeaderError = McpTransportHeaderErrors[keyof McpTransportHeaderErrors];
|
|
1459
|
+
type McpTransportHeaderResponses = {
|
|
1460
|
+
/**
|
|
1461
|
+
* MCP response
|
|
1462
|
+
*/
|
|
1463
|
+
200: {
|
|
1464
|
+
[key: string]: unknown;
|
|
1465
|
+
};
|
|
1466
|
+
};
|
|
1467
|
+
type McpTransportHeaderResponse = McpTransportHeaderResponses[keyof McpTransportHeaderResponses];
|
|
1468
|
+
type McpTransportPathData = {
|
|
1469
|
+
/**
|
|
1470
|
+
* JSON-RPC 2.0 request envelope with jsonrpc, id, method, and params fields.
|
|
1471
|
+
*/
|
|
1472
|
+
body: {
|
|
1473
|
+
jsonrpc: "2.0";
|
|
749
1474
|
/**
|
|
750
|
-
*
|
|
1475
|
+
* Request identifier echoed in the response.
|
|
751
1476
|
*/
|
|
752
|
-
|
|
1477
|
+
id: unknown;
|
|
753
1478
|
/**
|
|
754
|
-
*
|
|
1479
|
+
* JSON-RPC method, e.g. initialize, tools/list, tools/call.
|
|
755
1480
|
*/
|
|
756
|
-
|
|
1481
|
+
method: string;
|
|
1482
|
+
params?: {
|
|
1483
|
+
[key: string]: unknown;
|
|
1484
|
+
};
|
|
1485
|
+
[key: string]: unknown | "2.0" | string | {
|
|
1486
|
+
[key: string]: unknown;
|
|
1487
|
+
} | undefined;
|
|
757
1488
|
};
|
|
758
|
-
|
|
1489
|
+
path: {
|
|
1490
|
+
/**
|
|
1491
|
+
* Your Stophy API key in the format st_<key>
|
|
1492
|
+
*/
|
|
1493
|
+
apiKey: string;
|
|
1494
|
+
};
|
|
1495
|
+
query?: never;
|
|
1496
|
+
url: "/v1/mcp/{apiKey}";
|
|
759
1497
|
};
|
|
760
|
-
type
|
|
1498
|
+
type McpTransportPathErrors = {
|
|
761
1499
|
/**
|
|
762
1500
|
* Unauthorized
|
|
763
1501
|
*/
|
|
764
1502
|
401: ErrorResponse;
|
|
1503
|
+
/**
|
|
1504
|
+
* Method not allowed. Use POST.
|
|
1505
|
+
*/
|
|
1506
|
+
405: ErrorResponse;
|
|
765
1507
|
};
|
|
766
|
-
type
|
|
767
|
-
type
|
|
1508
|
+
type McpTransportPathError = McpTransportPathErrors[keyof McpTransportPathErrors];
|
|
1509
|
+
type McpTransportPathResponses = {
|
|
768
1510
|
/**
|
|
769
|
-
*
|
|
1511
|
+
* MCP response
|
|
770
1512
|
*/
|
|
771
1513
|
200: {
|
|
772
|
-
|
|
773
|
-
requestId: string;
|
|
774
|
-
data: UsageData;
|
|
1514
|
+
[key: string]: unknown;
|
|
775
1515
|
};
|
|
776
1516
|
};
|
|
777
|
-
type
|
|
1517
|
+
type McpTransportPathResponse = McpTransportPathResponses[keyof McpTransportPathResponses];
|
|
778
1518
|
type ClientOptions = {
|
|
779
1519
|
baseUrl: "https://api.stophy.dev" | (string & {});
|
|
780
1520
|
};
|
|
781
1521
|
|
|
1522
|
+
interface MeteredResponse<T> {
|
|
1523
|
+
success: true;
|
|
1524
|
+
requestId: string;
|
|
1525
|
+
cacheState: "hit" | "miss";
|
|
1526
|
+
creditsUsed: number;
|
|
1527
|
+
creditsRemaining: number;
|
|
1528
|
+
warning?: string;
|
|
1529
|
+
data: T;
|
|
1530
|
+
}
|
|
1531
|
+
interface AccountResponse<T> {
|
|
1532
|
+
success: true;
|
|
1533
|
+
requestId: string;
|
|
1534
|
+
data: T;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
type CreditsResponse = AccountResponse<NonNullable<GetCreditsResponse["data"]>>;
|
|
1538
|
+
type LogsResponse = AccountResponse<NonNullable<GetLogsResponse["data"]>>;
|
|
1539
|
+
type UsageResponse = AccountResponse<NonNullable<GetUsageResponse["data"]>>;
|
|
1540
|
+
|
|
782
1541
|
type ChannelBody = GetChannelData["body"];
|
|
783
1542
|
type ChannelOptions = Omit<ChannelBody, "channelUrl">;
|
|
1543
|
+
type GeneratedChannelData = NonNullable<GetChannelResponse["data"]>;
|
|
1544
|
+
type GeneratedChannelItem = GeneratedChannelData["items"][number];
|
|
1545
|
+
interface ChannelCourseItem {
|
|
1546
|
+
type: "course";
|
|
1547
|
+
id: string;
|
|
1548
|
+
url: string;
|
|
1549
|
+
courseUrl: string;
|
|
1550
|
+
playlistUrl: string;
|
|
1551
|
+
title: string | null;
|
|
1552
|
+
author: string | null;
|
|
1553
|
+
authorId: string | null;
|
|
1554
|
+
videoCount: number | null;
|
|
1555
|
+
videoCountText: string | null;
|
|
1556
|
+
thumbnails: Array<{
|
|
1557
|
+
url: string;
|
|
1558
|
+
width: number;
|
|
1559
|
+
height: number;
|
|
1560
|
+
}>;
|
|
1561
|
+
}
|
|
1562
|
+
type ChannelData = Omit<GeneratedChannelData, "items" | "tab"> & {
|
|
1563
|
+
items: Array<GeneratedChannelItem | ChannelCourseItem>;
|
|
1564
|
+
tab: ChannelBody["tab"] | "community" | "course";
|
|
1565
|
+
};
|
|
1566
|
+
type ChannelResponse = MeteredResponse<ChannelData>;
|
|
1567
|
+
|
|
1568
|
+
type KidsInput = {
|
|
1569
|
+
type: "search";
|
|
1570
|
+
q: string;
|
|
1571
|
+
continuationToken?: string;
|
|
1572
|
+
} | {
|
|
1573
|
+
type: "video";
|
|
1574
|
+
videoUrl: string;
|
|
1575
|
+
};
|
|
1576
|
+
type KidsDataFor<T extends KidsInput["type"]> = T extends "search" ? KidsSearchData : KidsVideoData;
|
|
1577
|
+
|
|
1578
|
+
type GeneratedMusicBody = YoutubeMusicData["body"];
|
|
1579
|
+
type SearchType = NonNullable<GeneratedMusicBody["searchType"]>;
|
|
1580
|
+
type MusicInput = {
|
|
1581
|
+
type: "search";
|
|
1582
|
+
q: string;
|
|
1583
|
+
searchType?: SearchType;
|
|
1584
|
+
continuationToken?: string;
|
|
1585
|
+
} | {
|
|
1586
|
+
type: "suggest";
|
|
1587
|
+
q: string;
|
|
1588
|
+
} | {
|
|
1589
|
+
type: "song" | "lyrics";
|
|
1590
|
+
videoUrl: string;
|
|
1591
|
+
} | {
|
|
1592
|
+
type: "album";
|
|
1593
|
+
albumUrl: string;
|
|
1594
|
+
} | {
|
|
1595
|
+
type: "artist";
|
|
1596
|
+
artistUrl: string;
|
|
1597
|
+
} | {
|
|
1598
|
+
type: "playlist";
|
|
1599
|
+
playlistUrl: string;
|
|
1600
|
+
continuationToken?: string;
|
|
1601
|
+
};
|
|
1602
|
+
type MusicDataFor<T extends MusicInput["type"]> = T extends "search" ? MusicSearchData : T extends "suggest" ? MusicSuggestData : T extends "song" ? MusicSongData : T extends "lyrics" ? MusicLyricsData : T extends "album" ? MusicAlbumData : T extends "artist" ? MusicArtistData : MusicPlaylistData;
|
|
784
1603
|
|
|
785
1604
|
type PlaylistBody = GetPlaylistData["body"];
|
|
786
1605
|
type PlaylistOptions = Omit<PlaylistBody, "playlistUrl">;
|
|
1606
|
+
type PlaylistResponse = MeteredResponse<NonNullable<GetPlaylistResponse["data"]>>;
|
|
787
1607
|
|
|
788
1608
|
type SearchBody = SearchVideosData["body"];
|
|
789
1609
|
type SearchOptions = Omit<SearchBody, "q">;
|
|
1610
|
+
type SearchResponse = MeteredResponse<NonNullable<SearchVideosResponse["data"]>>;
|
|
790
1611
|
|
|
791
|
-
type
|
|
792
|
-
type SuggestOptions = Omit<
|
|
1612
|
+
type SuggestBody = GetSuggestionsData["body"];
|
|
1613
|
+
type SuggestOptions = Omit<SuggestBody, "q">;
|
|
1614
|
+
type SuggestResponse = MeteredResponse<NonNullable<GetSuggestionsResponse["data"]>>;
|
|
793
1615
|
|
|
794
|
-
type VideoResponseFor<T> =
|
|
795
|
-
data: T;
|
|
796
|
-
};
|
|
1616
|
+
type VideoResponseFor<T> = MeteredResponse<T>;
|
|
797
1617
|
type VideoUrlBody = Extract<GetVideoData["body"], {
|
|
798
1618
|
videoUrl: string;
|
|
799
1619
|
}>;
|
|
800
1620
|
type CommentsOptions = Pick<VideoUrlBody, "sortBy" | "continuationToken">;
|
|
1621
|
+
type TranscriptOptions = Pick<VideoUrlBody, "lang">;
|
|
801
1622
|
type LiveChatOptions = Pick<VideoUrlBody, "chatType" | "continuationToken">;
|
|
802
1623
|
|
|
803
1624
|
interface StophyOptions {
|
|
@@ -817,33 +1638,38 @@ declare class Stophy {
|
|
|
817
1638
|
constructor(input?: StophyClientInput);
|
|
818
1639
|
video(body: GetVideoData["body"] & {
|
|
819
1640
|
type: "details";
|
|
820
|
-
}): Promise<VideoResponseFor<
|
|
1641
|
+
}): Promise<VideoResponseFor<VideoResponseDetails>>;
|
|
821
1642
|
video(body: GetVideoData["body"] & {
|
|
822
1643
|
type: "transcript";
|
|
823
|
-
}): Promise<VideoResponseFor<
|
|
1644
|
+
}): Promise<VideoResponseFor<VideoResponseTranscript>>;
|
|
824
1645
|
video(body: GetVideoData["body"] & {
|
|
825
|
-
type: "comments"
|
|
826
|
-
}): Promise<VideoResponseFor<
|
|
1646
|
+
type: "comments";
|
|
1647
|
+
}): Promise<VideoResponseFor<VideoResponseComments>>;
|
|
1648
|
+
video(body: GetVideoData["body"] & {
|
|
1649
|
+
type: "replies";
|
|
1650
|
+
}): Promise<VideoResponseFor<VideoResponseReplies>>;
|
|
827
1651
|
video(body: GetVideoData["body"] & {
|
|
828
1652
|
type: "livechat";
|
|
829
|
-
}): Promise<VideoResponseFor<
|
|
1653
|
+
}): Promise<VideoResponseFor<VideoResponseLivechat>>;
|
|
830
1654
|
video(body: GetVideoData["body"]): Promise<GetVideoResponse>;
|
|
831
|
-
videoDetails(videoUrl: string): Promise<VideoResponseFor<
|
|
832
|
-
transcript(videoUrl: string): Promise<VideoResponseFor<
|
|
833
|
-
comments(videoUrl: string, options?: CommentsOptions): Promise<VideoResponseFor<
|
|
834
|
-
replies(continuationToken: string): Promise<VideoResponseFor<
|
|
835
|
-
liveChat(videoUrl: string, options?: LiveChatOptions): Promise<VideoResponseFor<
|
|
836
|
-
search(body: SearchVideosData["body"]): Promise<
|
|
837
|
-
search(query: string, options?: SearchOptions): Promise<
|
|
838
|
-
channel(body: GetChannelData["body"]): Promise<
|
|
839
|
-
channel(channelUrl: string, options?: ChannelOptions): Promise<
|
|
840
|
-
playlist(body: GetPlaylistData["body"]): Promise<
|
|
841
|
-
playlist(playlistUrl: string, options?: PlaylistOptions): Promise<
|
|
842
|
-
suggest(query: GetSuggestionsData["
|
|
843
|
-
suggest(query: string, options?: SuggestOptions): Promise<
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1655
|
+
videoDetails(videoUrl: string): Promise<VideoResponseFor<VideoResponseDetails>>;
|
|
1656
|
+
transcript(videoUrl: string, options?: TranscriptOptions): Promise<VideoResponseFor<VideoResponseTranscript>>;
|
|
1657
|
+
comments(videoUrl: string, options?: CommentsOptions): Promise<VideoResponseFor<VideoResponseComments>>;
|
|
1658
|
+
replies(continuationToken: string): Promise<VideoResponseFor<VideoResponseReplies>>;
|
|
1659
|
+
liveChat(videoUrl: string, options?: LiveChatOptions): Promise<VideoResponseFor<VideoResponseLivechat>>;
|
|
1660
|
+
search(body: SearchVideosData["body"]): Promise<SearchResponse>;
|
|
1661
|
+
search(query: string, options?: SearchOptions): Promise<SearchResponse>;
|
|
1662
|
+
channel(body: GetChannelData["body"]): Promise<ChannelResponse>;
|
|
1663
|
+
channel(channelUrl: string, options?: ChannelOptions): Promise<ChannelResponse>;
|
|
1664
|
+
playlist(body: GetPlaylistData["body"]): Promise<PlaylistResponse>;
|
|
1665
|
+
playlist(playlistUrl: string, options?: PlaylistOptions): Promise<PlaylistResponse>;
|
|
1666
|
+
suggest(query: GetSuggestionsData["body"]): Promise<SuggestResponse>;
|
|
1667
|
+
suggest(query: string, options?: SuggestOptions): Promise<SuggestResponse>;
|
|
1668
|
+
music<T extends MusicInput>(body: T): Promise<MeteredResponse<MusicDataFor<T["type"]>>>;
|
|
1669
|
+
kids<T extends KidsInput>(body: T): Promise<MeteredResponse<KidsDataFor<T["type"]>>>;
|
|
1670
|
+
credits(): Promise<CreditsResponse>;
|
|
1671
|
+
logs(query?: GetLogsData["query"]): Promise<LogsResponse>;
|
|
1672
|
+
usage(query?: GetUsageData["query"]): Promise<UsageResponse>;
|
|
847
1673
|
}
|
|
848
1674
|
|
|
849
1675
|
/** Thrown when the Stophy API responds with a non-success status. */
|
|
@@ -860,4 +1686,4 @@ declare class StophyError extends Error {
|
|
|
860
1686
|
});
|
|
861
1687
|
}
|
|
862
1688
|
|
|
863
|
-
export { type
|
|
1689
|
+
export { type AccountResponse, type ChannelOptions, type ChannelResponse, type ClientOptions, type Comment, type CommentsOptions, type CreditsResponse, type EmptyState, type ErrorResponse, type GetChannelData, type GetChannelError, type GetChannelErrors, type GetChannelResponse, type GetChannelResponses, type GetCreditsData, type GetCreditsError, type GetCreditsErrors, type GetCreditsResponse, type GetCreditsResponses, type GetLogsData, type GetLogsError, type GetLogsErrors, type GetLogsResponse, type GetLogsResponses, type GetPlaylistData, type GetPlaylistError, type GetPlaylistErrors, type GetPlaylistResponse, type GetPlaylistResponses, type GetSuggestionsData, type GetSuggestionsError, type GetSuggestionsErrors, type GetSuggestionsResponse, type GetSuggestionsResponses, type GetUsageData, type GetUsageError, type GetUsageErrors, type GetUsageResponse, type GetUsageResponses, type GetVideoData, type GetVideoError, type GetVideoErrors, type GetVideoResponse, type GetVideoResponses, type KidsDataFor, type KidsInput, type KidsResponseData, type KidsSearchData, type KidsVideoData, type KidsVideoDetails, type KidsVideoItem, type LiveChatOptions, type LogsResponse, type McpTool, type McpTransportHeaderData, type McpTransportHeaderError, type McpTransportHeaderErrors, type McpTransportHeaderResponse, type McpTransportHeaderResponses, type McpTransportPathData, type McpTransportPathError, type McpTransportPathErrors, type McpTransportPathResponse, type McpTransportPathResponses, type MeteredResponse, type MusicAlbumData, type MusicAlbumRef, type MusicArtistData, type MusicArtistRef, type MusicDataFor, type MusicInput, type MusicItem, type MusicLyricsData, type MusicPlaylistData, type MusicResponseData, type MusicSearchData, type MusicSong, type MusicSongData, type MusicSuggestData, type PlaylistOptions, type PlaylistResponse, type RelatedVideo, type Reply, type SearchOptions, type SearchResponse, type SearchVideosData, type SearchVideosError, type SearchVideosErrors, type SearchVideosResponse, type SearchVideosResponses, Stophy, type StophyClientInput, StophyError, type StophyOptions, type SuggestOptions, type SuggestResponse, type Thumbnail, type UsageResponse, type VideoDetail, type VideoRequestReplies, type VideoRequestVideoOp, type VideoResponseComments, type VideoResponseDetails, type VideoResponseLivechat, type VideoResponseReplies, type VideoResponseTranscript, type YoutubeKidsData, type YoutubeKidsError, type YoutubeKidsErrors, type YoutubeKidsResponse, type YoutubeKidsResponses, type YoutubeMusicData, type YoutubeMusicError, type YoutubeMusicErrors, type YoutubeMusicResponse, type YoutubeMusicResponses, Stophy as default };
|