@ooneex/youtube 0.0.4
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/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/index.d.ts +439 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +11 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ooneex
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @ooneex/youtube
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { ArgsOptions, FormatOptions, PlaylistInfo, QualityOptions, VideoFormat, VideoInfo, VideoProgress } from "ytdlp-nodejs";
|
|
2
|
+
/**
|
|
3
|
+
* Video information returned from YouTube.
|
|
4
|
+
* Contains metadata such as title, description, duration, view count, etc.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const info: YoutubeVideoInfoType = await youtube.getVideoInfo(url);
|
|
9
|
+
* console.log(info.title, info.duration, info.view_count);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
type YoutubeVideoInfoType = VideoInfo;
|
|
13
|
+
/**
|
|
14
|
+
* Playlist information returned from YouTube.
|
|
15
|
+
* Contains playlist metadata and list of videos in the playlist.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const playlist: YoutubePlaylistInfoType = await youtube.getPlaylistInfo(url);
|
|
20
|
+
* console.log(playlist.title, playlist.entries.length);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
type YoutubePlaylistInfoType = PlaylistInfo;
|
|
24
|
+
/**
|
|
25
|
+
* Video format information including codec, resolution, and bitrate details.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const info = await youtube.getVideoInfo(url);
|
|
30
|
+
* const formats: YoutubeVideoFormatType[] = info.formats;
|
|
31
|
+
* formats.forEach(f => console.log(f.format_id, f.ext, f.resolution));
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
type YoutubeVideoFormatType = VideoFormat;
|
|
35
|
+
/**
|
|
36
|
+
* Download progress information for tracking video download status.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const progress: YoutubeVideoProgressType = {
|
|
41
|
+
* percent: 50,
|
|
42
|
+
* totalSize: "100MB",
|
|
43
|
+
* currentSpeed: "5MB/s",
|
|
44
|
+
* eta: "10s",
|
|
45
|
+
* };
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
type YoutubeVideoProgressType = VideoProgress;
|
|
49
|
+
/**
|
|
50
|
+
* Additional arguments options for yt-dlp commands.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const args: YoutubeArgsOptionsType = {
|
|
55
|
+
* noPlaylist: true,
|
|
56
|
+
* extractAudio: true,
|
|
57
|
+
* };
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
type YoutubeArgsOptionsType = ArgsOptions;
|
|
61
|
+
/**
|
|
62
|
+
* Format options for downloading videos with specific quality settings.
|
|
63
|
+
*
|
|
64
|
+
* @typeParam F - The format keyword type (e.g., "video", "audio", "videoandaudio")
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const options: YoutubeFormatOptionsType<"video"> = {
|
|
69
|
+
* format: { quality: "1080p" },
|
|
70
|
+
* };
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
type YoutubeFormatOptionsType<F extends YoutubeFormatKeyWordType> = FormatOptions<F>;
|
|
74
|
+
/**
|
|
75
|
+
* Quality options for specifying video/audio quality preferences.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const quality: YoutubeQualityOptionsType = {
|
|
80
|
+
* video: "1080p",
|
|
81
|
+
* audio: "highest",
|
|
82
|
+
* };
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
type YoutubeQualityOptionsType = QualityOptions;
|
|
86
|
+
/**
|
|
87
|
+
* Format keyword type for specifying download format categories.
|
|
88
|
+
* Can be "video", "audio", or "videoandaudio".
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const format: YoutubeFormatKeyWordType = "videoandaudio";
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
type YoutubeFormatKeyWordType = keyof QualityOptions;
|
|
96
|
+
/**
|
|
97
|
+
* Video quality presets for download operations.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const quality: YoutubeVideoQualityType = "1080p";
|
|
102
|
+
*
|
|
103
|
+
* // Available options:
|
|
104
|
+
* // - "2160p" (4K)
|
|
105
|
+
* // - "1440p" (2K)
|
|
106
|
+
* // - "1080p" (Full HD)
|
|
107
|
+
* // - "720p" (HD)
|
|
108
|
+
* // - "480p" (SD)
|
|
109
|
+
* // - "360p", "240p", "144p" (Low quality)
|
|
110
|
+
* // - "highest" (Best available)
|
|
111
|
+
* // - "lowest" (Smallest file size)
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
type YoutubeVideoQualityType = "2160p" | "1440p" | "1080p" | "720p" | "480p" | "360p" | "240p" | "144p" | "highest" | "lowest";
|
|
115
|
+
/**
|
|
116
|
+
* Audio quality presets for audio download operations.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const quality: YoutubeAudioQualityType = "highest";
|
|
121
|
+
*
|
|
122
|
+
* // Available options:
|
|
123
|
+
* // - "highest" (Best available audio quality)
|
|
124
|
+
* // - "lowest" (Smallest file size)
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
type YoutubeAudioQualityType = "highest" | "lowest";
|
|
128
|
+
/**
|
|
129
|
+
* Configuration options for the YouTube client.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const options: YoutubeOptionsType = {
|
|
134
|
+
* binaryPath: "/usr/local/bin/yt-dlp",
|
|
135
|
+
* ffmpegPath: "/usr/local/bin/ffmpeg",
|
|
136
|
+
* };
|
|
137
|
+
* const youtube = new Youtube(options);
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
type YoutubeOptionsType = {
|
|
141
|
+
/**
|
|
142
|
+
* Path to the yt-dlp binary.
|
|
143
|
+
* Falls back to YOUTUBE_YTDLP_PATH environment variable if not provided.
|
|
144
|
+
*/
|
|
145
|
+
binaryPath?: string;
|
|
146
|
+
/**
|
|
147
|
+
* Path to the ffmpeg binary.
|
|
148
|
+
* Falls back to YOUTUBE_FFMPEG_PATH environment variable if not provided.
|
|
149
|
+
*/
|
|
150
|
+
ffmpegPath?: string;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Interface defining the YouTube client API.
|
|
154
|
+
* Provides methods for fetching video info, downloading, and managing media.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* class MyYoutubeClient implements IYoutube {
|
|
159
|
+
* async getVideoInfo(url: string) { ... }
|
|
160
|
+
* async getPlaylistInfo(url: string) { ... }
|
|
161
|
+
* // ... implement all methods
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
interface IYoutube {
|
|
166
|
+
/**
|
|
167
|
+
* Retrieves detailed information about a YouTube video.
|
|
168
|
+
* @param url - The YouTube video URL
|
|
169
|
+
* @returns Promise resolving to video metadata
|
|
170
|
+
*/
|
|
171
|
+
getVideoInfo(url: string): Promise<YoutubeVideoInfoType>;
|
|
172
|
+
/**
|
|
173
|
+
* Retrieves information about a YouTube playlist.
|
|
174
|
+
* @param url - The YouTube playlist URL
|
|
175
|
+
* @returns Promise resolving to playlist metadata
|
|
176
|
+
*/
|
|
177
|
+
getPlaylistInfo(url: string): Promise<YoutubePlaylistInfoType>;
|
|
178
|
+
/**
|
|
179
|
+
* Downloads a video to the local filesystem.
|
|
180
|
+
* @param url - The YouTube video URL
|
|
181
|
+
* @param destination - The destination path for the downloaded file
|
|
182
|
+
* @returns Promise resolving to the downloaded file path
|
|
183
|
+
*/
|
|
184
|
+
download(url: string, destination: string): Promise<string>;
|
|
185
|
+
/**
|
|
186
|
+
* Downloads a video and returns it as a File object.
|
|
187
|
+
* @param url - The YouTube video URL
|
|
188
|
+
* @param options - Optional filename and format settings
|
|
189
|
+
* @returns Promise resolving to a File object
|
|
190
|
+
*/
|
|
191
|
+
getFile<F extends YoutubeFormatKeyWordType>(url: string, options?: {
|
|
192
|
+
filename?: string;
|
|
193
|
+
format?: YoutubeFormatOptionsType<F>["format"];
|
|
194
|
+
}): Promise<File>;
|
|
195
|
+
/**
|
|
196
|
+
* Extracts the video ID (watch ID) from a YouTube URL.
|
|
197
|
+
* @param url - The YouTube video URL
|
|
198
|
+
* @returns The video ID or null if not found
|
|
199
|
+
*/
|
|
200
|
+
getWatchId(url: string): string | null;
|
|
201
|
+
/**
|
|
202
|
+
* Generates an embed URL for a YouTube video.
|
|
203
|
+
* @param urlOrId - The YouTube video URL or video ID
|
|
204
|
+
* @returns The embed URL or null if the video ID cannot be extracted
|
|
205
|
+
*/
|
|
206
|
+
getEmbedUrl(urlOrId: string): string | null;
|
|
207
|
+
/**
|
|
208
|
+
* Generates a standard watch URL for a YouTube video.
|
|
209
|
+
* @param urlOrId - The YouTube video URL or video ID
|
|
210
|
+
* @returns The watch URL or null if the video ID cannot be extracted
|
|
211
|
+
*/
|
|
212
|
+
getWatchUrl(urlOrId: string): string | null;
|
|
213
|
+
/**
|
|
214
|
+
* Downloads only the audio from a YouTube video.
|
|
215
|
+
* @param url - The YouTube video URL
|
|
216
|
+
* @param destination - The destination path for the downloaded audio file
|
|
217
|
+
* @returns Promise resolving to the downloaded audio file path
|
|
218
|
+
*/
|
|
219
|
+
downloadAudio(url: string, destination: string): Promise<string>;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* YouTube client for downloading and extracting information from YouTube videos and playlists.
|
|
223
|
+
* Wraps yt-dlp functionality with a clean async API and proper error handling.
|
|
224
|
+
*
|
|
225
|
+
* @example Basic Usage
|
|
226
|
+
* ```typescript
|
|
227
|
+
* import { Youtube } from "@ooneex/youtube";
|
|
228
|
+
*
|
|
229
|
+
* const youtube = new Youtube();
|
|
230
|
+
*
|
|
231
|
+
* // Get video information
|
|
232
|
+
* const info = await youtube.getVideoInfo("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
233
|
+
* console.log(info.title, info.duration);
|
|
234
|
+
*
|
|
235
|
+
* // Download a video
|
|
236
|
+
* const filePath = await youtube.download("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
237
|
+
* console.log(`Downloaded to: ${filePath}`);
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @example Download with Quality Options
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const youtube = new Youtube();
|
|
243
|
+
*
|
|
244
|
+
* // Download video in 1080p
|
|
245
|
+
* const path = await youtube.download(url, {
|
|
246
|
+
* format: { video: "1080p" },
|
|
247
|
+
* });
|
|
248
|
+
*
|
|
249
|
+
* // Download audio only
|
|
250
|
+
* const audioPath = await youtube.download(url, {
|
|
251
|
+
* format: { audio: "highest" },
|
|
252
|
+
* });
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
declare class Youtube implements IYoutube {
|
|
256
|
+
private readonly ytdlp;
|
|
257
|
+
/**
|
|
258
|
+
* Creates a new YouTube client instance.
|
|
259
|
+
*
|
|
260
|
+
* @param options - Optional configuration for binary paths
|
|
261
|
+
* @throws {YoutubeException} If required binary paths are not configured
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* const youtube = new Youtube();
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @example With Custom Paths
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const youtube = new Youtube({
|
|
271
|
+
* binaryPath: "/custom/path/to/yt-dlp",
|
|
272
|
+
* ffmpegPath: "/custom/path/to/ffmpeg",
|
|
273
|
+
* });
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
276
|
+
constructor(options?: YoutubeOptionsType);
|
|
277
|
+
/**
|
|
278
|
+
* Retrieves detailed metadata for a YouTube video.
|
|
279
|
+
*
|
|
280
|
+
* @param url - The YouTube video URL
|
|
281
|
+
* @returns Promise resolving to video information including title, description,
|
|
282
|
+
* duration, view count, available formats, and more
|
|
283
|
+
* @throws {YoutubeException} If the video cannot be accessed or URL is invalid
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* const youtube = new Youtube();
|
|
288
|
+
* const info = await youtube.getVideoInfo("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
289
|
+
*
|
|
290
|
+
* console.log("Title:", info.title);
|
|
291
|
+
* console.log("Duration:", info.duration, "seconds");
|
|
292
|
+
* console.log("Views:", info.view_count);
|
|
293
|
+
* console.log("Description:", info.description);
|
|
294
|
+
* console.log("Available formats:", info.formats.length);
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
getVideoInfo(url: string): Promise<YoutubeVideoInfoType>;
|
|
298
|
+
/**
|
|
299
|
+
* Retrieves information about a YouTube playlist including all videos.
|
|
300
|
+
*
|
|
301
|
+
* @param url - The YouTube playlist URL
|
|
302
|
+
* @returns Promise resolving to playlist metadata and video entries
|
|
303
|
+
* @throws {YoutubeException} If the playlist cannot be accessed or URL is invalid
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const youtube = new Youtube();
|
|
308
|
+
* const playlist = await youtube.getPlaylistInfo(
|
|
309
|
+
* "https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf"
|
|
310
|
+
* );
|
|
311
|
+
*
|
|
312
|
+
* console.log("Playlist:", playlist.title);
|
|
313
|
+
* console.log("Video count:", playlist.entries.length);
|
|
314
|
+
*
|
|
315
|
+
* // Iterate over videos in the playlist
|
|
316
|
+
* for (const video of playlist.entries) {
|
|
317
|
+
* console.log(`- ${video.title} (${video.duration}s)`);
|
|
318
|
+
* }
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
getPlaylistInfo(url: string): Promise<YoutubePlaylistInfoType>;
|
|
322
|
+
/**
|
|
323
|
+
* Downloads a video to the local filesystem.
|
|
324
|
+
*
|
|
325
|
+
* @typeParam F - The format keyword type (video, audio, or videoandaudio)
|
|
326
|
+
* @param url - The YouTube video URL
|
|
327
|
+
* @param options - Optional format and quality settings
|
|
328
|
+
* @returns Promise resolving to the path of the downloaded file
|
|
329
|
+
* @throws {YoutubeException} If download fails
|
|
330
|
+
*
|
|
331
|
+
* @example Download with Default Settings
|
|
332
|
+
* ```typescript
|
|
333
|
+
* const youtube = new Youtube();
|
|
334
|
+
* const filePath = await youtube.download("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
335
|
+
* console.log("Downloaded to:", filePath);
|
|
336
|
+
* ```
|
|
337
|
+
*
|
|
338
|
+
* @example Download with Specific Quality
|
|
339
|
+
* ```typescript
|
|
340
|
+
* const youtube = new Youtube();
|
|
341
|
+
*
|
|
342
|
+
* // Download 1080p video
|
|
343
|
+
* const videoPath = await youtube.download(url, {
|
|
344
|
+
* format: { video: "1080p" },
|
|
345
|
+
* });
|
|
346
|
+
*
|
|
347
|
+
* // Download 720p video with audio
|
|
348
|
+
* const hdPath = await youtube.download(url, {
|
|
349
|
+
* format: { videoandaudio: "720p" },
|
|
350
|
+
* });
|
|
351
|
+
* ```
|
|
352
|
+
*
|
|
353
|
+
* @example Download Audio Only
|
|
354
|
+
* ```typescript
|
|
355
|
+
* const youtube = new Youtube();
|
|
356
|
+
* const audioPath = await youtube.download(url, {
|
|
357
|
+
* format: { audio: "highest" },
|
|
358
|
+
* });
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
download(url: string, destination: string): Promise<string>;
|
|
362
|
+
/**
|
|
363
|
+
* Downloads only the audio from a YouTube video.
|
|
364
|
+
* Convenience method that wraps download with audio-only format settings.
|
|
365
|
+
*
|
|
366
|
+
* @param url - The YouTube video URL
|
|
367
|
+
* @param quality - Audio quality preference (defaults to "highest")
|
|
368
|
+
* @returns Promise resolving to the path of the downloaded audio file
|
|
369
|
+
* @throws {YoutubeException} If download fails
|
|
370
|
+
*
|
|
371
|
+
* @example Basic Usage
|
|
372
|
+
* ```typescript
|
|
373
|
+
* const youtube = new Youtube();
|
|
374
|
+
* const audioPath = await youtube.downloadAudio("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
375
|
+
* console.log("Audio downloaded to:", audioPath);
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
* @example With Quality Option
|
|
379
|
+
* ```typescript
|
|
380
|
+
* const youtube = new Youtube();
|
|
381
|
+
*
|
|
382
|
+
* // Download highest quality audio
|
|
383
|
+
* const hqPath = await youtube.downloadAudio(url, "highest");
|
|
384
|
+
*
|
|
385
|
+
* // Download lowest quality (smaller file)
|
|
386
|
+
* const lqPath = await youtube.downloadAudio(url, "lowest");
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
downloadAudio(url: string, destination: string): Promise<string>;
|
|
390
|
+
/**
|
|
391
|
+
* Downloads a video and returns it as a File object.
|
|
392
|
+
* Useful for in-memory processing or streaming without saving to disk.
|
|
393
|
+
*
|
|
394
|
+
* @typeParam F - The format keyword type (video, audio, or videoandaudio)
|
|
395
|
+
* @param url - The YouTube video URL
|
|
396
|
+
* @param options - Optional filename and format settings
|
|
397
|
+
* @returns Promise resolving to a File object containing the video data
|
|
398
|
+
* @throws {YoutubeException} If download fails
|
|
399
|
+
*
|
|
400
|
+
* @example Basic Usage
|
|
401
|
+
* ```typescript
|
|
402
|
+
* const youtube = new Youtube();
|
|
403
|
+
* const file = await youtube.getFile("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
404
|
+
*
|
|
405
|
+
* console.log("File name:", file.name);
|
|
406
|
+
* console.log("File size:", file.size, "bytes");
|
|
407
|
+
* console.log("MIME type:", file.type);
|
|
408
|
+
* ```
|
|
409
|
+
*
|
|
410
|
+
* @example With Custom Filename
|
|
411
|
+
* ```typescript
|
|
412
|
+
* const youtube = new Youtube();
|
|
413
|
+
* const file = await youtube.getFile(url, {
|
|
414
|
+
* filename: "my-video.mp4",
|
|
415
|
+
* });
|
|
416
|
+
* ```
|
|
417
|
+
*
|
|
418
|
+
* @example With Format Options
|
|
419
|
+
* ```typescript
|
|
420
|
+
* const youtube = new Youtube();
|
|
421
|
+
* const audioFile = await youtube.getFile(url, {
|
|
422
|
+
* filename: "audio.mp3",
|
|
423
|
+
* format: { audio: "highest" },
|
|
424
|
+
* });
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
getFile<F extends YoutubeFormatKeyWordType>(url: string, options?: {
|
|
428
|
+
filename?: string;
|
|
429
|
+
format?: YoutubeFormatOptionsType<F>["format"] | undefined;
|
|
430
|
+
}): Promise<File>;
|
|
431
|
+
getWatchId(url: string): string | null;
|
|
432
|
+
getEmbedUrl(urlOrId: string): string | null;
|
|
433
|
+
getWatchUrl(urlOrId: string): string | null;
|
|
434
|
+
}
|
|
435
|
+
import { Exception } from "@ooneex/exception";
|
|
436
|
+
declare class YoutubeException extends Exception {
|
|
437
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
438
|
+
}
|
|
439
|
+
export { YoutubeVideoQualityType, YoutubeVideoProgressType, YoutubeVideoInfoType, YoutubeVideoFormatType, YoutubeQualityOptionsType, YoutubePlaylistInfoType, YoutubeOptionsType, YoutubeFormatOptionsType, YoutubeFormatKeyWordType, YoutubeException, YoutubeAudioQualityType, YoutubeArgsOptionsType, Youtube, IYoutube };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{YtDlp as B}from"ytdlp-nodejs";import{Exception as z}from"@ooneex/exception";import{HttpStatus as A}from"@ooneex/http-status";class q extends z{constructor(S,C={}){super(S,{status:A.Code.InternalServerError,data:C});this.name="YoutubeException"}}class F{ytdlp;constructor(S={}){let C=S.binaryPath||Bun.env.YOUTUBE_YTDLP_PATH,H=S.ffmpegPath||Bun.env.YOUTUBE_FFMPEG_PATH;if(!C)throw new q("yt-dlp binary path is required. Please provide it through the constructor options or set the YOUTUBE_YTDLP_PATH environment variable.");if(!H)throw new q("ffmpeg binary path is required. Please provide it through the constructor options or set the YOUTUBE_FFMPEG_PATH environment variable.");this.ytdlp=new B({binaryPath:C,ffmpegPath:H})}async getVideoInfo(S){try{return await this.ytdlp.getInfoAsync(S)}catch(C){throw new q(`Failed to get video info: ${C.message}`,{data:{url:S}})}}async getPlaylistInfo(S){try{return await this.ytdlp.getInfoAsync(S)}catch(C){throw new q(`Failed to get playlist info: ${C.message}`,{data:{url:S}})}}async download(S,C){try{return await this.ytdlp.downloadAsync(this.getWatchId(S)||"",{format:{filter:"audioandvideo",type:"mp4"},output:C})}catch(H){throw new q(`Failed to download video: ${H.message}`,{data:{url:S}})}}async downloadAudio(S,C){try{return await this.ytdlp.downloadAsync(this.getWatchId(S)||"",{format:{filter:"audioonly",type:"mp3"},output:C})}catch(H){throw new q(`Failed to download audio: ${H.message}`,{data:{url:S}})}}async getFile(S,C){try{let H=C?{filename:C.filename,format:C.format}:void 0;return await this.ytdlp.getFileAsync(this.getWatchId(S)||"",H)}catch(H){throw new q(`Failed to get file: ${H.message}`,{data:{url:S}})}}getWatchId(S){let C=[/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/watch\?.*&v=)([^&\n?#]+)/,/youtube\.com\/shorts\/([^&\n?#]+)/];for(let H of C){let x=S.match(H);if(x?.[1])return x[1]}return null}getEmbedUrl(S){let C=this.getWatchId(S)??S;if(!/^[\w-]{10,12}$/.test(C))return null;return`https://www.youtube.com/embed/${C}`}getWatchUrl(S){let C=this.getWatchId(S)??S;if(!/^[\w-]{10,12}$/.test(C))return null;return`https://www.youtube.com/watch?v=${C}`}}export{q as YoutubeException,F as Youtube};
|
|
3
|
+
|
|
4
|
+
//# debugId=D8DC7E8F8C92550864756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["src/Youtube.ts", "src/YoutubeException.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { YtDlp } from \"ytdlp-nodejs\";\nimport type {\n IYoutube,\n YoutubeFormatKeyWordType,\n YoutubeFormatOptionsType,\n YoutubeOptionsType,\n YoutubePlaylistInfoType,\n YoutubeVideoInfoType,\n} from \"./types\";\nimport { YoutubeException } from \"./YoutubeException\";\n\n/**\n * YouTube client for downloading and extracting information from YouTube videos and playlists.\n * Wraps yt-dlp functionality with a clean async API and proper error handling.\n *\n * @example Basic Usage\n * ```typescript\n * import { Youtube } from \"@ooneex/youtube\";\n *\n * const youtube = new Youtube();\n *\n * // Get video information\n * const info = await youtube.getVideoInfo(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n * console.log(info.title, info.duration);\n *\n * // Download a video\n * const filePath = await youtube.download(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n * console.log(`Downloaded to: ${filePath}`);\n * ```\n *\n * @example Download with Quality Options\n * ```typescript\n * const youtube = new Youtube();\n *\n * // Download video in 1080p\n * const path = await youtube.download(url, {\n * format: { video: \"1080p\" },\n * });\n *\n * // Download audio only\n * const audioPath = await youtube.download(url, {\n * format: { audio: \"highest\" },\n * });\n * ```\n */\nexport class Youtube implements IYoutube {\n private readonly ytdlp: YtDlp;\n\n /**\n * Creates a new YouTube client instance.\n *\n * @param options - Optional configuration for binary paths\n * @throws {YoutubeException} If required binary paths are not configured\n *\n * @example\n * ```typescript\n * const youtube = new Youtube();\n * ```\n *\n * @example With Custom Paths\n * ```typescript\n * const youtube = new Youtube({\n * binaryPath: \"/custom/path/to/yt-dlp\",\n * ffmpegPath: \"/custom/path/to/ffmpeg\",\n * });\n * ```\n */\n constructor(options: YoutubeOptionsType = {}) {\n const binaryPath = options.binaryPath || Bun.env.YOUTUBE_YTDLP_PATH;\n const ffmpegPath = options.ffmpegPath || Bun.env.YOUTUBE_FFMPEG_PATH;\n\n if (!binaryPath) {\n throw new YoutubeException(\n \"yt-dlp binary path is required. Please provide it through the constructor options or set the YOUTUBE_YTDLP_PATH environment variable.\",\n );\n }\n\n if (!ffmpegPath) {\n throw new YoutubeException(\n \"ffmpeg binary path is required. Please provide it through the constructor options or set the YOUTUBE_FFMPEG_PATH environment variable.\",\n );\n }\n\n this.ytdlp = new YtDlp({\n binaryPath,\n ffmpegPath,\n });\n }\n\n /**\n * Retrieves detailed metadata for a YouTube video.\n *\n * @param url - The YouTube video URL\n * @returns Promise resolving to video information including title, description,\n * duration, view count, available formats, and more\n * @throws {YoutubeException} If the video cannot be accessed or URL is invalid\n *\n * @example\n * ```typescript\n * const youtube = new Youtube();\n * const info = await youtube.getVideoInfo(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n *\n * console.log(\"Title:\", info.title);\n * console.log(\"Duration:\", info.duration, \"seconds\");\n * console.log(\"Views:\", info.view_count);\n * console.log(\"Description:\", info.description);\n * console.log(\"Available formats:\", info.formats.length);\n * ```\n */\n public async getVideoInfo(url: string): Promise<YoutubeVideoInfoType> {\n try {\n return await this.ytdlp.getInfoAsync<\"video\">(url);\n } catch (error) {\n throw new YoutubeException(`Failed to get video info: ${(error as Error).message}`, {\n data: { url },\n });\n }\n }\n\n /**\n * Retrieves information about a YouTube playlist including all videos.\n *\n * @param url - The YouTube playlist URL\n * @returns Promise resolving to playlist metadata and video entries\n * @throws {YoutubeException} If the playlist cannot be accessed or URL is invalid\n *\n * @example\n * ```typescript\n * const youtube = new Youtube();\n * const playlist = await youtube.getPlaylistInfo(\n * \"https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf\"\n * );\n *\n * console.log(\"Playlist:\", playlist.title);\n * console.log(\"Video count:\", playlist.entries.length);\n *\n * // Iterate over videos in the playlist\n * for (const video of playlist.entries) {\n * console.log(`- ${video.title} (${video.duration}s)`);\n * }\n * ```\n */\n public async getPlaylistInfo(url: string): Promise<YoutubePlaylistInfoType> {\n try {\n return await this.ytdlp.getInfoAsync<\"playlist\">(url);\n } catch (error) {\n throw new YoutubeException(`Failed to get playlist info: ${(error as Error).message}`, {\n data: { url },\n });\n }\n }\n\n /**\n * Downloads a video to the local filesystem.\n *\n * @typeParam F - The format keyword type (video, audio, or videoandaudio)\n * @param url - The YouTube video URL\n * @param options - Optional format and quality settings\n * @returns Promise resolving to the path of the downloaded file\n * @throws {YoutubeException} If download fails\n *\n * @example Download with Default Settings\n * ```typescript\n * const youtube = new Youtube();\n * const filePath = await youtube.download(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n * console.log(\"Downloaded to:\", filePath);\n * ```\n *\n * @example Download with Specific Quality\n * ```typescript\n * const youtube = new Youtube();\n *\n * // Download 1080p video\n * const videoPath = await youtube.download(url, {\n * format: { video: \"1080p\" },\n * });\n *\n * // Download 720p video with audio\n * const hdPath = await youtube.download(url, {\n * format: { videoandaudio: \"720p\" },\n * });\n * ```\n *\n * @example Download Audio Only\n * ```typescript\n * const youtube = new Youtube();\n * const audioPath = await youtube.download(url, {\n * format: { audio: \"highest\" },\n * });\n * ```\n */\n public async download(url: string, destination: string): Promise<string> {\n try {\n return await this.ytdlp.downloadAsync(this.getWatchId(url) || \"\", {\n format: { filter: \"audioandvideo\", type: \"mp4\" },\n output: destination,\n });\n } catch (error) {\n throw new YoutubeException(`Failed to download video: ${(error as Error).message}`, {\n data: { url },\n });\n }\n }\n\n /**\n * Downloads only the audio from a YouTube video.\n * Convenience method that wraps download with audio-only format settings.\n *\n * @param url - The YouTube video URL\n * @param quality - Audio quality preference (defaults to \"highest\")\n * @returns Promise resolving to the path of the downloaded audio file\n * @throws {YoutubeException} If download fails\n *\n * @example Basic Usage\n * ```typescript\n * const youtube = new Youtube();\n * const audioPath = await youtube.downloadAudio(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n * console.log(\"Audio downloaded to:\", audioPath);\n * ```\n *\n * @example With Quality Option\n * ```typescript\n * const youtube = new Youtube();\n *\n * // Download highest quality audio\n * const hqPath = await youtube.downloadAudio(url, \"highest\");\n *\n * // Download lowest quality (smaller file)\n * const lqPath = await youtube.downloadAudio(url, \"lowest\");\n * ```\n */\n public async downloadAudio(url: string, destination: string): Promise<string> {\n try {\n return await this.ytdlp.downloadAsync(this.getWatchId(url) || \"\", {\n format: { filter: \"audioonly\", type: \"mp3\" },\n output: destination,\n });\n } catch (error) {\n throw new YoutubeException(`Failed to download audio: ${(error as Error).message}`, {\n data: { url },\n });\n }\n }\n\n /**\n * Downloads a video and returns it as a File object.\n * Useful for in-memory processing or streaming without saving to disk.\n *\n * @typeParam F - The format keyword type (video, audio, or videoandaudio)\n * @param url - The YouTube video URL\n * @param options - Optional filename and format settings\n * @returns Promise resolving to a File object containing the video data\n * @throws {YoutubeException} If download fails\n *\n * @example Basic Usage\n * ```typescript\n * const youtube = new Youtube();\n * const file = await youtube.getFile(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n *\n * console.log(\"File name:\", file.name);\n * console.log(\"File size:\", file.size, \"bytes\");\n * console.log(\"MIME type:\", file.type);\n * ```\n *\n * @example With Custom Filename\n * ```typescript\n * const youtube = new Youtube();\n * const file = await youtube.getFile(url, {\n * filename: \"my-video.mp4\",\n * });\n * ```\n *\n * @example With Format Options\n * ```typescript\n * const youtube = new Youtube();\n * const audioFile = await youtube.getFile(url, {\n * filename: \"audio.mp3\",\n * format: { audio: \"highest\" },\n * });\n * ```\n */\n public async getFile<F extends YoutubeFormatKeyWordType>(\n url: string,\n options?: { filename?: string; format?: YoutubeFormatOptionsType<F>[\"format\"] | undefined },\n ): Promise<File> {\n try {\n const fileOptions = options ? { filename: options.filename, format: options.format } : undefined;\n return await this.ytdlp.getFileAsync(\n this.getWatchId(url) || \"\",\n fileOptions as Parameters<typeof this.ytdlp.getFileAsync<F>>[1],\n );\n } catch (error) {\n throw new YoutubeException(`Failed to get file: ${(error as Error).message}`, {\n data: { url },\n });\n }\n }\n\n public getWatchId(url: string): string | null {\n const patterns = [\n /(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/|youtube\\.com\\/embed\\/|youtube\\.com\\/v\\/|youtube\\.com\\/watch\\?.*&v=)([^&\\n?#]+)/,\n /youtube\\.com\\/shorts\\/([^&\\n?#]+)/,\n ];\n\n for (const pattern of patterns) {\n const match = url.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n\n return null;\n }\n\n public getEmbedUrl(urlOrId: string): string | null {\n const videoId = this.getWatchId(urlOrId) ?? urlOrId;\n\n // Validate that it looks like a YouTube video ID (typically 11 characters, alphanumeric with - and _)\n if (!/^[\\w-]{10,12}$/.test(videoId)) {\n return null;\n }\n\n return `https://www.youtube.com/embed/${videoId}`;\n }\n\n public getWatchUrl(urlOrId: string): string | null {\n const videoId = this.getWatchId(urlOrId) ?? urlOrId;\n\n // Validate that it looks like a YouTube video ID (typically 11 characters, alphanumeric with - and _)\n if (!/^[\\w-]{10,12}$/.test(videoId)) {\n return null;\n }\n\n return `https://www.youtube.com/watch?v=${videoId}`;\n }\n}\n",
|
|
6
|
+
"import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class YoutubeException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"YoutubeException\";\n }\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": ";AAAA,gBAAS,qBCAT,oBAAS,0BACT,qBAAS,4BAEF,MAAM,UAAyB,CAAU,CAC9C,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,oBACxB,MACF,CAAC,EACD,KAAK,KAAO,mBAEhB,CDkCO,MAAM,CAA4B,CACtB,MAqBjB,WAAW,CAAC,EAA8B,CAAC,EAAG,CAC5C,IAAM,EAAa,EAAQ,YAAc,IAAI,IAAI,mBAC3C,EAAa,EAAQ,YAAc,IAAI,IAAI,oBAEjD,GAAI,CAAC,EACH,MAAM,IAAI,EACR,uIACF,EAGF,GAAI,CAAC,EACH,MAAM,IAAI,EACR,wIACF,EAGF,KAAK,MAAQ,IAAI,EAAM,CACrB,aACA,YACF,CAAC,OAuBU,aAAY,CAAC,EAA4C,CACpE,GAAI,CACF,OAAO,MAAM,KAAK,MAAM,aAAsB,CAAG,EACjD,MAAO,EAAO,CACd,MAAM,IAAI,EAAiB,6BAA8B,EAAgB,UAAW,CAClF,KAAM,CAAE,KAAI,CACd,CAAC,QA2BQ,gBAAe,CAAC,EAA+C,CAC1E,GAAI,CACF,OAAO,MAAM,KAAK,MAAM,aAAyB,CAAG,EACpD,MAAO,EAAO,CACd,MAAM,IAAI,EAAiB,gCAAiC,EAAgB,UAAW,CACrF,KAAM,CAAE,KAAI,CACd,CAAC,QA2CQ,SAAQ,CAAC,EAAa,EAAsC,CACvE,GAAI,CACF,OAAO,MAAM,KAAK,MAAM,cAAc,KAAK,WAAW,CAAG,GAAK,GAAI,CAChE,OAAQ,CAAE,OAAQ,gBAAiB,KAAM,KAAM,EAC/C,OAAQ,CACV,CAAC,EACD,MAAO,EAAO,CACd,MAAM,IAAI,EAAiB,6BAA8B,EAAgB,UAAW,CAClF,KAAM,CAAE,KAAI,CACd,CAAC,QA+BQ,cAAa,CAAC,EAAa,EAAsC,CAC5E,GAAI,CACF,OAAO,MAAM,KAAK,MAAM,cAAc,KAAK,WAAW,CAAG,GAAK,GAAI,CAChE,OAAQ,CAAE,OAAQ,YAAa,KAAM,KAAM,EAC3C,OAAQ,CACV,CAAC,EACD,MAAO,EAAO,CACd,MAAM,IAAI,EAAiB,6BAA8B,EAAgB,UAAW,CAClF,KAAM,CAAE,KAAI,CACd,CAAC,QAyCQ,QAA2C,CACtD,EACA,EACe,CACf,GAAI,CACF,IAAM,EAAc,EAAU,CAAE,SAAU,EAAQ,SAAU,OAAQ,EAAQ,MAAO,EAAI,OACvF,OAAO,MAAM,KAAK,MAAM,aACtB,KAAK,WAAW,CAAG,GAAK,GACxB,CACF,EACA,MAAO,EAAO,CACd,MAAM,IAAI,EAAiB,uBAAwB,EAAgB,UAAW,CAC5E,KAAM,CAAE,KAAI,CACd,CAAC,GAIE,UAAU,CAAC,EAA4B,CAC5C,IAAM,EAAW,CACf,wHACA,mCACF,EAEA,QAAW,KAAW,EAAU,CAC9B,IAAM,EAAQ,EAAI,MAAM,CAAO,EAC/B,GAAI,IAAQ,GACV,OAAO,EAAM,GAIjB,OAAO,KAGF,WAAW,CAAC,EAAgC,CACjD,IAAM,EAAU,KAAK,WAAW,CAAO,GAAK,EAG5C,GAAI,CAAC,iBAAiB,KAAK,CAAO,EAChC,OAAO,KAGT,MAAO,iCAAiC,IAGnC,WAAW,CAAC,EAAgC,CACjD,IAAM,EAAU,KAAK,WAAW,CAAO,GAAK,EAG5C,GAAI,CAAC,iBAAiB,KAAK,CAAO,EAChC,OAAO,KAGT,MAAO,mCAAmC,IAE9C",
|
|
9
|
+
"debugId": "D8DC7E8F8C92550864756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ooneex/youtube",
|
|
3
|
+
"description": "A YouTube video downloader and utility library",
|
|
4
|
+
"version": "0.0.4",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"LICENSE",
|
|
9
|
+
"README.md",
|
|
10
|
+
"package.json"
|
|
11
|
+
],
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "bun test tests",
|
|
26
|
+
"build": "bunup",
|
|
27
|
+
"lint": "tsgo --noEmit && bunx biome lint",
|
|
28
|
+
"publish": "bun publish --access public || true"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@ooneex/exception": "0.0.1",
|
|
32
|
+
"@ooneex/http-status": "0.0.1",
|
|
33
|
+
"ytdlp-nodejs": "^2.3.5"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"api",
|
|
37
|
+
"bun",
|
|
38
|
+
"downloader",
|
|
39
|
+
"embed",
|
|
40
|
+
"ooneex",
|
|
41
|
+
"typescript",
|
|
42
|
+
"video",
|
|
43
|
+
"youtube",
|
|
44
|
+
"ytdlp"
|
|
45
|
+
]
|
|
46
|
+
}
|