stophy 0.2.0 → 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.cts CHANGED
@@ -6,9 +6,9 @@ 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
- code?: "UNAUTHORIZED" | "INSUFFICIENT_CREDITS" | "BAD_REQUEST" | "INVALID_INPUT" | "NOT_FOUND" | "CONCURRENCY_LIMITED" | "INTERNAL_ERROR";
11
+ code?: "UNAUTHORIZED" | "INSUFFICIENT_CREDITS" | "BAD_REQUEST" | "INVALID_INPUT" | "NOT_FOUND" | "CONCURRENCY_LIMITED" | "UPSTREAM_UNAVAILABLE" | "INTERNAL_ERROR";
12
12
  /**
13
13
  * Human-readable error message.
14
14
  */
@@ -23,344 +23,478 @@ 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 = {
54
+ type VideoDetail = {
55
+ /**
56
+ * Item type discriminator. Always `video` for this schema.
57
+ */
58
+ type: "video";
47
59
  id: string;
48
- type?: "video";
60
+ /**
61
+ * Canonical URL alias for the item.
62
+ */
63
+ url: string;
49
64
  videoUrl: string;
50
- title: string | null;
51
- author?: string | null;
52
- authorId?: string | null;
53
- category?: string | null;
54
- description?: string | null;
55
- durationSec?: number | null;
56
- durationText?: string | null;
57
- isLive?: boolean;
58
- likeCount?: number | null;
59
- likeCountText?: string | null;
60
- publishedAt?: string | null;
61
- tags?: Array<string>;
62
- viewCount?: number | null;
63
- viewCountText?: string | null;
65
+ title: string;
66
+ author: string | null;
67
+ authorId: string | null;
68
+ description: string | null;
69
+ viewCount: number | null;
70
+ viewCountText: string | null;
71
+ likeCount: number | null;
72
+ likeCountText: string | null;
73
+ durationSec: number | null;
74
+ durationText: string | null;
75
+ publishedAt: string | null;
76
+ tags: Array<string>;
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 = {
87
+ /**
88
+ * Item type discriminator. Always `video` for this schema.
89
+ */
90
+ type: "video";
67
91
  id: string;
68
- type?: "video";
92
+ /**
93
+ * Canonical URL alias for the item.
94
+ */
95
+ url: string;
69
96
  videoUrl: string;
70
- title?: string | null;
71
- author?: string | null;
72
- authorId?: string | null;
73
- durationSec?: number | null;
74
- durationText?: string | null;
75
- publishedAt?: string | null;
76
- publishedAtText?: string | null;
77
- viewCount?: number | null;
78
- viewCountText?: string | null;
97
+ title: string | null;
98
+ author: string | null;
99
+ authorId: string | null;
100
+ viewCount: number | null;
101
+ viewCountText: string | null;
102
+ durationSec: number | null;
103
+ durationText: string | null;
104
+ publishedAt: string | null;
105
+ publishedAtText: 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;
90
- authorThumbnail?: string | null;
113
+ /**
114
+ * URL of the commenter’s channel avatar. Plain string URL, not an object.
115
+ */
116
+ authorThumbnail: string | null;
91
117
  hasChannelOwnerReplied: boolean;
92
118
  isChannelOwner: boolean;
93
119
  isHearted: boolean;
94
120
  isPinned: boolean;
95
121
  isVerified: boolean;
96
- publishedAt?: string | null;
97
- publishedAtText?: string | null;
98
- likeCount?: number | null;
99
- likeCountText?: string | null;
100
- replyCount?: number | null;
101
- replyCountText?: string | null;
102
- repliesToken?: string | null;
103
- };
104
- type CommentsData = {
122
+ publishedAt: string | null;
123
+ publishedAtText: string | null;
124
+ likeCount: number | null;
125
+ likeCountText: string | null;
126
+ replyCount: number | null;
127
+ replyCountText: string | null;
128
+ /**
129
+ * Token to fetch replies via type=replies.
130
+ */
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
+ }>;
168
+ /**
169
+ * Concatenated transcript text.
170
+ */
171
+ text: string;
172
+ };
173
+ /**
174
+ * Returned when type is 'comments'.
175
+ */
176
+ type VideoResponseComments = {
177
+ videoId: string;
178
+ sortBy: "any" | "top" | "latest";
105
179
  items: Array<Comment>;
106
180
  continuationToken: string | null;
107
- empty?: EmptyState;
181
+ hasMore: boolean;
108
182
  };
109
- type LiveChatMessage = {
110
- id: string;
111
- text: string;
112
- author?: string | null;
113
- authorId?: string | null;
114
- timestampUsec?: string | null;
115
- isOwner: boolean;
116
- isModerator: boolean;
117
- isVerified: boolean;
118
- superChatAmount?: string | null;
119
- 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;
120
190
  };
121
- type LiveChatData = {
122
- status: string;
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;
199
+ status: "live" | "upcoming" | "replay" | "chat_disabled" | "not_live";
123
200
  isLive: boolean;
124
- concurrentViewers?: number | null;
125
- pollIntervalMs?: number | null;
126
- messages: Array<LiveChatMessage>;
201
+ concurrentViewers: number | null;
202
+ /**
203
+ * Suggested delay before next poll.
204
+ */
205
+ pollIntervalMs: number | null;
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
+ }>;
127
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;
128
235
  };
