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/dist/index.d.ts 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
- type EmptyState = {
27
- code: string;
28
- message: string;
29
- };
30
- type TranscriptLanguage = {
31
- code: string | null;
32
- name: string | null;
33
- isAutoGenerated: boolean;
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 TranscriptSegment = {
36
- start: number;
37
- duration: number;
38
- text: string;
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 TranscriptResult = {
41
- language: TranscriptLanguage;
42
- segments: Array<TranscriptSegment>;
43
- text: string;
44
- empty?: EmptyState;
50
+ type VideoRequestReplies = {
51
+ type: "replies";
52
+ continuationToken: string;
45
53
  };
46
- type VideoDetails = {
47
- id: string;
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 | null;
65
+ title: string;
51
66
  author: string | null;
52
67
  authorId: string | null;
53
- category: string | null;
54
68
  description: string | null;
55
- durationSec: number | null;
56
- durationText: string | null;
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
- viewCount: number | null;
63
- viewCountText: string | null;
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
- id: string;
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 | null;
87
- text: string | null;
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
- * Present for top-level comment requests.
129
+ * Token to fetch replies via type=replies.
107
130
  */
108
- videoId?: string;
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
- * Resolved sort order for top-level comment requests.
169
+ * Concatenated transcript text.
111
170
  */
112
- sortBy?: "any" | "latest" | "top";
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
- empty?: EmptyState;
181
+ hasMore: boolean;
116
182
  };
117
- type LiveChatMessage = {
118
- id: string;
119
- text: string;
120
- author: string | null;
121
- authorId: string | null;
122
- timestampUsec: string | null;
123
- isOwner: boolean;
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
- type LiveChatData = {
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<LiveChatMessage>;
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
- * Shape depends on the request `type`: details, transcript, comments/replies, or livechat.
237
+ * YouTube Music result item. URL fields are populated only when YouTube returns the matching identifier for that item type.
139
238
  */
140
- type VideoData = VideoDetailsData | TranscriptResult | CommentsData | LiveChatData;
141
- type SearchVideo = {
142
- type: "video";
143
- id: string;
144
- videoUrl: string;
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
- description: string | null;
251
+ album: MusicAlbumRef | null;
252
+ artists: Array<MusicArtistRef>;
149
253
  duration: string | null;
150
254
  durationSec: number | null;
151
255
  durationText: string | null;
152
- isLive: boolean;
153
- isUpcoming: boolean;
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 SearchShort = {
162
- type: "short";
260
+ type MusicSong = {
163
261
  id: string;
164
- shortUrl: string;
165
- title: string;
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
- videoCount: number | null;
178
- videoCountText: string | null;
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 SearchChannel = {
182
- type: "channel";
183
- id: string;
184
- channelUrl: string;
185
- name: string;
186
- handle: string | null;
187
- description: string | null;
188
- subscriberCount: number | null;
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 SearchItem = ({
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
- type?: "video" | "short" | "channel" | "playlist" | "movie";
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 ChannelLink = {
218
- title: string;
219
- url: string;
290
+ type MusicSongData = {
291
+ song: MusicSong;
292
+ } | {
293
+ empty: EmptyState;
220
294
  };
221
- type ChannelProfile = {
222
- id: string | null;
223
- name: string | null;
224
- handle: string | null;
225
- channelUrl: string | null;
226
- description: string | null;
227
- subscriberCount: number | null;
228
- subscriberCountText: string | null;
229
- videoCount: number | null;
230
- videoCountText: string | null;
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 ChannelVideo = {
241
- id: string;
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
- title: string | null;
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 ChannelPlaylist = {
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
- title: string | null;
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
- isPlayable: boolean;
318
- isUpcoming: boolean;
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 PlaylistData = {
327
- playlist: PlaylistMeta | null;
328
- items: Array<PlaylistItem>;
415
+ type KidsSearchData = {
416
+ items: Array<KidsVideoItem>;
329
417
  continuationToken: string | null;
330
- empty?: EmptyState;
331
- };
332
- type SuggestData = {
333
- q: string;
334
- hl: string;
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 CreditsData = {
339
- credits: number;
424
+ type KidsVideoData = {
425
+ video: KidsVideoDetails;
426
+ related: Array<KidsVideoItem>;
427
+ } | {
428
+ empty: EmptyState;
340
429
  };
341
- type LogEntry = {
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
- userId?: string;
344
- apiKeyId?: string | null;
345
- apiKeyName?: string | null;
346
- endpoint: string;
347
- method: string;
348
- status: number;
349
- credits: number;
350
- durationMs?: number | null;
351
- response?: string | null;
352
- createdAt: string;
353
- };
354
- type LogsData = {
355
- logs: Array<LogEntry>;
356
- total: number;
357
- page: number;
358
- pageSize: number;
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 GetVideoData = {
456
+ type SearchVideosData = {
371
457
  body: {
372
458
  /**
373
- * The type of data to retrieve.
459
+ * Search query.
374
460
  */
375
- type: "details" | "transcript" | "comments" | "livechat";
461
+ q: string;
376
462
  /**
377
- * Full YouTube video URL.
463
+ * Filter by content type.
378
464
  */
379
- videoUrl: string;
465
+ type?: "video" | "short" | "channel" | "playlist" | "movie";
466
+ /**
467
+ * Sort order. Defaults to relevance.
468
+ */
469
+ sortBy?: "relevance" | "popularity" | "date" | "rating";
380
470
  /**
381
- * Comment sort order. Only applies when type is comments.
471
+ * Filter by upload date.
382
472
  */
383
- sortBy?: "latest" | "top";
473
+ uploadDate?: "today" | "week" | "month" | "year";
384
474
  /**
385
- * 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.
475
+ * Duration filter. Not applicable when type is short.
386
476
  */
387
- chatType?: "top" | "live";
477
+ duration?: "short" | "medium" | "long";
388
478
  /**
389
- * For comments, pass a previous comments response token. For livechat, pass the previous livechat token to poll for new messages.
479
+ * Filter by video features.
390
480
  */
391
- continuationToken?: string;
392
- } | {
393
- type: "replies";
481
+ features?: Array<"live" | "4k" | "hd" | "subtitles" | "creativeCommons" | "360" | "vr180" | "3d" | "hdr" | "location" | "purchased">;
394
482
  /**
395
- * The repliesToken from a top-level comment.
483
+ * Token from a previous response to fetch the next page.
396
484
  */
397
- continuationToken: string;
485
+ continuationToken?: string;
398
486
  };
399
487
  path?: never;
400
488
  query?: never;
401
- url: "/v1/video";
489
+ url: "/v1/search";
402
490
  };
403
- type GetVideoErrors = {
491
+ type SearchVideosErrors = {
404
492
  /**
405
493
  * Validation error
406
494
  */
407
495
  400: ErrorResponse;
408
496
  /**
409
- * Invalid or missing API key
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
- * Video or captions not found
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
- * Upstream video data temporarily unavailable
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 GetVideoError = GetVideoErrors[keyof GetVideoErrors];
434
- type GetVideoResponses = {
517
+ type SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
518
+ type SearchVideosResponses = {
435
519
  /**
436
- * Successful response
520
+ * Search results
437
521
  */
438
522
  200: {
439
- success: true;
440
- requestId: string;
441
- data: VideoData;
442
- cacheState: "hit" | "miss";
443
- creditsUsed: number;
444
- creditsRemaining: number;
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 GetVideoResponse = GetVideoResponses[keyof GetVideoResponses];
448
- type SearchVideosData = {
616
+ type SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
617
+ type GetVideoData = {
449
618
  body: {
450
619
  /**
451
- * Search query.
452
- */
453
- q: string;
454
- /**
455
- * Filter by content type.
620
+ * The type of data to retrieve.
456
621
  */
457
- type?: "video" | "short" | "channel" | "playlist" | "movie";
622
+ type: "details" | "transcript" | "comments" | "livechat";
458
623
  /**
459
- * Sort order. Defaults to relevance.
624
+ * Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...).
460
625
  */
461
- sortBy?: "relevance" | "popularity" | "date" | "rating";
626
+ videoUrl: string;
462
627
  /**
463
- * Filter by upload date.
628
+ * Comment sort order: any (YouTube's default ordering), top, or latest. Only applies when type is 'comments'. Defaults to any.
464
629
  */
465
- uploadDate?: "today" | "week" | "month" | "year";
630
+ sortBy?: "any" | "top" | "latest";
466
631
  /**
467
- * Duration filter. Not applicable when type is short.
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
- duration?: "short" | "medium" | "long";
634
+ chatType?: "top" | "live";
470
635
  /**
471
- * Filter by video features.
636
+ * Preferred transcript language code. Only applies when type is 'transcript'.
472
637
  */
473
- features?: Array<"live" | "4k" | "hd" | "subtitles" | "creativeCommons" | "360" | "vr180" | "3d" | "hdr" | "location" | "purchased">;
638
+ lang?: string;
474
639
  /**
475
- * Token from a previous response to fetch the next page.
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/search";
652
+ url: "/v1/video";
482
653
  };
483
- type SearchVideosErrors = {
654
+ type GetVideoErrors = {
484
655
  /**
485
656
  * Validation error
486
657
  */
487
658
  400: ErrorResponse;
488
659
  /**
489
- * Unauthorized
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
- * Rate limited
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 SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
506
- type SearchVideosResponses = {
680
+ type GetVideoError = GetVideoErrors[keyof GetVideoErrors];
681
+ type GetVideoResponses = {
507
682
  /**
508
- * Search results
683
+ * Successful response
509
684
  */
510
685
  200: {
511
- success: true;
512
- requestId: string;
513
- data: SearchData;
514
- cacheState: "hit" | "miss";
515
- creditsUsed: number;
516
- creditsRemaining: number;
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 SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
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
- * Rate limited
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: true;
572
- requestId: string;
573
- data: ChannelData;
574
- cacheState: "hit" | "miss";
575
- creditsUsed: number;
576
- creditsRemaining: number;
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
- * Rate limited
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: true;
624
- requestId: string;
625
- data: PlaylistData;
626
- cacheState: "hit" | "miss";
627
- creditsUsed: number;
628
- creditsRemaining: number;
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?: never;
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
- * Rate limited
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: true;
676
- requestId: string;
677
- data: SuggestData;
678
- cacheState: "hit" | "miss";
679
- creditsUsed: number;
680
- creditsRemaining: number;
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: true;
703
- requestId: string;
704
- data: CreditsData;
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: true;
740
- requestId: string;
741
- data: LogsData;
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 GetUsageData = {
746
- body?: never;
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
- * Time window: 'today', the last 7 days, or the last 30 days.
1475
+ * Request identifier echoed in the response.
751
1476
  */
752
- days?: "today" | "7" | "30";
1477
+ id: unknown;
753
1478
  /**
754
- * Timezone offset in minutes used to bucket activity into days. Defaults to UTC.
1479
+ * JSON-RPC method, e.g. initialize, tools/list, tools/call.
755
1480
  */
756
- tz?: string;
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
- url: "/v1/usage";
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 GetUsageErrors = {
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 GetUsageError = GetUsageErrors[keyof GetUsageErrors];
767
- type GetUsageResponses = {
1508
+ type McpTransportPathError = McpTransportPathErrors[keyof McpTransportPathErrors];
1509
+ type McpTransportPathResponses = {
768
1510
  /**
769
- * Daily usage
1511
+ * MCP response
770
1512
  */
771
1513
  200: {
772
- success: true;
773
- requestId: string;
774
- data: UsageData;
1514
+ [key: string]: unknown;
775
1515
  };
776
1516
  };
777
- type GetUsageResponse = GetUsageResponses[keyof GetUsageResponses];
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 SuggestQuery = GetSuggestionsData["query"];
792
- type SuggestOptions = Omit<SuggestQuery, "q">;
1612
+ type SuggestBody = GetSuggestionsData["body"];
1613
+ type SuggestOptions = Omit<SuggestBody, "q">;
1614
+ type SuggestResponse = MeteredResponse<NonNullable<GetSuggestionsResponse["data"]>>;
793
1615
 
794
- type VideoResponseFor<T> = Omit<GetVideoResponse, "data"> & {
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<VideoDetailsData>>;
1641
+ }): Promise<VideoResponseFor<VideoResponseDetails>>;
821
1642
  video(body: GetVideoData["body"] & {
822
1643
  type: "transcript";
823
- }): Promise<VideoResponseFor<TranscriptResult>>;
1644
+ }): Promise<VideoResponseFor<VideoResponseTranscript>>;
824
1645
  video(body: GetVideoData["body"] & {
825
- type: "comments" | "replies";
826
- }): Promise<VideoResponseFor<CommentsData>>;
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<LiveChatData>>;
1653
+ }): Promise<VideoResponseFor<VideoResponseLivechat>>;
830
1654
  video(body: GetVideoData["body"]): Promise<GetVideoResponse>;
831
- videoDetails(videoUrl: string): Promise<VideoResponseFor<VideoDetailsData>>;
832
- transcript(videoUrl: string): Promise<VideoResponseFor<TranscriptResult>>;
833
- comments(videoUrl: string, options?: CommentsOptions): Promise<VideoResponseFor<CommentsData>>;
834
- replies(continuationToken: string): Promise<VideoResponseFor<CommentsData>>;
835
- liveChat(videoUrl: string, options?: LiveChatOptions): Promise<VideoResponseFor<LiveChatData>>;
836
- search(body: SearchVideosData["body"]): Promise<SearchVideosResponse>;
837
- search(query: string, options?: SearchOptions): Promise<SearchVideosResponse>;
838
- channel(body: GetChannelData["body"]): Promise<GetChannelResponse>;
839
- channel(channelUrl: string, options?: ChannelOptions): Promise<GetChannelResponse>;
840
- playlist(body: GetPlaylistData["body"]): Promise<GetPlaylistResponse>;
841
- playlist(playlistUrl: string, options?: PlaylistOptions): Promise<GetPlaylistResponse>;
842
- suggest(query: GetSuggestionsData["query"]): Promise<GetSuggestionsResponse>;
843
- suggest(query: string, options?: SuggestOptions): Promise<GetSuggestionsResponse>;
844
- credits(): Promise<GetCreditsResponse>;
845
- logs(query?: GetLogsData["query"]): Promise<GetLogsResponse>;
846
- usage(query?: GetUsageData["query"]): Promise<GetUsageResponse>;
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 ChannelData, type ChannelLink, type ChannelOptions, type ChannelPlaylist, type ChannelProfile, type ChannelShort, type ChannelVideo, type ClientOptions, type Comment, type CommentsData, type CommentsOptions, type ContentItem, type CreditsData, 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 LiveChatData, type LiveChatMessage, type LiveChatOptions, type LogEntry, type LogsData, type PlaylistData, type PlaylistItem, type PlaylistMeta, type PlaylistOptions, type RelatedVideo, type SearchChannel, type SearchData, type SearchItem, type SearchOptions, type SearchPlaylist, type SearchQuery, type SearchShort, type SearchVideo, type SearchVideosData, type SearchVideosError, type SearchVideosErrors, type SearchVideosResponse, type SearchVideosResponses, Stophy, type StophyClientInput, StophyError, type StophyOptions, type SuggestData, type SuggestOptions, type Thumbnail, type TranscriptLanguage, type TranscriptResult, type TranscriptSegment, type UsageData, type UsageItem, type VideoData, type VideoDetails, type VideoDetailsData, Stophy as default };
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 };