extract-youtube 1.0.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/src/proxies.ts ADDED
@@ -0,0 +1,222 @@
1
+ /**
2
+ * @fileoverview Proxy configuration classes for the YouTube Transcript API
3
+ */
4
+
5
+ import { RequestsProxyConfigDict } from './types';
6
+
7
+ /**
8
+ * Exception for invalid proxy configurations
9
+ */
10
+ export class InvalidProxyConfig extends Error {
11
+ constructor(message: string) {
12
+ super(message);
13
+ this.name = 'InvalidProxyConfig';
14
+ Object.setPrototypeOf(this, InvalidProxyConfig.prototype);
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Base class for all proxy configurations.
20
+ * Any proxy config can be used as long as it can be converted to a RequestsProxyConfigDict.
21
+ */
22
+ export abstract class ProxyConfig {
23
+ /**
24
+ * Converts this proxy config to a dictionary that can be used by HTTP clients.
25
+ * @returns {RequestsProxyConfigDict} The proxy configuration dictionary
26
+ */
27
+ abstract toRequestsDict(): RequestsProxyConfigDict;
28
+
29
+ /**
30
+ * If you are using rotating proxies, it can be useful to prevent the HTTP
31
+ * client from keeping TCP connections alive, as your IP won't be rotated on
32
+ * every request if your connection stays open.
33
+ * @returns {boolean} Whether to prevent keeping connections alive
34
+ */
35
+ get preventKeepingConnectionsAlive(): boolean {
36
+ return false;
37
+ }
38
+
39
+ /**
40
+ * Defines how many times we should retry if a request is blocked. When using
41
+ * rotating residential proxies with a large IP pool it can make sense to retry a
42
+ * couple of times when a blocked IP is encountered, since a retry will trigger
43
+ * an IP rotation and the next IP might not be blocked.
44
+ * @returns {number} Number of retries when blocked
45
+ */
46
+ get retriesWhenBlocked(): number {
47
+ return 0;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Generic proxy configuration that can be used to set up any HTTP/HTTPS/SOCKS proxy.
53
+ *
54
+ * If only an HTTP or an HTTPS proxy is provided, it will be used for both types of
55
+ * connections. However, you will have to provide at least one of the two.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const proxyConfig = new GenericProxyConfig({
60
+ * httpUrl: 'http://user:pass@proxy.example.com:8080',
61
+ * httpsUrl: 'https://user:pass@proxy.example.com:8080'
62
+ * });
63
+ * ```
64
+ */
65
+ export class GenericProxyConfig extends ProxyConfig {
66
+ protected _httpUrl: string | null;
67
+ protected _httpsUrl: string | null;
68
+
69
+ /**
70
+ * Creates a generic proxy configuration.
71
+ * If only an HTTP or an HTTPS proxy is provided, it will be used for both types of
72
+ * connections. However, you will have to provide at least one of the two.
73
+ *
74
+ * @param {Object} options - Proxy configuration options
75
+ * @param {string} [options.httpUrl] - The proxy URL used for HTTP requests. Defaults to httpsUrl if not provided.
76
+ * @param {string} [options.httpsUrl] - The proxy URL used for HTTPS requests. Defaults to httpUrl if not provided.
77
+ * @throws {InvalidProxyConfig} If neither httpUrl nor httpsUrl is provided
78
+ */
79
+ constructor(options: { httpUrl?: string; httpsUrl?: string }) {
80
+ super();
81
+ const { httpUrl, httpsUrl } = options;
82
+
83
+ if (!httpUrl && !httpsUrl) {
84
+ throw new InvalidProxyConfig(
85
+ 'GenericProxyConfig requires you to define at least one of the two: http or https'
86
+ );
87
+ }
88
+
89
+ this._httpUrl = httpUrl || null;
90
+ this._httpsUrl = httpsUrl || null;
91
+ }
92
+
93
+ get httpUrl(): string | null {
94
+ return this._httpUrl;
95
+ }
96
+
97
+ get httpsUrl(): string | null {
98
+ return this._httpsUrl;
99
+ }
100
+
101
+ toRequestsDict(): RequestsProxyConfigDict {
102
+ return {
103
+ http: this.httpUrl || this.httpsUrl!,
104
+ https: this.httpsUrl || this.httpUrl!
105
+ };
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Webshare proxy configuration for rotating residential proxies.
111
+ *
112
+ * Webshare is a provider offering rotating residential proxies, which is the
113
+ * most reliable way to work around being blocked by YouTube.
114
+ *
115
+ * If you don't have a Webshare account yet, you will have to create one
116
+ * at https://www.webshare.io/?referral_code=w0xno53eb50g and purchase a "Residential"
117
+ * proxy package that suits your workload (make sure NOT to purchase "Proxy Server"
118
+ * or "Static Residential"!).
119
+ *
120
+ * Once you have created an account you only need the "Proxy Username" and
121
+ * "Proxy Password" that you can find in your Webshare settings to set up this config.
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * const proxyConfig = new WebshareProxyConfig({
126
+ * proxyUsername: 'your-username',
127
+ * proxyPassword: 'your-password',
128
+ * filterIpLocations: ['us', 'de']
129
+ * });
130
+ * ```
131
+ */
132
+ export class WebshareProxyConfig extends GenericProxyConfig {
133
+ public static readonly DEFAULT_DOMAIN_NAME = 'p.webshare.io';
134
+ public static readonly DEFAULT_PORT = 80;
135
+
136
+ public readonly proxyUsername: string;
137
+ public readonly proxyPassword: string;
138
+ public readonly domainName: string;
139
+ public readonly proxyPort: number;
140
+ private readonly filterIpLocations: string[];
141
+ private readonly _retriesWhenBlocked: number;
142
+
143
+ /**
144
+ * Creates a Webshare proxy configuration.
145
+ *
146
+ * Once you have created a Webshare account and purchased a "Residential" package
147
+ * (make sure NOT to purchase "Proxy Server" or "Static Residential"!), this config
148
+ * class allows you to easily use it by defaulting to the most reliable proxy settings
149
+ * (rotating residential proxies).
150
+ *
151
+ * @param {Object} options - Webshare configuration options
152
+ * @param {string} options.proxyUsername - "Proxy Username" found at https://dashboard.webshare.io/proxy/settings
153
+ * @param {string} options.proxyPassword - "Proxy Password" found at https://dashboard.webshare.io/proxy/settings
154
+ * @param {string[]} [options.filterIpLocations] - If you want to limit the pool of IPs to specific countries,
155
+ * provide a list of location codes (e.g., ['us', 'de']). This can reduce latency and work around location-based restrictions.
156
+ * @param {number} [options.retriesWhenBlocked=10] - How many times to retry if a request is blocked
157
+ * @param {string} [options.domainName] - Custom domain name (defaults to p.webshare.io)
158
+ * @param {number} [options.proxyPort] - Custom proxy port (defaults to 80)
159
+ */
160
+ constructor(options: {
161
+ proxyUsername: string;
162
+ proxyPassword: string;
163
+ filterIpLocations?: string[];
164
+ retriesWhenBlocked?: number;
165
+ domainName?: string;
166
+ proxyPort?: number;
167
+ }) {
168
+ super({ httpUrl: 'placeholder' });
169
+
170
+ this.proxyUsername = options.proxyUsername;
171
+ this.proxyPassword = options.proxyPassword;
172
+ this.domainName = options.domainName || WebshareProxyConfig.DEFAULT_DOMAIN_NAME;
173
+ this.proxyPort = options.proxyPort || WebshareProxyConfig.DEFAULT_PORT;
174
+ this.filterIpLocations = options.filterIpLocations || [];
175
+ this._retriesWhenBlocked = options.retriesWhenBlocked ?? 10;
176
+ }
177
+
178
+ /**
179
+ * Gets the full proxy URL with location filtering and rotation settings.
180
+ * @returns {string} The complete proxy URL
181
+ */
182
+ get url(): string {
183
+ const locationCodes = this.filterIpLocations
184
+ .map(code => `-${code.toUpperCase()}`)
185
+ .join('');
186
+
187
+ let username = this.proxyUsername;
188
+ const suffix = '-rotate';
189
+
190
+ if (username.endsWith(suffix)) {
191
+ username = username.slice(0, -suffix.length);
192
+ }
193
+
194
+ return (
195
+ `http://${username}${locationCodes}${suffix}:${this.proxyPassword}` +
196
+ `@${this.domainName}:${this.proxyPort}/`
197
+ );
198
+ }
199
+
200
+ get httpUrl(): string {
201
+ return this.url;
202
+ }
203
+
204
+ get httpsUrl(): string {
205
+ return this.url;
206
+ }
207
+
208
+ toRequestsDict(): RequestsProxyConfigDict {
209
+ return {
210
+ http: this.url,
211
+ https: this.url
212
+ };
213
+ }
214
+
215
+ get preventKeepingConnectionsAlive(): boolean {
216
+ return true;
217
+ }
218
+
219
+ get retriesWhenBlocked(): number {
220
+ return this._retriesWhenBlocked;
221
+ }
222
+ }
package/src/types.ts ADDED
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @fileoverview Type definitions for the YouTube Transcript API
3
+ */
4
+
5
+ import { Response, RequestInit } from 'node-fetch';
6
+
7
+ /**
8
+ * Represents a single snippet/cue of a transcript
9
+ */
10
+ export interface FetchedTranscriptSnippet {
11
+ /** The text content of this transcript snippet */
12
+ text: string;
13
+ /** The timestamp at which this transcript snippet appears on screen in seconds */
14
+ start: number;
15
+ /**
16
+ * The duration of how long the snippet stays on screen in seconds.
17
+ * Note: This is not the duration of the transcribed speech, but how long
18
+ * the snippet stays on screen. Therefore, there can be overlaps between snippets!
19
+ */
20
+ duration: number;
21
+ }
22
+
23
+ /**
24
+ * Translation language information
25
+ */
26
+ export interface TranslationLanguage {
27
+ /** The name of the language */
28
+ language: string;
29
+ /** The language code (e.g., 'en', 'de', 'fr') */
30
+ language_code: string;
31
+ }
32
+
33
+ /**
34
+ * Playability status enum values
35
+ */
36
+ export enum PlayabilityStatus {
37
+ OK = 'OK',
38
+ ERROR = 'ERROR',
39
+ LOGIN_REQUIRED = 'LOGIN_REQUIRED'
40
+ }
41
+
42
+ /**
43
+ * Playability failed reason enum values
44
+ */
45
+ export enum PlayabilityFailedReason {
46
+ BOT_DETECTED = "Sign in to confirm you're not a bot",
47
+ AGE_RESTRICTED = 'This video may be inappropriate for some users.',
48
+ VIDEO_UNAVAILABLE = 'This video is unavailable'
49
+ }
50
+
51
+ /**
52
+ * Proxy configuration dictionary for HTTP clients
53
+ */
54
+ export interface RequestsProxyConfigDict {
55
+ http: string;
56
+ https: string;
57
+ }
58
+
59
+ /**
60
+ * Caption track data from YouTube API
61
+ */
62
+ export interface CaptionTrack {
63
+ baseUrl: string;
64
+ name: {
65
+ runs: Array<{ text: string }>;
66
+ };
67
+ languageCode: string;
68
+ kind?: string;
69
+ isTranslatable?: boolean;
70
+ }
71
+
72
+ /**
73
+ * Captions JSON data from YouTube
74
+ */
75
+ export interface CaptionsJson {
76
+ captionTracks: CaptionTrack[];
77
+ translationLanguages?: Array<{
78
+ languageName: {
79
+ runs: Array<{ text: string }>;
80
+ };
81
+ languageCode: string;
82
+ }>;
83
+ }
84
+
85
+ /**
86
+ * YouTube InnerTube API response
87
+ */
88
+ export interface InnerTubeData {
89
+ playabilityStatus?: {
90
+ status?: string;
91
+ reason?: string;
92
+ errorScreen?: {
93
+ playerErrorMessageRenderer?: {
94
+ subreason?: {
95
+ runs?: Array<{ text?: string }>;
96
+ };
97
+ };
98
+ };
99
+ };
100
+ captions?: {
101
+ playerCaptionsTracklistRenderer?: CaptionsJson;
102
+ };
103
+ }
104
+
105
+ /**
106
+ * HTTP client interface with fetch-like API
107
+ */
108
+ export interface HttpClient {
109
+ get(url: string, options?: RequestInit): Promise<Response>;
110
+ post(url: string, options?: RequestInit): Promise<Response>;
111
+ }
112
+
113
+ /**
114
+ * Cookie storage interface
115
+ */
116
+ export interface CookieJar {
117
+ set(name: string, value: string, domain: string): void;
118
+ get(name: string): string | undefined;
119
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview HTTP error handling utilities for YouTube API requests
3
+ */
4
+
5
+ import { Response } from 'node-fetch';
6
+ import { IpBlocked, YouTubeRequestFailed } from '../errors';
7
+
8
+ /**
9
+ * Checks an HTTP response and throws appropriate errors if the request failed.
10
+ *
11
+ * @param {Response} response - The HTTP response to check
12
+ * @param {string} videoId - The video ID associated with the request
13
+ * @throws {IpBlocked} If status is 429 (Too Many Requests)
14
+ * @throws {YouTubeRequestFailed} If status indicates an error
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const response = await httpClient.get(url);
19
+ * handleHttpErrors(response, videoId);
20
+ * // If we reach here, the request was successful
21
+ * ```
22
+ */
23
+ export function handleHttpErrors(response: Response, videoId: string): void {
24
+ if (response.status === 429) {
25
+ throw new IpBlocked(videoId);
26
+ }
27
+
28
+ if (!response.ok) {
29
+ const errorMessage = `HTTP ${response.status}: ${response.statusText}`;
30
+ throw new YouTubeRequestFailed(videoId, new Error(errorMessage));
31
+ }
32
+ }
@@ -0,0 +1,254 @@
1
+ /**
2
+ * @fileoverview Main API class for the YouTube Transcript API
3
+ */
4
+
5
+ import { ProxyConfig } from './proxies';
6
+ import { FetchedTranscript, TranscriptList } from './models';
7
+ import { TranscriptListFetcher } from './fetchers/transcript-list-fetcher';
8
+ import { HttpClient } from './types';
9
+ import { FetchHttpClient } from './http/fetch-http-client';
10
+
11
+ /**
12
+ * Main API class for retrieving YouTube transcripts.
13
+ * This is the primary entry point for the library.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Basic usage
18
+ * const api = new YouTubeTranscriptApi();
19
+ * const transcript = await api.fetchTranscript('video_id');
20
+ *
21
+ * // With language preference
22
+ * const transcript = await api.fetchTranscript('video_id', { languages: ['de', 'en'] });
23
+ *
24
+ * // With proxy
25
+ * import { GenericProxyConfig } from 'youtube-transcript-api';
26
+ * const api = new YouTubeTranscriptApi({
27
+ * proxyConfig: new GenericProxyConfig({
28
+ * httpUrl: 'http://user:pass@proxy.example.com:8080'
29
+ * })
30
+ * });
31
+ * ```
32
+ */
33
+ export class YouTubeTranscriptApi {
34
+ private transcriptListFetcher: TranscriptListFetcher;
35
+
36
+ /**
37
+ * Creates a new YouTubeTranscriptApi instance.
38
+ *
39
+ * Note on thread-safety: As this class initializes an HTTP client,
40
+ * it is not thread-safe. Make sure to initialize an instance per
41
+ * thread if used in a multi-threading scenario!
42
+ *
43
+ * @param {Object} [options] - Configuration options
44
+ * @param {ProxyConfig} [options.proxyConfig] - An optional ProxyConfig object defining proxies
45
+ * used for all network requests. This can be used to work around your IP being blocked
46
+ * by YouTube, as described in the "Working around IP bans" section of the README.
47
+ * @param {HttpClient} [options.httpClient] - You can optionally pass in a custom HTTP client
48
+ * if you want to share state between different instances of YouTubeTranscriptApi or
49
+ * customize request behavior.
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // Basic usage
54
+ * const api = new YouTubeTranscriptApi();
55
+ *
56
+ * // With Webshare proxy
57
+ * import { WebshareProxyConfig } from 'youtube-transcript-api';
58
+ * const api = new YouTubeTranscriptApi({
59
+ * proxyConfig: new WebshareProxyConfig({
60
+ * proxyUsername: 'your-username',
61
+ * proxyPassword: 'your-password',
62
+ * filterIpLocations: ['us', 'de']
63
+ * })
64
+ * });
65
+ *
66
+ * // With generic proxy
67
+ * import { GenericProxyConfig } from 'youtube-transcript-api';
68
+ * const api = new YouTubeTranscriptApi({
69
+ * proxyConfig: new GenericProxyConfig({
70
+ * httpUrl: 'http://user:pass@proxy.example.com:8080',
71
+ * httpsUrl: 'https://user:pass@proxy.example.com:8080'
72
+ * })
73
+ * });
74
+ * ```
75
+ */
76
+ constructor(options?: { proxyConfig?: ProxyConfig; httpClient?: HttpClient }) {
77
+ const httpClient = this.initializeHttpClient(options);
78
+ this.configureHttpClientWithProxy(httpClient, options?.proxyConfig);
79
+ this.transcriptListFetcher = new TranscriptListFetcher(httpClient, options?.proxyConfig || null);
80
+ }
81
+
82
+ /**
83
+ * Initializes the HTTP client from options or creates a default one.
84
+ *
85
+ * @private
86
+ * @param {Object} [options] - Configuration options
87
+ * @returns {HttpClient} The initialized HTTP client
88
+ */
89
+ private initializeHttpClient(options?: { httpClient?: HttpClient }): HttpClient {
90
+ return options?.httpClient || new FetchHttpClient();
91
+ }
92
+
93
+ /**
94
+ * Configures the HTTP client with proxy settings if provided.
95
+ *
96
+ * @private
97
+ * @param {HttpClient} httpClient - The HTTP client to configure
98
+ * @param {ProxyConfig} [proxyConfig] - Optional proxy configuration
99
+ */
100
+ private configureHttpClientWithProxy(httpClient: HttpClient, proxyConfig?: ProxyConfig): void {
101
+ if (!proxyConfig || !(httpClient instanceof FetchHttpClient)) {
102
+ return;
103
+ }
104
+
105
+ const proxyDictionary = proxyConfig.toRequestsDict();
106
+ httpClient.setProxies(proxyDictionary);
107
+
108
+ if (proxyConfig.preventKeepingConnectionsAlive) {
109
+ httpClient.setHeader('Connection', 'close');
110
+ }
111
+
112
+ // Note: Retry logic for 429 status codes with configured retries
113
+ // would need to be implemented in the HTTP client or fetcher
114
+ }
115
+
116
+ /**
117
+ * Retrieves the transcript for a single video.
118
+ * This is a shortcut for calling:
119
+ * `api.listTranscripts(videoId).then(list => list.findTranscript(languages)).then(t => t.fetch())`
120
+ *
121
+ * @param {string} videoId - The ID of the video you want to retrieve the transcript for.
122
+ * Make sure that this is the actual ID, NOT the full URL to the video!
123
+ * @param {Object} [options] - Fetch options
124
+ * @param {string[]} [options.languages=['en']] - A list of language codes in descending priority.
125
+ * For example, if this is set to ['de', 'en'] it will first try to fetch the german
126
+ * transcript (de) and then fetch the english transcript (en) if it fails to do so.
127
+ * @param {boolean} [options.preserveFormatting=false] - Whether to keep select HTML text formatting
128
+ * @returns {Promise<FetchedTranscript>} The fetched transcript
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const api = new YouTubeTranscriptApi();
133
+ *
134
+ * // Fetch English transcript
135
+ * const transcript = await api.fetchTranscript('dQw4w9WgXcQ');
136
+ *
137
+ * // Fetch with language preference
138
+ * const transcript = await api.fetchTranscript('dQw4w9WgXcQ', {
139
+ * languages: ['de', 'en']
140
+ * });
141
+ *
142
+ * // Preserve HTML formatting
143
+ * const transcript = await api.fetchTranscript('dQw4w9WgXcQ', {
144
+ * preserveFormatting: true
145
+ * });
146
+ *
147
+ * // Iterate over snippets
148
+ * for (const snippet of transcript) {
149
+ * console.log(`${snippet.start}s: ${snippet.text}`);
150
+ * }
151
+ * ```
152
+ */
153
+ async fetchTranscript(
154
+ videoId: string,
155
+ options?: {
156
+ languages?: string[];
157
+ preserveFormatting?: boolean;
158
+ }
159
+ ): Promise<FetchedTranscript> {
160
+ const preferredLanguages = options?.languages || ['en'];
161
+ const preserveFormatting = options?.preserveFormatting || false;
162
+
163
+ const transcriptList = await this.listTranscripts(videoId);
164
+ const transcript = transcriptList.findTranscript(preferredLanguages);
165
+ return transcript.fetch(preserveFormatting);
166
+ }
167
+
168
+ /**
169
+ * Retrieves the list of transcripts which are available for a given video.
170
+ * It returns a TranscriptList object which is iterable and provides methods to
171
+ * filter the list of transcripts for specific languages.
172
+ *
173
+ * While iterating over the TranscriptList, the individual transcripts are
174
+ * represented by Transcript objects, which provide metadata and can either
175
+ * be fetched by calling transcript.fetch() or translated by calling
176
+ * transcript.translate('en').
177
+ *
178
+ * @param {string} videoId - The ID of the video you want to retrieve the transcript for.
179
+ * Make sure that this is the actual ID, NOT the full URL to the video!
180
+ * @returns {Promise<TranscriptList>} A list of available transcripts
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * const api = new YouTubeTranscriptApi();
185
+ *
186
+ * // Retrieve available transcripts
187
+ * const transcriptList = await api.listTranscripts('video_id');
188
+ *
189
+ * // Iterate over all available transcripts
190
+ * for (const transcript of transcriptList) {
191
+ * console.log(
192
+ * transcript.videoId,
193
+ * transcript.language,
194
+ * transcript.languageCode,
195
+ * transcript.isGenerated,
196
+ * transcript.isTranslatable,
197
+ * transcript.translationLanguages
198
+ * );
199
+ *
200
+ * // Fetch the actual transcript data
201
+ * const fetched = await transcript.fetch();
202
+ * console.log(fetched);
203
+ *
204
+ * // Translate the transcript
205
+ * if (transcript.isTranslatable) {
206
+ * const translated = transcript.translate('de');
207
+ * const fetchedTranslated = await translated.fetch();
208
+ * console.log(fetchedTranslated);
209
+ * }
210
+ * }
211
+ *
212
+ * // Filter for specific language
213
+ * const transcript = transcriptList.findTranscript(['de', 'en']);
214
+ *
215
+ * // Filter for manually created transcripts
216
+ * const manual = transcriptList.findManuallyCreatedTranscript(['de', 'en']);
217
+ *
218
+ * // Filter for automatically generated transcripts
219
+ * const generated = transcriptList.findGeneratedTranscript(['de', 'en']);
220
+ * ```
221
+ */
222
+ async listTranscripts(videoId: string): Promise<TranscriptList> {
223
+ return this.transcriptListFetcher.fetchTranscriptList(videoId);
224
+ }
225
+
226
+ /**
227
+ * Alias for fetchTranscript() for backward compatibility.
228
+ *
229
+ * @deprecated Use fetchTranscript() instead
230
+ * @param {string} videoId - The video ID
231
+ * @param {Object} [options] - Fetch options
232
+ * @returns {Promise<FetchedTranscript>} The fetched transcript
233
+ */
234
+ async fetch(
235
+ videoId: string,
236
+ options?: {
237
+ languages?: string[];
238
+ preserveFormatting?: boolean;
239
+ }
240
+ ): Promise<FetchedTranscript> {
241
+ return this.fetchTranscript(videoId, options);
242
+ }
243
+
244
+ /**
245
+ * Alias for listTranscripts() for backward compatibility.
246
+ *
247
+ * @deprecated Use listTranscripts() instead
248
+ * @param {string} videoId - The video ID
249
+ * @returns {Promise<TranscriptList>} A list of available transcripts
250
+ */
251
+ async list(videoId: string): Promise<TranscriptList> {
252
+ return this.listTranscripts(videoId);
253
+ }
254
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "strict": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "moduleResolution": "node",
16
+ "resolveJsonModule": true
17
+ },
18
+ "include": ["src/**/*", "__tests__"],
19
+ "exclude": ["node_modules", "dist", "src/**/*.test.ts", "__tests__"]
20
+ }