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/README.md +20 -6
- package/dist/index.cjs +73 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1263 -380
- package/dist/index.d.ts +1263 -380
- package/dist/index.js +73 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
/**
|
|
27
|
+
* An MCP tool exposed by the Stophy MCP server.
|
|
28
|
+
*/
|
|
29
|
+
type McpTool = {
|
|
30
|
+
name?: "stophy_search_videos" | "stophy_get_video" | "stophy_get_channel" | "stophy_get_playlist" | "stophy_get_suggestions" | "stophy_music" | "stophy_kids" | "stophy_get_credits";
|
|
31
|
+
description?: string;
|
|
32
|
+
inputSchema?: {
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
};
|
|
34
35
|
};
|
|
35
|
-
type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
type VideoRequestVideoOp = {
|
|
37
|
+
type: "details" | "transcript" | "comments" | "livechat";
|
|
38
|
+
videoUrl: string;
|
|
39
|
+
/**
|
|
40
|
+
* Comment sort order: any (YouTube's default ordering), top, or latest. Only applies when type is 'comments'. Defaults to any.
|
|
41
|
+
*/
|
|
42
|
+
sortBy?: "any" | "top" | "latest";
|
|
43
|
+
chatType?: "top" | "live";
|
|
44
|
+
/**
|
|
45
|
+
* Preferred transcript language code. Only applies when type is transcript.
|
|
46
|
+
*/
|
|
47
|
+
lang?: string;
|
|
48
|
+
continuationToken?: string;
|
|
39
49
|
};
|
|
40
|
-
type
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
text: string;
|
|
44
|
-
empty?: EmptyState;
|
|
50
|
+
type VideoRequestReplies = {
|
|
51
|
+
type: "replies";
|
|
52
|
+
continuationToken: string;
|
|
45
53
|
};
|
|
46
|
-
type
|
|
54
|
+
type VideoDetail = {
|
|
55
|
+
/**
|
|
56
|
+
* Item type discriminator. Always `video` for this schema.
|
|
57
|
+
*/
|
|
58
|
+
type: "video";
|
|
47
59
|
id: string;
|
|
48
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Canonical URL alias for the item.
|
|
62
|
+
*/
|
|
63
|
+
url: string;
|
|
49
64
|
videoUrl: string;
|
|
50
|
-
title: string
|
|
51
|
-
author
|
|
52
|
-
authorId
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
publishedAt
|
|
61
|
-
tags
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Canonical URL alias for the item.
|
|
94
|
+
*/
|
|
95
|
+
url: string;
|
|
69
96
|
videoUrl: string;
|
|
70
|
-
title
|
|
71
|
-
author
|
|
72
|
-
authorId
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
87
|
-
text: string
|
|
109
|
+
id: string;
|
|
110
|
+
text: string;
|
|
88
111
|
author: string | null;
|
|
89
112
|
authorId: string | null;
|
|
90
|
-
|
|
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
|
|
97
|
-
publishedAtText
|
|
98
|
-
likeCount
|
|
99
|
-
likeCountText
|
|
100
|
-
replyCount
|
|
101
|
-
replyCountText
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
181
|
+
hasMore: boolean;
|
|
108
182
|
};
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
122
|
-
|
|
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
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
*
|
|
237
|
+
* YouTube Music result item. URL fields are populated only when YouTube returns the matching identifier for that item type.
|
|
131
238
|
*/
|
|
132
|
-
type
|
|
133
|
-
type
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
videoUrl
|
|
239
|
+
type MusicItem = {
|
|
240
|
+
type: "song" | "video" | "album" | "artist" | "playlist" | "podcast" | "episode" | "profile";
|
|
241
|
+
id: string | null;
|
|
242
|
+
url: string | null;
|
|
243
|
+
videoUrl?: string | null;
|
|
244
|
+
playlistUrl?: string | null;
|
|
245
|
+
channelUrl?: string | null;
|
|
246
|
+
albumUrl?: string | null;
|
|
247
|
+
artistUrl?: string | null;
|
|
137
248
|
title: string;
|
|
138
|
-
author
|
|
139
|
-
authorId
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
|
154
|
-
type: "short";
|
|
260
|
+
type MusicSong = {
|
|
155
261
|
id: string;
|
|
156
|
-
|
|
262
|
+
url: string;
|
|
263
|
+
videoUrl: string;
|
|
157
264
|
title: string;
|
|
158
|
-
author
|
|
159
|
-
authorId
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
|
182
|
-
|
|
183
|
-
|
|
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
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
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
|
|
209
|
-
|
|
210
|
-
|
|
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
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
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
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
|
394
|
+
type KidsVideoDetails = {
|
|
395
|
+
type: "video";
|
|
267
396
|
id: string;
|
|
268
|
-
|
|
397
|
+
url: string;
|
|
269
398
|
videoUrl: string;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
287
|
-
|
|
288
|
-
items: Array<PlaylistItem>;
|
|
415
|
+
type KidsSearchData = {
|
|
416
|
+
items: Array<KidsVideoItem>;
|
|
289
417
|
continuationToken: string | null;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
|
299
|
-
|
|
424
|
+
type KidsVideoData = {
|
|
425
|
+
video: KidsVideoDetails;
|
|
426
|
+
related: Array<KidsVideoItem>;
|
|
427
|
+
} | {
|
|
428
|
+
empty: EmptyState;
|
|
300
429
|
};
|
|
301
|
-
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
|
456
|
+
type SearchVideosData = {
|
|
331
457
|
body: {
|
|
332
458
|
/**
|
|
333
|
-
*
|
|
459
|
+
* Search query.
|
|
334
460
|
*/
|
|
335
|
-
|
|
461
|
+
q: string;
|
|
336
462
|
/**
|
|
337
|
-
*
|
|
463
|
+
* Filter by content type.
|
|
338
464
|
*/
|
|
339
|
-
|
|
465
|
+
type?: "video" | "short" | "channel" | "playlist" | "movie";
|
|
340
466
|
/**
|
|
341
|
-
*
|
|
467
|
+
* Sort order. Defaults to relevance.
|
|
342
468
|
*/
|
|
343
|
-
sortBy?: "
|
|
469
|
+
sortBy?: "relevance" | "popularity" | "date" | "rating";
|
|
344
470
|
/**
|
|
345
|
-
*
|
|
471
|
+
* Filter by upload date.
|
|
346
472
|
*/
|
|
347
|
-
|
|
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
|
-
*
|
|
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/
|
|
489
|
+
url: "/v1/search";
|
|
356
490
|
};
|
|
357
|
-
type
|
|
491
|
+
type SearchVideosErrors = {
|
|
358
492
|
/**
|
|
359
493
|
* Validation error
|
|
360
494
|
*/
|
|
361
495
|
400: ErrorResponse;
|
|
362
496
|
/**
|
|
363
|
-
*
|
|
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
|
-
*
|
|
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
|
|
380
|
-
type
|
|
517
|
+
type SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
|
|
518
|
+
type SearchVideosResponses = {
|
|
381
519
|
/**
|
|
382
|
-
*
|
|
520
|
+
* Search results
|
|
383
521
|
*/
|
|
384
522
|
200: {
|
|
385
|
-
success
|
|
386
|
-
requestId
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
|
394
|
-
type
|
|
616
|
+
type SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
|
|
617
|
+
type GetVideoData = {
|
|
395
618
|
body: {
|
|
396
619
|
/**
|
|
397
|
-
*
|
|
620
|
+
* The type of data to retrieve.
|
|
398
621
|
*/
|
|
399
|
-
|
|
622
|
+
type: "details" | "transcript" | "comments" | "livechat";
|
|
400
623
|
/**
|
|
401
|
-
*
|
|
624
|
+
* Full YouTube video URL (e.g. https://www.youtube.com/watch?v=...).
|
|
402
625
|
*/
|
|
403
|
-
|
|
626
|
+
videoUrl: string;
|
|
404
627
|
/**
|
|
405
|
-
*
|
|
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?: "
|
|
630
|
+
sortBy?: "any" | "top" | "latest";
|
|
408
631
|
/**
|
|
409
|
-
*
|
|
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
|
-
|
|
634
|
+
chatType?: "top" | "live";
|
|
412
635
|
/**
|
|
413
|
-
*
|
|
636
|
+
* Preferred transcript language code. Only applies when type is 'transcript'.
|
|
414
637
|
*/
|
|
415
|
-
|
|
638
|
+
lang?: string;
|
|
416
639
|
/**
|
|
417
|
-
*
|
|
640
|
+
* Pagination token. For 'livechat', pass the continuationToken from a previous livechat response to poll for new messages.
|
|
418
641
|
*/
|
|
419
|
-
|
|
642
|
+
continuationToken?: string;
|
|
643
|
+
} | {
|
|
644
|
+
type: "replies";
|
|
420
645
|
/**
|
|
421
|
-
*
|
|
646
|
+
* The repliesToken from a previous comments response.
|
|
422
647
|
*/
|
|
423
|
-
continuationToken
|
|
648
|
+
continuationToken: string;
|
|
424
649
|
};
|
|
425
650
|
path?: never;
|
|
426
651
|
query?: never;
|
|
427
|
-
url: "/v1/
|
|
652
|
+
url: "/v1/video";
|
|
428
653
|
};
|
|
429
|
-
type
|
|
654
|
+
type GetVideoErrors = {
|
|
430
655
|
/**
|
|
431
656
|
* Validation error
|
|
432
657
|
*/
|
|
433
658
|
400: ErrorResponse;
|
|
434
659
|
/**
|
|
435
|
-
*
|
|
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
|
-
*
|
|
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
|
|
452
|
-
type
|
|
680
|
+
type GetVideoError = GetVideoErrors[keyof GetVideoErrors];
|
|
681
|
+
type GetVideoResponses = {
|
|
453
682
|
/**
|
|
454
|
-
*
|
|
683
|
+
* Successful response
|
|
455
684
|
*/
|
|
456
685
|
200: {
|
|
457
|
-
success
|
|
458
|
-
requestId
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
|
518
|
-
requestId
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
-
*
|
|
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
|
|
570
|
-
requestId
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
|
622
|
-
requestId
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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
|
|
649
|
-
requestId
|
|
650
|
-
data
|
|
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
|
|
686
|
-
requestId
|
|
687
|
-
data
|
|
1377
|
+
success?: true;
|
|
1378
|
+
requestId?: string;
|
|
1379
|
+
data?: {
|
|
1380
|
+
logs?: Array<{
|
|
1381
|
+
id?: string;
|
|
1382
|
+
userId?: string;
|
|
1383
|
+
apiKeyId?: string | null;
|
|
1384
|
+
apiKeyName?: string | null;
|
|
1385
|
+
/**
|
|
1386
|
+
* e.g. /video
|
|
1387
|
+
*/
|
|
1388
|
+
endpoint?: string;
|
|
1389
|
+
/**
|
|
1390
|
+
* e.g. POST
|
|
1391
|
+
*/
|
|
1392
|
+
method?: string;
|
|
1393
|
+
status?: number;
|
|
1394
|
+
credits?: number;
|
|
1395
|
+
durationMs?: number | null;
|
|
1396
|
+
/**
|
|
1397
|
+
* Serialized response body.
|
|
1398
|
+
*/
|
|
1399
|
+
response?: string | null;
|
|
1400
|
+
createdAt?: string;
|
|
1401
|
+
}>;
|
|
1402
|
+
/**
|
|
1403
|
+
* Total number of matching log entries.
|
|
1404
|
+
*/
|
|
1405
|
+
total?: number;
|
|
1406
|
+
/**
|
|
1407
|
+
* Zero-based page index that was returned.
|
|
1408
|
+
*/
|
|
1409
|
+
page?: number;
|
|
1410
|
+
/**
|
|
1411
|
+
* Fixed page size (50).
|
|
1412
|
+
*/
|
|
1413
|
+
pageSize?: number;
|
|
1414
|
+
totalPages?: number;
|
|
1415
|
+
/**
|
|
1416
|
+
* Distinct endpoints seen for this account, useful for building filters.
|
|
1417
|
+
*/
|
|
1418
|
+
endpoints?: Array<string>;
|
|
1419
|
+
};
|
|
688
1420
|
};
|
|
689
1421
|
};
|
|
690
1422
|
type GetLogsResponse = GetLogsResponses[keyof GetLogsResponses];
|
|
691
|
-
type
|
|
692
|
-
|
|
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
|
-
*
|
|
1475
|
+
* Request identifier echoed in the response.
|
|
697
1476
|
*/
|
|
698
|
-
|
|
1477
|
+
id: unknown;
|
|
699
1478
|
/**
|
|
700
|
-
*
|
|
1479
|
+
* JSON-RPC method, e.g. initialize, tools/list, tools/call.
|
|
701
1480
|
*/
|
|
702
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
713
|
-
type
|
|
1508
|
+
type McpTransportPathError = McpTransportPathErrors[keyof McpTransportPathErrors];
|
|
1509
|
+
type McpTransportPathResponses = {
|
|
714
1510
|
/**
|
|
715
|
-
*
|
|
1511
|
+
* MCP response
|
|
716
1512
|
*/
|
|
717
1513
|
200: {
|
|
718
|
-
|
|
719
|
-
requestId: string;
|
|
720
|
-
data: UsageData;
|
|
1514
|
+
[key: string]: unknown;
|
|
721
1515
|
};
|
|
722
1516
|
};
|
|
723
|
-
type
|
|
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
|
|
738
|
-
type SuggestOptions = Omit<
|
|
1612
|
+
type SuggestBody = GetSuggestionsData["body"];
|
|
1613
|
+
type SuggestOptions = Omit<SuggestBody, "q">;
|
|
1614
|
+
type SuggestResponse = MeteredResponse<NonNullable<GetSuggestionsResponse["data"]>>;
|
|
739
1615
|
|
|
740
|
-
type VideoResponseFor<T> =
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
type
|
|
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<
|
|
1641
|
+
}): Promise<VideoResponseFor<VideoResponseDetails>>;
|
|
764
1642
|
video(body: GetVideoData["body"] & {
|
|
765
1643
|
type: "transcript";
|
|
766
|
-
}): Promise<VideoResponseFor<
|
|
1644
|
+
}): Promise<VideoResponseFor<VideoResponseTranscript>>;
|
|
1645
|
+
video(body: GetVideoData["body"] & {
|
|
1646
|
+
type: "comments";
|
|
1647
|
+
}): Promise<VideoResponseFor<VideoResponseComments>>;
|
|
767
1648
|
video(body: GetVideoData["body"] & {
|
|
768
|
-
type: "
|
|
769
|
-
}): Promise<VideoResponseFor<
|
|
1649
|
+
type: "replies";
|
|
1650
|
+
}): Promise<VideoResponseFor<VideoResponseReplies>>;
|
|
770
1651
|
video(body: GetVideoData["body"] & {
|
|
771
1652
|
type: "livechat";
|
|
772
|
-
}): Promise<VideoResponseFor<
|
|
1653
|
+
}): Promise<VideoResponseFor<VideoResponseLivechat>>;
|
|
773
1654
|
video(body: GetVideoData["body"]): Promise<GetVideoResponse>;
|
|
774
|
-
videoDetails(videoUrl: string): Promise<VideoResponseFor<
|
|
775
|
-
transcript(videoUrl: string): Promise<VideoResponseFor<
|
|
776
|
-
comments(videoUrl: string, options?: CommentsOptions): Promise<VideoResponseFor<
|
|
777
|
-
replies(continuationToken: string): Promise<VideoResponseFor<
|
|
778
|
-
liveChat(videoUrl: string, options?: LiveChatOptions): Promise<VideoResponseFor<
|
|
779
|
-
search(body: SearchVideosData["body"]): Promise<
|
|
780
|
-
search(query: string, options?: SearchOptions): Promise<
|
|
781
|
-
channel(body: GetChannelData["body"]): Promise<
|
|
782
|
-
channel(channelUrl: string, options?: ChannelOptions): Promise<
|
|
783
|
-
playlist(body: GetPlaylistData["body"]): Promise<
|
|
784
|
-
playlist(playlistUrl: string, options?: PlaylistOptions): Promise<
|
|
785
|
-
suggest(query: GetSuggestionsData["
|
|
786
|
-
suggest(query: string, options?: SuggestOptions): Promise<
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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
|
|
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 };
|