@ooneex/youtube 0.0.18 → 1.0.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 CHANGED
@@ -1 +1,55 @@
1
1
  # @ooneex/youtube
2
+
3
+ YouTube video downloader and metadata extraction library for fetching video information, thumbnails, and media streams.
4
+
5
+ ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
6
+ ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
7
+ ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
8
+
9
+ ## Features
10
+
11
+ ✅ **Video ID Extraction** - Parse video IDs from watch URLs, short URLs, embed URLs, and other YouTube URL formats
12
+
13
+ ✅ **Embed URL Generation** - Convert any YouTube URL or video ID into an embeddable URL via `getEmbedUrl`
14
+
15
+ ✅ **Watch URL Generation** - Convert any YouTube URL or video ID into a standard watch URL via `getWatchUrl`
16
+
17
+ ✅ **ytdlp Integration** - Type definitions for ytdlp-nodejs including video/audio quality, format options, and download progress
18
+
19
+ ✅ **Quality Types** - `YoutubeVideoQualityType` (144p to 2160p) and `YoutubeAudioQualityType` for stream selection
20
+
21
+ ✅ **Error Handling** - Custom `YoutubeException` for YouTube-specific error scenarios
22
+
23
+ ✅ **Type-Safe** - Full TypeScript support with `IYoutube` interface and re-exported ytdlp types
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ bun add @ooneex/youtube
29
+ ```
30
+
31
+ ## License
32
+
33
+ This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
34
+
35
+ ## Contributing
36
+
37
+ Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
38
+
39
+ ### Development Setup
40
+
41
+ 1. Clone the repository
42
+ 2. Install dependencies: `bun install`
43
+ 3. Run tests: `bun run test`
44
+ 4. Build the project: `bun run build`
45
+
46
+ ### Guidelines
47
+
48
+ - Write tests for new features
49
+ - Follow the existing code style
50
+ - Update documentation for API changes
51
+ - Ensure all tests pass before submitting PR
52
+
53
+ ---
54
+
55
+ Made with ❤️ by the Ooneex team
package/dist/index.d.ts CHANGED
@@ -1,433 +1,18 @@
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
- */
1
+ import { ArgsOptions, FormatOptions, QualityOptions, VideoFormat, VideoProgress } from "ytdlp-nodejs";
34
2
  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
3
  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
4
  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
5
  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
6
  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
7
  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
8
  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
9
  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
10
  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
11
  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
12
  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
13
  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
14
  }
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
15
  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
16
  getWatchId(url: string): string | null;
432
17
  getEmbedUrl(urlOrId: string): string | null;
433
18
  getWatchUrl(urlOrId: string): string | null;
@@ -436,4 +21,4 @@ import { Exception } from "@ooneex/exception";
436
21
  declare class YoutubeException extends Exception {
437
22
  constructor(message: string, data?: Record<string, unknown>);
438
23
  }
439
- export { YoutubeVideoQualityType, YoutubeVideoProgressType, YoutubeVideoInfoType, YoutubeVideoFormatType, YoutubeQualityOptionsType, YoutubePlaylistInfoType, YoutubeOptionsType, YoutubeFormatOptionsType, YoutubeFormatKeyWordType, YoutubeException, YoutubeAudioQualityType, YoutubeArgsOptionsType, Youtube, IYoutube };
24
+ export { YoutubeVideoQualityType, YoutubeVideoProgressType, YoutubeVideoFormatType, YoutubeQualityOptionsType, YoutubeFormatOptionsType, YoutubeFormatKeyWordType, YoutubeException, YoutubeAudioQualityType, YoutubeArgsOptionsType, Youtube, IYoutube };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
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};
2
+ class u{getWatchId(t){let e=[/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/watch\?.*&v=)([^&\n?#]+)/,/youtube\.com\/shorts\/([^&\n?#]+)/];for(let r of e){let o=t.match(r);if(o?.[1])return o[1]}return null}getEmbedUrl(t){let e=this.getWatchId(t)??t;if(!/^[\w-]{10,12}$/.test(e))return null;return`https://www.youtube.com/embed/${e}`}getWatchUrl(t){let e=this.getWatchId(t)??t;if(!/^[\w-]{10,12}$/.test(e))return null;return`https://www.youtube.com/watch?v=${e}`}}import{Exception as p}from"@ooneex/exception";import{HttpStatus as s}from"@ooneex/http-status";class n extends p{constructor(t,e={}){super(t,{status:s.Code.InternalServerError,data:e});this.name="YoutubeException"}}export{n as YoutubeException,u as Youtube};
3
3
 
4
- //# debugId=D8DC7E8F8C92550864756E2164756E21
4
+ //# debugId=E2B22519AFE2B76E64756E2164756E21
package/dist/index.js.map CHANGED
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["src/Youtube.ts", "src/YoutubeException.ts"],
4
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",
5
+ "import type { IYoutube } from \"./types\";\n\nexport class Youtube implements IYoutube {\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 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 if (!/^[\\w-]{10,12}$/.test(videoId)) {\n return null;\n }\n\n return `https://www.youtube.com/watch?v=${videoId}`;\n }\n}\n",
6
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
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",
8
+ "mappings": ";AAEO,MAAM,CAA4B,CAChC,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,EAE5C,GAAI,CAAC,iBAAiB,KAAK,CAAO,EAChC,OAAO,KAGT,MAAO,iCAAiC,IAGnC,WAAW,CAAC,EAAgC,CACjD,IAAM,EAAU,KAAK,WAAW,CAAO,GAAK,EAE5C,GAAI,CAAC,iBAAiB,KAAK,CAAO,EAChC,OAAO,KAGT,MAAO,mCAAmC,IAE9C,CCtCA,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",
9
+ "debugId": "E2B22519AFE2B76E64756E2164756E21",
10
10
  "names": []
11
11
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ooneex/youtube",
3
- "description": "A YouTube video downloader and utility library",
4
- "version": "0.0.18",
3
+ "description": "YouTube video downloader and metadata extraction library for fetching video information, thumbnails, and media streams",
4
+ "version": "1.0.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -28,8 +28,8 @@
28
28
  "npm:publish": "bun publish --tolerate-republish --access public"
29
29
  },
30
30
  "dependencies": {
31
- "@ooneex/exception": "0.0.17",
32
- "@ooneex/http-status": "0.0.17",
31
+ "@ooneex/exception": "0.0.18",
32
+ "@ooneex/http-status": "0.0.18",
33
33
  "ytdlp-nodejs": "^2.3.5"
34
34
  },
35
35
  "keywords": [