stophy 0.1.1
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 +100 -0
- package/dist/index.cjs +255 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +805 -0
- package/dist/index.d.ts +805 -0
- package/dist/index.js +249 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
import { Client } from '@hey-api/client-fetch';
|
|
2
|
+
|
|
3
|
+
type ErrorResponse = {
|
|
4
|
+
/**
|
|
5
|
+
* Always false for error responses.
|
|
6
|
+
*/
|
|
7
|
+
success: false;
|
|
8
|
+
/**
|
|
9
|
+
* Machine-readable error code.
|
|
10
|
+
*/
|
|
11
|
+
code?: 'UNAUTHORIZED' | 'INSUFFICIENT_CREDITS' | 'BAD_REQUEST' | 'INVALID_INPUT' | 'NOT_FOUND' | 'CONCURRENCY_LIMITED' | 'INTERNAL_ERROR';
|
|
12
|
+
/**
|
|
13
|
+
* Human-readable error message.
|
|
14
|
+
*/
|
|
15
|
+
error: string;
|
|
16
|
+
/**
|
|
17
|
+
* Optional additional context, present on validation errors.
|
|
18
|
+
*/
|
|
19
|
+
details?: unknown;
|
|
20
|
+
};
|
|
21
|
+
type Thumbnail = {
|
|
22
|
+
url: string;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
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;
|
|
34
|
+
};
|
|
35
|
+
type TranscriptSegment = {
|
|
36
|
+
start: number;
|
|
37
|
+
duration: number;
|
|
38
|
+
text: string;
|
|
39
|
+
};
|
|
40
|
+
type TranscriptResult = {
|
|
41
|
+
language: TranscriptLanguage;
|
|
42
|
+
segments: Array<TranscriptSegment>;
|
|
43
|
+
text: string;
|
|
44
|
+
empty?: EmptyState;
|
|
45
|
+
};
|
|
46
|
+
type VideoDetails = {
|
|
47
|
+
id: string;
|
|
48
|
+
type?: 'video';
|
|
49
|
+
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;
|
|
64
|
+
thumbnails: Array<Thumbnail>;
|
|
65
|
+
};
|
|
66
|
+
type RelatedVideo = {
|
|
67
|
+
id: string;
|
|
68
|
+
type?: 'video';
|
|
69
|
+
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;
|
|
79
|
+
thumbnails: Array<Thumbnail>;
|
|
80
|
+
};
|
|
81
|
+
type VideoDetailsData = {
|
|
82
|
+
video: VideoDetails;
|
|
83
|
+
related: Array<RelatedVideo>;
|
|
84
|
+
};
|
|
85
|
+
type Comment = {
|
|
86
|
+
id: string | null;
|
|
87
|
+
text: string | null;
|
|
88
|
+
author: string | null;
|
|
89
|
+
authorId: string | null;
|
|
90
|
+
authorThumbnail?: string | null;
|
|
91
|
+
hasChannelOwnerReplied: boolean;
|
|
92
|
+
isChannelOwner: boolean;
|
|
93
|
+
isHearted: boolean;
|
|
94
|
+
isPinned: boolean;
|
|
95
|
+
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 = {
|
|
105
|
+
items: Array<Comment>;
|
|
106
|
+
continuationToken: string | null;
|
|
107
|
+
empty?: EmptyState;
|
|
108
|
+
};
|
|
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;
|
|
120
|
+
};
|
|
121
|
+
type LiveChatData = {
|
|
122
|
+
status: string;
|
|
123
|
+
isLive: boolean;
|
|
124
|
+
concurrentViewers?: number | null;
|
|
125
|
+
pollIntervalMs?: number | null;
|
|
126
|
+
messages: Array<LiveChatMessage>;
|
|
127
|
+
continuationToken: string | null;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Shape depends on the request `type`: details, transcript, comments/replies, or livechat.
|
|
131
|
+
*/
|
|
132
|
+
type VideoData = VideoDetailsData | TranscriptResult | CommentsData | LiveChatData;
|
|
133
|
+
type SearchVideo = {
|
|
134
|
+
type: 'video';
|
|
135
|
+
id: string;
|
|
136
|
+
videoUrl: string;
|
|
137
|
+
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;
|
|
151
|
+
thumbnails: Array<Thumbnail>;
|
|
152
|
+
};
|
|
153
|
+
type SearchShort = {
|
|
154
|
+
type: 'short';
|
|
155
|
+
id: string;
|
|
156
|
+
shortUrl: string;
|
|
157
|
+
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;
|
|
168
|
+
thumbnails: Array<Thumbnail>;
|
|
169
|
+
};
|
|
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>;
|
|
180
|
+
};
|
|
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>;
|
|
192
|
+
};
|
|
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;
|
|
207
|
+
};
|
|
208
|
+
type ChannelLink = {
|
|
209
|
+
title: string;
|
|
210
|
+
url: string;
|
|
211
|
+
};
|
|
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;
|
|
230
|
+
};
|
|
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>;
|
|
247
|
+
};
|
|
248
|
+
type ChannelData = {
|
|
249
|
+
channel: ChannelProfile | null;
|
|
250
|
+
tab?: string | null;
|
|
251
|
+
items?: Array<ContentItem>;
|
|
252
|
+
continuationToken?: string | null;
|
|
253
|
+
empty?: EmptyState;
|
|
254
|
+
};
|
|
255
|
+
type PlaylistMeta = {
|
|
256
|
+
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;
|
|
264
|
+
thumbnails: Array<Thumbnail>;
|
|
265
|
+
};
|
|
266
|
+
type PlaylistItem = {
|
|
267
|
+
id: string;
|
|
268
|
+
type?: 'video';
|
|
269
|
+
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;
|
|
284
|
+
thumbnails: Array<Thumbnail>;
|
|
285
|
+
};
|
|
286
|
+
type PlaylistData = {
|
|
287
|
+
playlist: PlaylistMeta | null;
|
|
288
|
+
items: Array<PlaylistItem>;
|
|
289
|
+
continuationToken: string | null;
|
|
290
|
+
empty?: EmptyState;
|
|
291
|
+
};
|
|
292
|
+
type SuggestData = {
|
|
293
|
+
q: string;
|
|
294
|
+
hl: string;
|
|
295
|
+
gl: string;
|
|
296
|
+
suggestions: Array<string>;
|
|
297
|
+
};
|
|
298
|
+
type CreditsData = {
|
|
299
|
+
credits: number;
|
|
300
|
+
};
|
|
301
|
+
type LogEntry = {
|
|
302
|
+
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>;
|
|
329
|
+
};
|
|
330
|
+
type GetVideoData = {
|
|
331
|
+
body: {
|
|
332
|
+
/**
|
|
333
|
+
* The type of data to retrieve.
|
|
334
|
+
*/
|
|
335
|
+
type: 'details' | 'transcript' | 'comments' | 'replies' | 'livechat';
|
|
336
|
+
/**
|
|
337
|
+
* Full YouTube video URL. Not required when type is replies.
|
|
338
|
+
*/
|
|
339
|
+
videoUrl: string;
|
|
340
|
+
/**
|
|
341
|
+
* Comment sort order. Only applies when type is comments.
|
|
342
|
+
*/
|
|
343
|
+
sortBy?: 'latest' | 'top';
|
|
344
|
+
/**
|
|
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.
|
|
346
|
+
*/
|
|
347
|
+
chatType?: 'top' | 'live';
|
|
348
|
+
/**
|
|
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.
|
|
350
|
+
*/
|
|
351
|
+
continuationToken?: string;
|
|
352
|
+
};
|
|
353
|
+
path?: never;
|
|
354
|
+
query?: never;
|
|
355
|
+
url: '/v1/video';
|
|
356
|
+
};
|
|
357
|
+
type GetVideoErrors = {
|
|
358
|
+
/**
|
|
359
|
+
* Validation error
|
|
360
|
+
*/
|
|
361
|
+
400: ErrorResponse;
|
|
362
|
+
/**
|
|
363
|
+
* Invalid or missing API key
|
|
364
|
+
*/
|
|
365
|
+
401: ErrorResponse;
|
|
366
|
+
/**
|
|
367
|
+
* Insufficient credits
|
|
368
|
+
*/
|
|
369
|
+
402: ErrorResponse;
|
|
370
|
+
/**
|
|
371
|
+
* Rate limited
|
|
372
|
+
*/
|
|
373
|
+
429: ErrorResponse;
|
|
374
|
+
/**
|
|
375
|
+
* Internal error
|
|
376
|
+
*/
|
|
377
|
+
500: ErrorResponse;
|
|
378
|
+
};
|
|
379
|
+
type GetVideoError = GetVideoErrors[keyof GetVideoErrors];
|
|
380
|
+
type GetVideoResponses = {
|
|
381
|
+
/**
|
|
382
|
+
* Successful response
|
|
383
|
+
*/
|
|
384
|
+
200: {
|
|
385
|
+
success: true;
|
|
386
|
+
requestId: string;
|
|
387
|
+
data: VideoData;
|
|
388
|
+
cacheState: 'hit' | 'miss';
|
|
389
|
+
creditsUsed: number;
|
|
390
|
+
creditsRemaining: number;
|
|
391
|
+
};
|
|
392
|
+
};
|
|
393
|
+
type GetVideoResponse = GetVideoResponses[keyof GetVideoResponses];
|
|
394
|
+
type SearchVideosData = {
|
|
395
|
+
body: {
|
|
396
|
+
/**
|
|
397
|
+
* Search query.
|
|
398
|
+
*/
|
|
399
|
+
q: string;
|
|
400
|
+
/**
|
|
401
|
+
* Filter by content type.
|
|
402
|
+
*/
|
|
403
|
+
type?: 'video' | 'short' | 'channel' | 'playlist' | 'movie';
|
|
404
|
+
/**
|
|
405
|
+
* Sort order. Defaults to relevance.
|
|
406
|
+
*/
|
|
407
|
+
sortBy?: 'relevance' | 'popularity' | 'date' | 'rating';
|
|
408
|
+
/**
|
|
409
|
+
* Filter by upload date.
|
|
410
|
+
*/
|
|
411
|
+
uploadDate?: 'today' | 'week' | 'month' | 'year';
|
|
412
|
+
/**
|
|
413
|
+
* Duration filter. Not applicable when type is short.
|
|
414
|
+
*/
|
|
415
|
+
duration?: 'short' | 'medium' | 'long';
|
|
416
|
+
/**
|
|
417
|
+
* Filter by video features.
|
|
418
|
+
*/
|
|
419
|
+
features?: Array<'live' | '4k' | 'hd' | 'subtitles' | 'creativeCommons' | '360' | 'vr180' | '3d' | 'hdr' | 'location' | 'purchased'>;
|
|
420
|
+
/**
|
|
421
|
+
* Token from a previous response to fetch the next page.
|
|
422
|
+
*/
|
|
423
|
+
continuationToken?: string;
|
|
424
|
+
};
|
|
425
|
+
path?: never;
|
|
426
|
+
query?: never;
|
|
427
|
+
url: '/v1/search';
|
|
428
|
+
};
|
|
429
|
+
type SearchVideosErrors = {
|
|
430
|
+
/**
|
|
431
|
+
* Validation error
|
|
432
|
+
*/
|
|
433
|
+
400: ErrorResponse;
|
|
434
|
+
/**
|
|
435
|
+
* Unauthorized
|
|
436
|
+
*/
|
|
437
|
+
401: ErrorResponse;
|
|
438
|
+
/**
|
|
439
|
+
* Insufficient credits
|
|
440
|
+
*/
|
|
441
|
+
402: ErrorResponse;
|
|
442
|
+
/**
|
|
443
|
+
* Rate limited
|
|
444
|
+
*/
|
|
445
|
+
429: ErrorResponse;
|
|
446
|
+
/**
|
|
447
|
+
* Internal error
|
|
448
|
+
*/
|
|
449
|
+
500: ErrorResponse;
|
|
450
|
+
};
|
|
451
|
+
type SearchVideosError = SearchVideosErrors[keyof SearchVideosErrors];
|
|
452
|
+
type SearchVideosResponses = {
|
|
453
|
+
/**
|
|
454
|
+
* Search results
|
|
455
|
+
*/
|
|
456
|
+
200: {
|
|
457
|
+
success: true;
|
|
458
|
+
requestId: string;
|
|
459
|
+
data: SearchData;
|
|
460
|
+
cacheState: 'hit' | 'miss';
|
|
461
|
+
creditsUsed: number;
|
|
462
|
+
creditsRemaining: number;
|
|
463
|
+
};
|
|
464
|
+
};
|
|
465
|
+
type SearchVideosResponse = SearchVideosResponses[keyof SearchVideosResponses];
|
|
466
|
+
type GetChannelData = {
|
|
467
|
+
body: {
|
|
468
|
+
/**
|
|
469
|
+
* Full YouTube channel URL, e.g. https://www.youtube.com/@mkbhd.
|
|
470
|
+
*/
|
|
471
|
+
channelUrl: string;
|
|
472
|
+
/**
|
|
473
|
+
* Content tab to fetch. Defaults to video.
|
|
474
|
+
*/
|
|
475
|
+
tab?: 'video' | 'short' | 'playlist' | 'about';
|
|
476
|
+
/**
|
|
477
|
+
* Token from a previous response to fetch the next page.
|
|
478
|
+
*/
|
|
479
|
+
continuationToken?: string;
|
|
480
|
+
/**
|
|
481
|
+
* Sort order for the selected tab.
|
|
482
|
+
*/
|
|
483
|
+
sortBy?: 'latest' | 'popular' | 'oldest';
|
|
484
|
+
};
|
|
485
|
+
path?: never;
|
|
486
|
+
query?: never;
|
|
487
|
+
url: '/v1/channel';
|
|
488
|
+
};
|
|
489
|
+
type GetChannelErrors = {
|
|
490
|
+
/**
|
|
491
|
+
* Validation error
|
|
492
|
+
*/
|
|
493
|
+
400: ErrorResponse;
|
|
494
|
+
/**
|
|
495
|
+
* Unauthorized
|
|
496
|
+
*/
|
|
497
|
+
401: ErrorResponse;
|
|
498
|
+
/**
|
|
499
|
+
* Insufficient credits
|
|
500
|
+
*/
|
|
501
|
+
402: ErrorResponse;
|
|
502
|
+
/**
|
|
503
|
+
* Rate limited
|
|
504
|
+
*/
|
|
505
|
+
429: ErrorResponse;
|
|
506
|
+
/**
|
|
507
|
+
* Internal error
|
|
508
|
+
*/
|
|
509
|
+
500: ErrorResponse;
|
|
510
|
+
};
|
|
511
|
+
type GetChannelError = GetChannelErrors[keyof GetChannelErrors];
|
|
512
|
+
type GetChannelResponses = {
|
|
513
|
+
/**
|
|
514
|
+
* Channel data
|
|
515
|
+
*/
|
|
516
|
+
200: {
|
|
517
|
+
success: true;
|
|
518
|
+
requestId: string;
|
|
519
|
+
data: ChannelData;
|
|
520
|
+
cacheState: 'hit' | 'miss';
|
|
521
|
+
creditsUsed: number;
|
|
522
|
+
creditsRemaining: number;
|
|
523
|
+
};
|
|
524
|
+
};
|
|
525
|
+
type GetChannelResponse = GetChannelResponses[keyof GetChannelResponses];
|
|
526
|
+
type GetPlaylistData = {
|
|
527
|
+
body: {
|
|
528
|
+
/**
|
|
529
|
+
* Full YouTube playlist URL.
|
|
530
|
+
*/
|
|
531
|
+
playlistUrl: string;
|
|
532
|
+
/**
|
|
533
|
+
* Token from a previous response to fetch the next page.
|
|
534
|
+
*/
|
|
535
|
+
continuationToken?: string;
|
|
536
|
+
};
|
|
537
|
+
path?: never;
|
|
538
|
+
query?: never;
|
|
539
|
+
url: '/v1/playlist';
|
|
540
|
+
};
|
|
541
|
+
type GetPlaylistErrors = {
|
|
542
|
+
/**
|
|
543
|
+
* Validation error
|
|
544
|
+
*/
|
|
545
|
+
400: ErrorResponse;
|
|
546
|
+
/**
|
|
547
|
+
* Unauthorized
|
|
548
|
+
*/
|
|
549
|
+
401: ErrorResponse;
|
|
550
|
+
/**
|
|
551
|
+
* Insufficient credits
|
|
552
|
+
*/
|
|
553
|
+
402: ErrorResponse;
|
|
554
|
+
/**
|
|
555
|
+
* Rate limited
|
|
556
|
+
*/
|
|
557
|
+
429: ErrorResponse;
|
|
558
|
+
/**
|
|
559
|
+
* Internal error
|
|
560
|
+
*/
|
|
561
|
+
500: ErrorResponse;
|
|
562
|
+
};
|
|
563
|
+
type GetPlaylistError = GetPlaylistErrors[keyof GetPlaylistErrors];
|
|
564
|
+
type GetPlaylistResponses = {
|
|
565
|
+
/**
|
|
566
|
+
* Playlist items
|
|
567
|
+
*/
|
|
568
|
+
200: {
|
|
569
|
+
success: true;
|
|
570
|
+
requestId: string;
|
|
571
|
+
data: PlaylistData;
|
|
572
|
+
cacheState: 'hit' | 'miss';
|
|
573
|
+
creditsUsed: number;
|
|
574
|
+
creditsRemaining: number;
|
|
575
|
+
};
|
|
576
|
+
};
|
|
577
|
+
type GetPlaylistResponse = GetPlaylistResponses[keyof GetPlaylistResponses];
|
|
578
|
+
type GetSuggestionsData = {
|
|
579
|
+
body?: never;
|
|
580
|
+
path?: never;
|
|
581
|
+
query: {
|
|
582
|
+
/**
|
|
583
|
+
* Search query.
|
|
584
|
+
*/
|
|
585
|
+
q: string;
|
|
586
|
+
/**
|
|
587
|
+
* Language code, e.g. en, fr, de. Defaults to en.
|
|
588
|
+
*/
|
|
589
|
+
hl?: string;
|
|
590
|
+
/**
|
|
591
|
+
* Country code, e.g. US, GB, DE. Defaults to US.
|
|
592
|
+
*/
|
|
593
|
+
gl?: string;
|
|
594
|
+
};
|
|
595
|
+
url: '/v1/suggest';
|
|
596
|
+
};
|
|
597
|
+
type GetSuggestionsErrors = {
|
|
598
|
+
/**
|
|
599
|
+
* Validation error
|
|
600
|
+
*/
|
|
601
|
+
400: ErrorResponse;
|
|
602
|
+
/**
|
|
603
|
+
* Unauthorized
|
|
604
|
+
*/
|
|
605
|
+
401: ErrorResponse;
|
|
606
|
+
/**
|
|
607
|
+
* Rate limited
|
|
608
|
+
*/
|
|
609
|
+
429: ErrorResponse;
|
|
610
|
+
/**
|
|
611
|
+
* Internal error
|
|
612
|
+
*/
|
|
613
|
+
500: ErrorResponse;
|
|
614
|
+
};
|
|
615
|
+
type GetSuggestionsError = GetSuggestionsErrors[keyof GetSuggestionsErrors];
|
|
616
|
+
type GetSuggestionsResponses = {
|
|
617
|
+
/**
|
|
618
|
+
* Autocomplete suggestions
|
|
619
|
+
*/
|
|
620
|
+
200: {
|
|
621
|
+
success: true;
|
|
622
|
+
requestId: string;
|
|
623
|
+
data: SuggestData;
|
|
624
|
+
cacheState: 'hit' | 'miss';
|
|
625
|
+
creditsUsed: number;
|
|
626
|
+
creditsRemaining: number;
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
type GetSuggestionsResponse = GetSuggestionsResponses[keyof GetSuggestionsResponses];
|
|
630
|
+
type GetCreditsData = {
|
|
631
|
+
body?: never;
|
|
632
|
+
path?: never;
|
|
633
|
+
query?: never;
|
|
634
|
+
url: '/v1/credits';
|
|
635
|
+
};
|
|
636
|
+
type GetCreditsErrors = {
|
|
637
|
+
/**
|
|
638
|
+
* Unauthorized
|
|
639
|
+
*/
|
|
640
|
+
401: ErrorResponse;
|
|
641
|
+
};
|
|
642
|
+
type GetCreditsError = GetCreditsErrors[keyof GetCreditsErrors];
|
|
643
|
+
type GetCreditsResponses = {
|
|
644
|
+
/**
|
|
645
|
+
* Credit balance
|
|
646
|
+
*/
|
|
647
|
+
200: {
|
|
648
|
+
success: true;
|
|
649
|
+
requestId: string;
|
|
650
|
+
data: CreditsData;
|
|
651
|
+
};
|
|
652
|
+
};
|
|
653
|
+
type GetCreditsResponse = GetCreditsResponses[keyof GetCreditsResponses];
|
|
654
|
+
type GetLogsData = {
|
|
655
|
+
body?: never;
|
|
656
|
+
path?: never;
|
|
657
|
+
query?: {
|
|
658
|
+
/**
|
|
659
|
+
* Time window: 'today', the last 7 days, or the last 30 days.
|
|
660
|
+
*/
|
|
661
|
+
days?: 'today' | '7' | '30';
|
|
662
|
+
/**
|
|
663
|
+
* Filter logs to a single endpoint, e.g. /video.
|
|
664
|
+
*/
|
|
665
|
+
endpoint?: string;
|
|
666
|
+
/**
|
|
667
|
+
* Zero-based page index. Page size is fixed at 50 entries.
|
|
668
|
+
*/
|
|
669
|
+
page?: number;
|
|
670
|
+
};
|
|
671
|
+
url: '/v1/logs';
|
|
672
|
+
};
|
|
673
|
+
type GetLogsErrors = {
|
|
674
|
+
/**
|
|
675
|
+
* Unauthorized
|
|
676
|
+
*/
|
|
677
|
+
401: ErrorResponse;
|
|
678
|
+
};
|
|
679
|
+
type GetLogsError = GetLogsErrors[keyof GetLogsErrors];
|
|
680
|
+
type GetLogsResponses = {
|
|
681
|
+
/**
|
|
682
|
+
* Request logs
|
|
683
|
+
*/
|
|
684
|
+
200: {
|
|
685
|
+
success: true;
|
|
686
|
+
requestId: string;
|
|
687
|
+
data: LogsData;
|
|
688
|
+
};
|
|
689
|
+
};
|
|
690
|
+
type GetLogsResponse = GetLogsResponses[keyof GetLogsResponses];
|
|
691
|
+
type GetUsageData = {
|
|
692
|
+
body?: never;
|
|
693
|
+
path?: never;
|
|
694
|
+
query?: {
|
|
695
|
+
/**
|
|
696
|
+
* Time window: 'today', the last 7 days, or the last 30 days.
|
|
697
|
+
*/
|
|
698
|
+
days?: 'today' | '7' | '30';
|
|
699
|
+
/**
|
|
700
|
+
* Timezone offset in minutes used to bucket activity into days. Defaults to UTC.
|
|
701
|
+
*/
|
|
702
|
+
tz?: string;
|
|
703
|
+
};
|
|
704
|
+
url: '/v1/usage';
|
|
705
|
+
};
|
|
706
|
+
type GetUsageErrors = {
|
|
707
|
+
/**
|
|
708
|
+
* Unauthorized
|
|
709
|
+
*/
|
|
710
|
+
401: ErrorResponse;
|
|
711
|
+
};
|
|
712
|
+
type GetUsageError = GetUsageErrors[keyof GetUsageErrors];
|
|
713
|
+
type GetUsageResponses = {
|
|
714
|
+
/**
|
|
715
|
+
* Daily usage
|
|
716
|
+
*/
|
|
717
|
+
200: {
|
|
718
|
+
success: true;
|
|
719
|
+
requestId: string;
|
|
720
|
+
data: UsageData;
|
|
721
|
+
};
|
|
722
|
+
};
|
|
723
|
+
type GetUsageResponse = GetUsageResponses[keyof GetUsageResponses];
|
|
724
|
+
type ClientOptions = {
|
|
725
|
+
baseUrl: 'https://api.stophy.dev' | (string & {});
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
/** A video response with `data` narrowed to the shape for a given request `type`. */
|
|
729
|
+
type VideoResponseFor<D> = Omit<GetVideoResponse, "data"> & {
|
|
730
|
+
data: D;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
interface StophyOptions {
|
|
734
|
+
/** API key from your dashboard. Sent as `Authorization: Bearer <key>`. */
|
|
735
|
+
apiKey: string;
|
|
736
|
+
/** Defaults to `https://api.stophy.dev`. */
|
|
737
|
+
baseUrl?: string;
|
|
738
|
+
/** Bring your own `fetch` (handy for tests or non-global runtimes). */
|
|
739
|
+
fetch?: typeof globalThis.fetch;
|
|
740
|
+
/** Sent with every request. */
|
|
741
|
+
headers?: Record<string, string>;
|
|
742
|
+
/**
|
|
743
|
+
* Retry attempts for transient failures (network errors and
|
|
744
|
+
* 429/500/502/503/504). Set to `0` to disable. Defaults to `2`.
|
|
745
|
+
*/
|
|
746
|
+
maxRetries?: number;
|
|
747
|
+
/** Base delay for backoff, in ms. Defaults to `500`. */
|
|
748
|
+
retryInitialDelayMs?: number;
|
|
749
|
+
}
|
|
750
|
+
/** Thrown when the API responds with a non-2xx status. */
|
|
751
|
+
declare class StophyError extends Error {
|
|
752
|
+
readonly code?: ErrorResponse["code"];
|
|
753
|
+
readonly status: number;
|
|
754
|
+
readonly requestId?: string;
|
|
755
|
+
readonly details?: unknown;
|
|
756
|
+
constructor(message: string, opts: {
|
|
757
|
+
status: number;
|
|
758
|
+
code?: ErrorResponse["code"];
|
|
759
|
+
requestId?: string;
|
|
760
|
+
details?: unknown;
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Stophy API client — YouTube context API for AI agents.
|
|
765
|
+
*
|
|
766
|
+
* ```ts
|
|
767
|
+
* const stophy = new Stophy({ apiKey: process.env.STOPHY_API_KEY! });
|
|
768
|
+
* const { data } = await stophy.video({ type: "transcript", videoUrl });
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
771
|
+
declare class Stophy {
|
|
772
|
+
/** The underlying fetch client, if you need lower-level access. */
|
|
773
|
+
readonly client: Client;
|
|
774
|
+
constructor(options: StophyOptions);
|
|
775
|
+
/** Video details, transcript, comments, replies, or live chat — pick with `type`. */
|
|
776
|
+
video(body: GetVideoData["body"] & {
|
|
777
|
+
type: "details";
|
|
778
|
+
}): Promise<VideoResponseFor<VideoDetailsData>>;
|
|
779
|
+
video(body: GetVideoData["body"] & {
|
|
780
|
+
type: "transcript";
|
|
781
|
+
}): Promise<VideoResponseFor<TranscriptResult>>;
|
|
782
|
+
video(body: GetVideoData["body"] & {
|
|
783
|
+
type: "comments" | "replies";
|
|
784
|
+
}): Promise<VideoResponseFor<CommentsData>>;
|
|
785
|
+
video(body: GetVideoData["body"] & {
|
|
786
|
+
type: "livechat";
|
|
787
|
+
}): Promise<VideoResponseFor<LiveChatData>>;
|
|
788
|
+
video(body: GetVideoData["body"]): Promise<GetVideoResponse>;
|
|
789
|
+
/** Search YouTube, optionally filtered by type, sort, date, duration, and features. */
|
|
790
|
+
search(body: SearchVideosData["body"]): Promise<SearchVideosResponse>;
|
|
791
|
+
/** Channel metadata and content. Switch sections with `tab`. */
|
|
792
|
+
channel(body: GetChannelData["body"]): Promise<GetChannelResponse>;
|
|
793
|
+
/** Playlist items. Page through long playlists with `continuationToken`. */
|
|
794
|
+
playlist(body: GetPlaylistData["body"]): Promise<GetPlaylistResponse>;
|
|
795
|
+
/** Search autocomplete suggestions. */
|
|
796
|
+
suggest(query: GetSuggestionsData["query"]): Promise<GetSuggestionsResponse>;
|
|
797
|
+
/** Your current credit balance. */
|
|
798
|
+
credits(): Promise<GetCreditsResponse>;
|
|
799
|
+
/** Recent API request logs. */
|
|
800
|
+
logs(query?: GetLogsData["query"]): Promise<GetLogsResponse>;
|
|
801
|
+
/** Daily credit and request counts. */
|
|
802
|
+
usage(query?: GetUsageData["query"]): Promise<GetUsageResponse>;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
export { type ChannelData, type ChannelLink, type ChannelProfile, type ClientOptions, type Comment, type CommentsData, 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 LogEntry, type LogsData, type PlaylistData, type PlaylistItem, type PlaylistMeta, type RelatedVideo, type SearchChannel, type SearchData, type SearchItem, type SearchPlaylist, type SearchShort, type SearchVideo, type SearchVideosData, type SearchVideosError, type SearchVideosErrors, type SearchVideosResponse, type SearchVideosResponses, Stophy, StophyError, type StophyOptions, type SuggestData, type Thumbnail, type TranscriptLanguage, type TranscriptResult, type TranscriptSegment, type UsageData, type UsageItem, type VideoData, type VideoDetails, type VideoDetailsData, Stophy as default };
|