129
236
  /**
130
- * 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.
131
238
  */
132
- type VideoData = VideoDetailsData | TranscriptResult | CommentsData | LiveChatData;
133
- type SearchVideo = {
134
- type: "video";
135
- id: string;
136
- 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;
137
248
  title: string;
138
- author?: string | null;
139
- authorId?: string | null;
140
- description?: string | null;
141
- duration?: string | null;
142
- durationSec?: number | null;
143
- durationText?: string | null;
144
- isLive?: boolean;
145
- isUpcoming?: boolean;
146
- isVerified?: boolean;
147
- viewCount?: number | null;
148
- viewCountText?: string | null;
149
- publishedAt?: string | null;
150
- publishedAtText?: string | null;
249
+ author: string | null;
250
+ authorId: string | null;
251
+ album: MusicAlbumRef | null;
252
+ artists: Array<MusicArtistRef>;
253
+ duration: string | null;
254
+ durationSec: number | null;
255
+ durationText: string | null;
256
+ isExplicit: boolean;
257
+ plays: string | null;
151
258
  thumbnails: Array<Thumbnail>;
152
259
  };
153
- type SearchShort = {
154
- type: "short";
260
+ type MusicSong = {
155
261
  id: string;
156
- shortUrl: string;
262
+ url: string;
263
+ videoUrl: string;
157
264
  title: string;
158
- author?: string | null;
159
- authorId?: string | null;
160
- description?: string | null;
161
- duration?: string | null;
162
- durationSec?: number | null;
163
- durationText?: string | null;
164
- viewCount?: number | null;
165
- viewCountText?: string | null;
166
- publishedAt?: string | null;
167
- publishedAtText?: string | null;
265
+ author: string | null;
266
+ authorId: 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;
168
275
  thumbnails: Array<Thumbnail>;
169
276
  };
170
- type SearchPlaylist = {
171
- type: "playlist";
172
- id: string;
173
- playlistUrl: string;
174
- title: string;
175
- author?: string | null;
176
- authorId?: string | null;
177
- videoCount?: number | null;
178
- videoCountText?: string | null;
179
- 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;
180
285
  };
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>;
286
+ type MusicSuggestData = {
287
+ q: string;
288
+ suggestions: Array<string>;
192
289
  };
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 SearchData = {
203
- items: Array<SearchItem>;
204
- continuationToken: string | null;
205
- estimatedResults?: number;
206
- empty?: EmptyState;
290
+ type MusicSongData = {
291
+ song: MusicSong;
292
+ } | {
293
+ empty: EmptyState;
207
294
  };
208
- type ChannelLink = {
209
- title: string;
210
- url: string;
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;
211
305
  };
212
- type ChannelProfile = {
213
- id: string | null;
214
- name: string | null;
215
- handle: string | null;
216
- channelUrl: string | null;
217
- description?: string | null;
218
- subscriberCount?: number | null;
219
- subscriberCountText?: string | null;
220
- videoCount?: number | null;
221
- videoCountText?: string | null;
222
- viewCount?: number | null;
223
- viewCountText?: string | null;
224
- isVerified: boolean;
225
- country?: string | null;
226
- joinedDate?: string | null;
227
- thumbnails: Array<Thumbnail>;
228
- banners: Array<Thumbnail>;
229
- links?: Array<ChannelLink> | null;
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;
230
323
  };
231
- type ContentItem = {
232
- id: string;
233
- type?: string;
234
- title?: string | null;
235
- videoUrl?: string;
236
- shortUrl?: string;
237
- playlistUrl?: string;
238
- author?: string | null;
239
- authorId?: string | null;
240
- durationSec?: number | null;
241
- durationText?: string | null;
242
- viewCount?: number | null;
243
- viewCountText?: string | null;
244
- publishedAt?: string | null;
245
- publishedAtText?: string | null;
246
- thumbnails: Array<Thumbnail>;
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;
247
351
  };
248
- type ChannelData = {
249
- channel: ChannelProfile | null;
250
- tab?: string | null;
251
- items?: Array<ContentItem>;
252
- continuationToken?: string | null;
253
- empty?: EmptyState;
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;
254
370
  };
255
- type PlaylistMeta = {
371
+ /**
372
+ * Response payload varies by request `type`.
373
+ */
374
+ type MusicResponseData = MusicSearchData | MusicSuggestData | MusicSongData | MusicLyricsData | MusicAlbumData | MusicArtistData | MusicPlaylistData;
375
+ type KidsVideoItem = {
376
+ type: "video";
256
377
  id: string;
257
- type?: "playlist";
258
- playlistUrl: string;
259
- title?: string | null;
260
- author?: string | null;
261
- authorId?: string | null;
262
- description?: string | null;
263
- videoCount?: string | null;
378
+ url: string;
379
+ videoUrl: string;
380
+ kidsUrl: string;
381
+ title: string;
382
+ author: string | null;
383
+ authorId: string | null;
384
+ authorUrl: string | null;
385
+ duration: string | null;
386
+ durationSec: number | null;
387
+ durationText: string | null;
388
+ publishedAt: string | null;
389
+ publishedAtText: string | null;
390
+ viewCount: number | null;
391
+ viewCountText: string | null;
264
392
  thumbnails: Array<Thumbnail>;
265
393
  };
266
- type PlaylistItem = {
394
+ type KidsVideoDetails = {
395
+ type: "video";
267
396
  id: string;
268
- type?: "video";
397
+ url: string;
269
398
  videoUrl: string;
270
- title?: string | null;
271
- author?: string | null;
272
- authorId?: string | null;
273
- durationSec?: number | null;
274
- durationText?: string | null;
275
- index?: number | null;
276
- isLive?: boolean;
277
- isPlayable?: boolean;
278
- isUpcoming?: boolean;
279
- upcomingAt?: string | null;
280
- viewCount?: number | null;
281
- viewCountText?: string | null;
282
- publishedAt?: string | null;
283
- publishedAtText?: string | null;
399
+ kidsUrl: string;
400
+ title: string;
401
+ author: string | null;
402
+ authorId: string | null;
403
+ authorUrl: string | null;
404
+ description: string | null;
405
+ duration: string | null;
406
+ durationSec: number | null;
407
+ durationText: string | null;
408
+ isLive: boolean;
409
+ isLiveContent: boolean;
410
+ keywords: Array<string>;
411
+ viewCount: number | null;
412
+ viewCountText: string | null;
284
413
  thumbnails: Array<Thumbnail>;
285
414
  };
286
- type PlaylistData = {
287
- playlist: PlaylistMeta | null;
288
- items: Array<PlaylistItem>;
415
+ type KidsSearchData = {
416
+ items: Array<KidsVideoItem>;
289
417
  continuationToken: string | null;
290
- empty?: EmptyState;
291
- };
292
- type SuggestData = {
293
- q: string;
294
- hl: string;
295
- gl: string;
296
- suggestions: Array<string>;
418
+ hasMore: boolean;
419
+ /**
420
+ * Present only when the operation yields no results.
421
+ */
422
+ empty?: EmptyState | null;
297
423
  };
298
- type CreditsData = {
299
- credits: number;
424
+ type KidsVideoData = {
425
+ video: KidsVideoDetails;
426
+ related: Array<KidsVideoItem>;
427
+ } | {
428
+ empty: EmptyState;
300
429
  };
301
- 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 = {
302
438
  id: string;
303
- userId?: string;
304
- apiKeyId?: string | null;
305
- apiKeyName?: string | null;
306
- endpoint: string;
307
- method: string;
308
- status: number;
309
- credits: number;
310
- durationMs?: number | null;
311
- response?: string | null;
312
- createdAt: string;
313
- };
314
- type LogsData = {
315
- logs: Array<LogEntry>;
316
- total: number;
317
- page: number;
318
- pageSize: number;
319
- totalPages: number;
320
- endpoints: Array<string>;
321
- };
322
- type UsageItem = {
323
- date: string;
324
- credits: number;
325
- requests: number;
326
- };
327
- type UsageData = {
328
- 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;
329
455
  };
330
- type GetVideoData = {
456
+ type SearchVideosData = {
331
457
  body: {
332
458
  /**
333
- * The type of data to retrieve.
459
+ * Search query.
334
460
  */
335
- type: "details" | "transcript" | "comments" | "replies" | "livechat";
461
+ q: string;
336
462
  /**
337
- * Full YouTube video URL. Not required when type is replies.
463
+ * Filter by content type.
338
464
  */
339
- videoUrl: string;
465
+ type?: "video" | "short" | "channel" | "playlist" | "movie";
340
466
  /**
341
- * Comment sort order. Only applies when type is comments.
467
+ * Sort order. Defaults to relevance.
342
468
  */
343
- sortBy?: "latest" | "top";
469
+ sortBy?: "relevance" | "popularity" | "date" | "rating";
344
470
  /**
345
- * 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.
471
+ * Filter by upload date.
346
472
  */
347
- chatType?: "top" | "live";
473
+ uploadDate?: "today" | "week" | "month" | "year";
474
+ /**
475
+ * Duration filter. Not applicable when type is short.
476
+ */
477
+ duration?: "short" | "medium" | "long";
348
478
  /**
349
- * Pagination token. Required when type is replies (use the repliesToken from a comment item); for livechat, pass the continuationToken from a previous livechat response to poll for new messages.
479
+ * Filter by video features.
480
+ */
481
+ features?: Array<"live" | "4k" | "hd" | "subtitles" | "creativeCommons" | "360" | "vr180" | "3d" | "hdr" | "location" | "purchased">;
482
+ /**
483
+ * Token from a previous response to fetch the next page.
350
484
  */
351
485
  continuationToken?: string;
352
486
  };
353
487
  path?: never;
354
488
  query?: never;
355
- url: "/v1/video";
489
+ url: "/v1/search";
356
490
  };
357
- type GetVideoErrors = {
491
+ type SearchVideosErrors = {
358
492
  /**
359
493
  * Validation error
360
494
  */
361
495
  400: ErrorResponse;
362
496
  /**
363
- * Invalid or missing API key
497
+ * Unauthorized
364
498
  */
365
499
  401: ErrorResponse;
366
500
  /**
@@ -368,71 +502,162 @@ type GetVideoErrors = {
368
502
  */
369
503
  402: ErrorResponse;
370
504
  /**
371
- * Rate limited
505
+ * Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
372
506
  */
373
507
  429: ErrorResponse;
374
508
  /**
375
509
  * Internal error
376
510
  */
377
511
  500: ErrorResponse;
512
+ /**
513
+ * Transient upstream failure (UPSTREAM_UNAVAILABLE). YouTube was unreachable or bot-checked; the credit is refunded. Retry the request.
514
+ */
515
+ 503: ErrorResponse;
378
516
  };
379
- type GetVideoError = GetVideoErrors[keyof GetVideoErrors];
380
- type GetVideoResponses = {
517
+ type SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
518
+ type SearchVideosResponses = {
381
519
  /**
382
- * Successful response
520
+ * Search results
383
521
  */
384
522
  200: {
385
- success: true;
386
- requestId: string;
387
- data: VideoData;
388
- cacheState: "hit" | "miss";
389
- creditsUsed: number;
390
- 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
+ };
391
614
  };
392
615
  };
393
- type GetVideoResponse = GetVideoResponses[keyof GetVideoResponses];
394
- type SearchVideosData = {
616
+ type SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
617
+ type GetVideoData = {
395
618
  body: {
396
619
  /**
397
- * Search query.
620
+ * The type of data to retrieve.
398
621
  */
399
- q: string;
622
+ type: "details" | "transcript" | "comments" | "livechat";
400
623
  /**
401
- * Filter by content type.
624
+ * Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...).
402
625
  */
403
- type?: "video" | "short" | "channel" | "playlist" | "movie";
626
+ videoUrl: string;
404
627
  /**
405
- * Sort order. Defaults to relevance.
628
+ * Comment sort order: any (YouTube's default ordering), top, or latest. Only applies when type is 'comments'. Defaults to any.
406
629
  */
407
- sortBy?: "relevance" | "popularity" | "date" | "rating";
630
+ sortBy?: "any" | "top" | "latest";
408
631
  /**
409
- * Filter by upload date.
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.
410
633
  */
411
- uploadDate?: "today" | "week" | "month" | "year";
634
+ chatType?: "top" | "live";
412
635
  /**
413
- * Duration filter. Not applicable when type is short.
636
+ * Preferred transcript language code. Only applies when type is 'transcript'.
414
637
  */
415
- duration?: "short" | "medium" | "long";
638
+ lang?: string;
416
639
  /**
417
- * Filter by video features.
640
+ * Pagination token. For 'livechat', pass the continuationToken from a previous livechat response to poll for new messages.
418
641
  */
419
- features?: Array<"live" | "4k" | "hd" | "subtitles" | "creativeCommons" | "360" | "vr180" | "3d" | "hdr" | "location" | "purchased">;
642
+ continuationToken?: string;
643
+ } | {
644
+ type: "replies";
420
645
  /**
421
- * Token from a previous response to fetch the next page.
646
+ * The repliesToken from a previous comments response.
422
647
  */
423
- continuationToken?: string;
648
+ continuationToken: string;
424
649
  };
425
650
  path?: never;
426
651
  query?: never;
427
- url: "/v1/search";
652
+ url: "/v1/video";
428
653
  };
429
- type SearchVideosErrors = {
654
+ type GetVideoErrors = {
430
655
  /**
431
656
  * Validation error
432
657
  */
433
658
  400: ErrorResponse;
434
659
  /**
435
- * Unauthorized
660
+ * Invalid or missing API key
436
661
  */
437
662
  401: ErrorResponse;
438
663
  /**
@@ -440,29 +665,46 @@ type SearchVideosErrors = {
440
665
  */
441
666
  402: ErrorResponse;
442
667
  /**
443
- * Rate limited
668
+ * Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
444
669
  */
445
670
  429: ErrorResponse;
446
671
  /**
447
672
  * Internal error
448
673
  */
449
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;
450
679
  };
451
- type SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
452
- type SearchVideosResponses = {
680
+ type GetVideoError = GetVideoErrors[keyof GetVideoErrors];
681
+ type GetVideoResponses = {
453
682
  /**
454
- * Search results
683
+ * Successful response
455
684
  */
456
685
  200: {
457
- success: true;
458
- requestId: string;
459
- data: SearchData;
460
- cacheState: "hit" | "miss";
461
- creditsUsed: number;
462
- 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);
463
705
  };
464
706
  };
465
- type SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
707
+ type GetVideoResponse = GetVideoResponses[keyof GetVideoResponses];
466
708
  type GetChannelData = {
467
709
  body: {
468
710
  /**
@@ -472,7 +714,11 @@ type GetChannelData = {
472
714
  /**
473
715
  * Content tab to fetch. Defaults to video.
474
716
  */
475
- 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;
476
722
  /**
477
723
  * Token from a previous response to fetch the next page.
478
724
  */
@@ -500,13 +746,17 @@ type GetChannelErrors = {
500
746
  */
501
747
  402: ErrorResponse;
502
748
  /**
503
- * Rate limited
749
+ * Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
504
750
  */
505
751
  429: ErrorResponse;
506
752
  /**
507
753
  * Internal error
508
754
  */
509
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;
510
760
  };
511
761
  type GetChannelError = GetChannelErrors[keyof GetChannelErrors];
512
762
  type GetChannelResponses = {
@@ -514,12 +764,183 @@ type GetChannelResponses = {
514
764
  * Channel data
515
765
  */
516
766
  200: {
517
- success: true;
518
- requestId: string;
519
- data: ChannelData;
520
- cacheState: "hit" | "miss";
521
- creditsUsed: number;
522
- 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
+ };
523
944
  };
524
945
  };
525
946
  type GetChannelResponse = GetChannelResponses[keyof GetChannelResponses];
@@ -552,13 +973,17 @@ type GetPlaylistErrors = {
552
973
  */
553
974
  402: ErrorResponse;
554
975
  /**
555
- * Rate limited
976
+ * Concurrency limited. Too many requests in flight for your plan; retry once an in-flight request finishes.
556
977
  */
557
978
  429: ErrorResponse;
558
979
  /**
559
980
  * Internal error
560
981
  */
561
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;
562
987
  };
563
988
  type GetPlaylistError = GetPlaylistErrors[keyof GetPlaylistErrors];
564
989
  type GetPlaylistResponses = {
@@ -566,19 +991,83 @@ type GetPlaylistResponses = {
566
991
  * Playlist items
567
992
  */
568
993
  200: {
569
- success: true;
570
- requestId: string;
571
- data: PlaylistData;
572
- cacheState: "hit" | "miss";
573
- creditsUsed: number;
574
- 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
+ };
575
1066
  };
576
1067
  };
577
1068
  type GetPlaylistResponse = GetPlaylistResponses[keyof GetPlaylistResponses];
578
1069
  type GetSuggestionsData = {
579
- body?: never;
580
- path?: never;
581
- query: {
1070
+ body: {
582
1071
  /**
583
1072
  * Search query.
584
1073
  */
@@ -592,6 +1081,8 @@ type GetSuggestionsData = {
592
1081
  */
593
1082
  gl?: string;
594
1083
  };
1084
+ path?: never;
1085
+ query?: never;
595
1086
  url: "/v1/suggest";
596
1087
  };
597
1088
  type GetSuggestionsErrors = {
@@ -604,13 +1095,21 @@ type GetSuggestionsErrors = {
604
1095
  */
605
1096
  401: ErrorResponse;
606
1097
  /**
607
- * 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.
608
1103
  */
609
1104
  429: ErrorResponse;
610
1105
  /**
611
1106
  * Internal error
612
1107
  */
613
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;
614
1113
  };
615
1114
  type GetSuggestionsError = GetSuggestionsErrors[keyof GetSuggestionsErrors];
616
1115
  type GetSuggestionsResponses = {
@@ -618,15 +1117,161 @@ type GetSuggestionsResponses = {
618
1117
  * Autocomplete suggestions
619
1118
  */
620
1119
  200: {
621
- success: true;
622
- requestId: string;
623
- data: SuggestData;
624
- cacheState: "hit" | "miss";
625
- creditsUsed: number;
626
- 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
+ };
627
1128
  };
628
1129
  };
629
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];
630
1275
  type GetCreditsData = {
631
1276
  body?: never;
632
1277
  path?: never;
@@ -645,12 +1290,59 @@ type GetCreditsResponses = {
645
1290
  * Credit balance
646
1291
  */
647
1292
  200: {
648
- success: true;
649
- requestId: string;
650
- data: CreditsData;
1293
+ success?: true;
1294
+ requestId?: string;
1295
+ data?: {
1296
+ /**
1297
+ * Current credit balance.
1298
+ */
1299
+ credits?: number;
1300
+ };
651
1301
  };
652
1302
  };
653
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];
654
1346
  type GetLogsData = {
655
1347
  body?: never;
656
1348
  path?: never;
@@ -682,66 +1374,252 @@ type GetLogsResponses = {
682
1374
  * Request logs
683
1375
  */
684
1376
  200: {
685
- success: true;
686
- requestId: string;
687
- 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
+ };
688
1420
  };
689
1421
  };
690
1422
  type GetLogsResponse = GetLogsResponses[keyof GetLogsResponses];
691
- type GetUsageData = {
692
- 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
+ };
693
1444
  path?: never;
694
- 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";
695
1474
  /**
696
- * Time window: 'today', the last 7 days, or the last 30 days.
1475
+ * Request identifier echoed in the response.
697
1476
  */
698
- days?: "today" | "7" | "30";
1477
+ id: unknown;
699
1478
  /**
700
- * Timezone offset in minutes used to bucket activity into days. Defaults to UTC.
1479
+ * JSON-RPC method, e.g. initialize, tools/list, tools/call.
701
1480
  */
702
- 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;
703
1488
  };
704
- 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}";
705
1497
  };
706
- type GetUsageErrors = {
1498
+ type McpTransportPathErrors = {
707
1499
  /**
708
1500
  * Unauthorized
709
1501
  */
710
1502
  401: ErrorResponse;
1503
+ /**
1504
+ * Method not allowed. Use POST.
1505
+ */
1506
+ 405: ErrorResponse;
711
1507
  };
712
- type GetUsageError = GetUsageErrors[keyof GetUsageErrors];
713
- type GetUsageResponses = {
1508
+ type McpTransportPathError = McpTransportPathErrors[keyof McpTransportPathErrors];
1509
+ type McpTransportPathResponses = {
714
1510
  /**
715
- * Daily usage
1511
+ * MCP response
716
1512
  */
717
1513
  200: {
718
- success: true;
719
- requestId: string;
720
- data: UsageData;
1514
+ [key: string]: unknown;
721
1515
  };
722
1516
  };
723
- type GetUsageResponse = GetUsageResponses[keyof GetUsageResponses];
1517
+ type McpTransportPathResponse = McpTransportPathResponses[keyof McpTransportPathResponses];
724
1518
  type ClientOptions = {
725
1519
  baseUrl: "https://api.stophy.dev" | (string & {});
726
1520
  };
727
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
+
728
1541
  type ChannelBody = GetChannelData["body"];
729
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;
730
1603
 
731
1604
  type PlaylistBody = GetPlaylistData["body"];
732
1605
  type PlaylistOptions = Omit<PlaylistBody, "playlistUrl">;
1606
+ type PlaylistResponse = MeteredResponse<NonNullable<GetPlaylistResponse["data"]>>;
733
1607
 
734
1608
  type SearchBody = SearchVideosData["body"];
735
1609
  type SearchOptions = Omit<SearchBody, "q">;
1610
+ type SearchResponse = MeteredResponse<NonNullable<SearchVideosResponse["data"]>>;
736
1611
 
737
- type SuggestQuery = GetSuggestionsData["query"];
738
- type SuggestOptions = Omit<SuggestQuery, "q">;
1612
+ type SuggestBody = GetSuggestionsData["body"];
1613
+ type SuggestOptions = Omit<SuggestBody, "q">;
1614
+ type SuggestResponse = MeteredResponse<NonNullable<GetSuggestionsResponse["data"]>>;
739
1615
 
740
- type VideoResponseFor<T> = Omit<GetVideoResponse, "data"> & {
741
- data: T;
742
- };
743
- type CommentsOptions = Pick<GetVideoData["body"], "sortBy" | "continuationToken">;
744
- type LiveChatOptions = Pick<GetVideoData["body"], "chatType" | "continuationToken">;
1616
+ type VideoResponseFor<T> = MeteredResponse<T>;
1617
+ type VideoUrlBody = Extract<GetVideoData["body"], {
1618
+ videoUrl: string;
1619
+ }>;
1620
+ type CommentsOptions = Pick<VideoUrlBody, "sortBy" | "continuationToken">;
1621
+ type TranscriptOptions = Pick<VideoUrlBody, "lang">;
1622
+ type LiveChatOptions = Pick<VideoUrlBody, "chatType" | "continuationToken">;
745
1623
 
746
1624
  interface StophyOptions {
747
1625
  /** Defaults to `STOPHY_API_KEY`. */
@@ -760,33 +1638,38 @@ declare class Stophy {
760
1638
  constructor(input?: StophyClientInput);
761
1639
  video(body: GetVideoData["body"] & {
762
1640
  type: "details";
763
- }): Promise<VideoResponseFor<VideoDetailsData>>;
1641
+ }): Promise<VideoResponseFor<VideoResponseDetails>>;
764
1642
  video(body: GetVideoData["body"] & {
765
1643
  type: "transcript";
766
- }): Promise<VideoResponseFor<TranscriptResult>>;
1644
+ }): Promise<VideoResponseFor<VideoResponseTranscript>>;
1645
+ video(body: GetVideoData["body"] & {
1646
+ type: "comments";
1647
+ }): Promise<VideoResponseFor<VideoResponseComments>>;
767
1648
  video(body: GetVideoData["body"] & {
768
- type: "comments" | "replies";
769
- }): Promise<VideoResponseFor<CommentsData>>;
1649
+ type: "replies";
1650
+ }): Promise<VideoResponseFor<VideoResponseReplies>>;
770
1651
  video(body: GetVideoData["body"] & {
771
1652
  type: "livechat";
772
- }): Promise<VideoResponseFor<LiveChatData>>;
1653
+ }): Promise<VideoResponseFor<VideoResponseLivechat>>;
773
1654
  video(body: GetVideoData["body"]): Promise<GetVideoResponse>;
774
- videoDetails(videoUrl: string): Promise<VideoResponseFor<VideoDetailsData>>;
775
- transcript(videoUrl: string): Promise<VideoResponseFor<TranscriptResult>>;
776
- comments(videoUrl: string, options?: CommentsOptions): Promise<VideoResponseFor<CommentsData>>;
777
- replies(continuationToken: string): Promise<VideoResponseFor<CommentsData>>;
778
- liveChat(videoUrl: string, options?: LiveChatOptions): Promise<VideoResponseFor<LiveChatData>>;
779
- search(body: SearchVideosData["body"]): Promise<SearchVideosResponse>;
780
- search(query: string, options?: SearchOptions): Promise<SearchVideosResponse>;
781
- channel(body: GetChannelData["body"]): Promise<GetChannelResponse>;
782
- channel(channelUrl: string, options?: ChannelOptions): Promise<GetChannelResponse>;
783
- playlist(body: GetPlaylistData["body"]): Promise<GetPlaylistResponse>;
784
- playlist(playlistUrl: string, options?: PlaylistOptions): Promise<GetPlaylistResponse>;
785
- suggest(query: GetSuggestionsData["query"]): Promise<GetSuggestionsResponse>;
786
- suggest(query: string, options?: SuggestOptions): Promise<GetSuggestionsResponse>;
787
- credits(): Promise<GetCreditsResponse>;
788
- logs(query?: GetLogsData["query"]): Promise<GetLogsResponse>;
789
- 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>;
790
1673
  }
791
1674
 
792
1675
  /** Thrown when the Stophy API responds with a non-success status. */
@@ -803,4 +1686,4 @@ declare class StophyError extends Error {
803
1686
  });
804
1687
  }
805
1688
 
806
- export { type ChannelData, type ChannelLink, type ChannelOptions, type ChannelProfile, 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 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 };