@yt-dlx/yt 0.1.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 ADDED
@@ -0,0 +1,15 @@
1
+ # yt-kit
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.3.14. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
@@ -0,0 +1,276 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ export interface SubprocessErrorData {
4
+ stdout: string;
5
+ stderr: string;
6
+ exitCode: number;
7
+ }
8
+ export declare class SubprocessError extends Error {
9
+ readonly stdout: string;
10
+ readonly stderr: string;
11
+ readonly exitCode: number;
12
+ constructor(message: string, extraData: SubprocessErrorData, errorOptions?: ErrorOptions);
13
+ }
14
+ export interface SubprocessOptions {
15
+ allowedExitCodes?: number[] | null;
16
+ ignoreExitCode?: boolean;
17
+ cleanOutput?: boolean;
18
+ signal?: AbortSignal;
19
+ onStdout?: (data: string) => void;
20
+ onStderr?: (data: string) => void;
21
+ }
22
+ export type SubprocessResult = {
23
+ type: "success";
24
+ stdout: string;
25
+ exitCode: number;
26
+ } | {
27
+ type: "error";
28
+ error: SubprocessError;
29
+ };
30
+ export declare function asyncSubprocess(command: string, args: string[], options?: SubprocessOptions): Promise<SubprocessResult>;
31
+ export declare function cleanSubprocessOutput(rawStdout: string): string;
32
+ export interface DownloadOptions extends SubprocessOptions {
33
+ outputDir?: string;
34
+ outputTemplate?: string;
35
+ restrictFilenames?: boolean | "URL";
36
+ format?: string;
37
+ newLine?: boolean;
38
+ }
39
+ export interface DownloadResult {
40
+ filePath?: string;
41
+ rawOutput: string;
42
+ }
43
+ export interface MediaDownloader {
44
+ download: (url: string, options?: DownloadOptions) => Promise<DownloadResult>;
45
+ }
46
+ export interface VideoFormat {
47
+ id: string;
48
+ ext: string;
49
+ resolution?: string;
50
+ height?: number;
51
+ width?: number;
52
+ fps?: number;
53
+ vcodec?: string;
54
+ acodec?: string;
55
+ filesize?: number;
56
+ qualityLabel?: string;
57
+ }
58
+ export type QualityPreset = "best" | "worst" | "best-video" | "worst-video" | "best-audio" | "worst-audio" | "storyboard" | "${number}p";
59
+ export type FormatSelector = QualityPreset | (string & {});
60
+ export interface MediaInspector {
61
+ getFormats(url: string): Promise<VideoFormat[]>;
62
+ getFormat(url: string, selector: string): Promise<VideoFormat[] | null>;
63
+ }
64
+ export declare class YtDlpDownloader implements MediaDownloader, MediaInspector {
65
+ private binaryPath;
66
+ constructor(binaryPath?: string);
67
+ download(url: string, options?: DownloadOptions): Promise<DownloadResult>;
68
+ getFormats(url: string, signal?: AbortSignal): Promise<VideoFormat[]>;
69
+ getFormat(url: string, selector: FormatSelector): Promise<VideoFormat[] | null>;
70
+ }
71
+ export interface YtDLPDumpedJSON {
72
+ id: string;
73
+ title: string;
74
+ formats: Format[];
75
+ thumbnails: Thumbnail[];
76
+ thumbnail: string;
77
+ description: string;
78
+ channel_id: string;
79
+ channel_url: string;
80
+ duration: number;
81
+ view_count: number;
82
+ average_rating: null;
83
+ age_limit: number;
84
+ webpage_url: string;
85
+ categories: string[];
86
+ tags: string[];
87
+ playable_in_embed: boolean;
88
+ live_status: string;
89
+ media_type: string;
90
+ release_timestamp: null;
91
+ _format_sort_fields: string[];
92
+ automatic_captions: {
93
+ [key: string]: AutomaticCaption[];
94
+ };
95
+ subtitles: Subtitles;
96
+ comment_count: number;
97
+ chapters: null;
98
+ heatmap: Heatmap[];
99
+ like_count: number;
100
+ channel: string;
101
+ channel_follower_count: number;
102
+ creators: null;
103
+ channel_is_verified: boolean;
104
+ uploader: string;
105
+ uploader_id: string;
106
+ uploader_url: string;
107
+ upload_date: string;
108
+ timestamp: number;
109
+ availability: string;
110
+ original_url: string;
111
+ webpage_url_basename: string;
112
+ webpage_url_domain: string;
113
+ extractor: string;
114
+ extractor_key: string;
115
+ playlist: null;
116
+ playlist_index: null;
117
+ display_id: string;
118
+ fulltitle: string;
119
+ duration_string: string;
120
+ release_year: null;
121
+ is_live: boolean;
122
+ was_live: boolean;
123
+ requested_subtitles: null;
124
+ _has_drm: null;
125
+ epoch: number;
126
+ requested_downloads: RequestedDownload[];
127
+ requested_formats: Format[];
128
+ format: string;
129
+ format_id: string;
130
+ ext: AudioEXTEnum;
131
+ protocol: string;
132
+ language: string;
133
+ format_note: string;
134
+ filesize_approx: number;
135
+ tbr: number;
136
+ width: number;
137
+ height: number;
138
+ resolution: string;
139
+ fps: number;
140
+ dynamic_range: "SDR";
141
+ vcodec: string;
142
+ vbr: number;
143
+ stretched_ratio: null;
144
+ aspect_ratio: number;
145
+ acodec: Acodec;
146
+ abr: number;
147
+ asr: number;
148
+ audio_channels: number;
149
+ _type: string;
150
+ _version: Version;
151
+ }
152
+ export interface Version {
153
+ version: string;
154
+ current_git_head: null;
155
+ release_git_head: string;
156
+ repository: string;
157
+ }
158
+ export type Acodec = "none" | "mp4a.40.5" | "opus" | "mp4a.40.2";
159
+ export interface AutomaticCaption {
160
+ ext: AutomaticCaptionEXT;
161
+ url: string;
162
+ name: string;
163
+ impersonate: boolean;
164
+ __yt_dlp_client: "visionos";
165
+ }
166
+ export type AutomaticCaptionEXT = "json3" | "srv1" | "srv2" | "srv3" | "ttml" | "srt" | "vtt";
167
+ export type AudioEXTEnum = "none" | "mp4" | "m4a" | "webm" | "mhtml";
168
+ export interface Format {
169
+ format_id: string;
170
+ format_note?: string;
171
+ ext: AudioEXTEnum;
172
+ protocol: Protocol;
173
+ acodec?: Acodec;
174
+ vcodec: string;
175
+ url: string;
176
+ width?: number | null;
177
+ height?: number | null;
178
+ fps?: number | null;
179
+ rows?: number;
180
+ columns?: number;
181
+ fragments?: Fragment[];
182
+ audio_ext: AudioEXTEnum;
183
+ video_ext: AudioEXTEnum;
184
+ vbr: number;
185
+ abr: number | null;
186
+ tbr: number | null;
187
+ resolution: string;
188
+ aspect_ratio: number | null;
189
+ filesize_approx?: number | null;
190
+ http_headers: HTTPHeaders;
191
+ format: string;
192
+ format_index?: null;
193
+ manifest_url?: string;
194
+ language?: null | string;
195
+ preference?: null;
196
+ quality?: number;
197
+ has_drm?: boolean;
198
+ source_preference?: number;
199
+ available_at?: number;
200
+ asr?: number | null;
201
+ filesize?: number;
202
+ audio_channels?: number | null;
203
+ language_preference?: number;
204
+ dynamic_range?: "SDR" | null;
205
+ container?: Container;
206
+ downloader_options?: DownloaderOptions;
207
+ }
208
+ export type Container = "m4a_dash" | "webm_dash" | "mp4_dash";
209
+ export interface DownloaderOptions {
210
+ http_chunk_size: number;
211
+ }
212
+ export interface Fragment {
213
+ url: string;
214
+ duration: number;
215
+ }
216
+ export interface HTTPHeaders {
217
+ "User-Agent": string;
218
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
219
+ "Accept-Language": "en-us,en;q=0.5";
220
+ "Sec-Fetch-Mode": "navigate";
221
+ }
222
+ export type Protocol = "mhtml" | "m3u8_native" | "https";
223
+ export interface Heatmap {
224
+ start_time: number;
225
+ end_time: number;
226
+ value: number;
227
+ }
228
+ export interface RequestedDownload {
229
+ requested_formats: Format[];
230
+ format: string;
231
+ format_id: string;
232
+ ext: AudioEXTEnum;
233
+ protocol: string;
234
+ language: string;
235
+ format_note: string;
236
+ filesize_approx: number;
237
+ tbr: number;
238
+ width: number;
239
+ height: number;
240
+ resolution: string;
241
+ fps: number;
242
+ dynamic_range: "SDR";
243
+ vcodec: string;
244
+ vbr: number;
245
+ aspect_ratio: number;
246
+ acodec: Acodec;
247
+ abr: number;
248
+ asr: number;
249
+ audio_channels: number;
250
+ _filename: string;
251
+ filename: string;
252
+ __write_download_archive: boolean;
253
+ }
254
+ export type Subtitles = unknown;
255
+ export interface Thumbnail {
256
+ url: string;
257
+ preference: number;
258
+ id: string;
259
+ height?: number;
260
+ width?: number;
261
+ resolution?: string;
262
+ }
263
+ export type YtEngineConfig = {
264
+ adapter: MediaInspector & MediaDownloader;
265
+ } | {
266
+ inspector: MediaInspector;
267
+ downloader: MediaDownloader;
268
+ };
269
+ export declare class YtEngine {
270
+ private readonly inspector;
271
+ private readonly downloader;
272
+ constructor(config: YtEngineConfig);
273
+ download(url: string, selector: FormatSelector, options: Omit<DownloadOptions, "format">): Promise<DownloadResult | null>;
274
+ }
275
+
276
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import{spawn as x}from"node:child_process";class d extends Error{stdout;stderr;exitCode;constructor(r,t,e){super(r,e);if(this.name="SubprocessError",this.stdout=t.stdout,this.stderr=t.stderr,this.exitCode=t.exitCode,Error.captureStackTrace)Error.captureStackTrace(this,d)}}var O={allowedExitCodes:[0],ignoreExitCode:!1};async function p(r,t,e){let{allowedExitCodes:s,ignoreExitCode:o,cleanOutput:n,signal:f}={...O,...e};return new Promise((m,b)=>{let u=x(r,t,{signal:f}),w=[],y=[];u.stdout.on("data",(i)=>{w.push(i),e?.onStdout?.(i.toString("utf-8"))}),u.stderr.on("data",(i)=>{y.push(i),e?.onStderr?.(i.toString("utf-8"))}),u.on("close",(i)=>{let a=i??0,l=Buffer.concat(w).toString("utf-8"),c=Buffer.concat(y).toString("utf-8");if(n)l=h(l),c=h(c);if(o||s?.includes(a))m({type:"success",stdout:l,exitCode:a});else{let D=new d(`El proceso "${r}" finalizó con código ${a}.
2
+ Stderr: ${c}`,{stdout:l,stderr:c,exitCode:a});m({type:"error",error:D})}}),u.on("error",(i)=>{if(i.name==="AbortError"){let a=new d("Proceso cancelado por el usuario",{stdout:"",stderr:"Aborted",exitCode:-1});return m({type:"error",error:a})}b(i)})})}function h(r){return r.split(`
3
+ `).map((t)=>{if(t.includes("\r")){let e=t.split("\r").filter(Boolean);return e[e.length-1]??""}return t}).filter((t)=>t.trim().length>0).join(`
4
+ `)}class g{binaryPath;constructor(r="yt-dlp"){this.binaryPath=r}async download(r,t){let e=[];if(t?.outputDir)e.push("-P",t.outputDir);if(t?.format)e.push("-f",t.format);if(t?.outputTemplate)e.push("-o",t.outputTemplate);if(t?.restrictFilenames){if(e.push("--restrict-filenames"),t.restrictFilenames==="URL")e.push("--restrict-filenames","URL")}if(t?.newLine)e.push("--newline");e.push(r);let s=await p(this.binaryPath,e,{cleanOutput:t?.cleanOutput,signal:t?.signal,onStdout:t?.onStdout,onStderr:t?.onStderr});if(s.type==="error")throw s.error;return{filePath:void 0,rawOutput:s.stdout}}async getFormats(r,t){let e=await p(this.binaryPath,["-J",r],{signal:t});if(e.type==="error")throw e.error;let s=JSON.parse(e.stdout),o=[];for(let n of s.formats){let f={id:n.format_id,ext:n.ext,resolution:n.resolution,height:n.height??void 0,width:n.width??void 0,fps:n.fps??void 0,vcodec:n.vcodec,acodec:n.acodec,filesize:n.filesize??n.filesize_approx??void 0,qualityLabel:n.format_note};o.push(f)}return o}async getFormat(r,t){let e=await this.getFormats(r);if(!e.length)return null;if(t.includes("video"))e=e.filter((o)=>o.vcodec&&o.vcodec!=="none");if(t.includes("audio"))e=e.filter((o)=>o.acodec&&o.acodec!=="none");if(t.includes("best"))return[e[e.length-1]];if(t.includes("worst"))return[e[0]];let s=e.filter((o)=>o.qualityLabel===t||o.id===t||o.resolution===t);return s.length?s:null}}class S{inspector;downloader;constructor(r){if("adapter"in r)this.inspector=r.adapter,this.downloader=r.adapter;else this.inspector=r.inspector,this.downloader=r.downloader}async download(r,t,e){let s=await this.inspector.getFormat(r,t);if(!s)return null;let o=s[s.length-1];return await this.downloader.download(r,{format:o.id,...e})}}export{h as cleanSubprocessOutput,p as asyncSubprocess,S as YtEngine,g as YtDlpDownloader,d as SubprocessError};
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@yt-dlx/yt",
3
+ "description": "YouTube Media Extractor & Downloader",
4
+ "version": "0.1.0",
5
+ "module": "entry.ts",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.js",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "scripts": {
19
+ "start": "bun index.ts",
20
+ "dev": "bun --watch index.ts",
21
+ "build": "bun build.ts && dts-bundle-generator --no-check -o dist/index.d.ts src/index.ts",
22
+ "prepublishOnly": "bun run build"
23
+ },
24
+ "devDependencies": {
25
+ "@eslint/js": "10.0.1",
26
+ "@stylistic/eslint-plugin": "5.10.0",
27
+ "@types/bun": "latest",
28
+ "eslint": "10.11.0",
29
+ "globals": "17.12.0",
30
+ "jiti": "2.7.0",
31
+ "typescript-eslint": "8.71.0",
32
+ "typescript": "5",
33
+ "dts-bundle-generator": "9.5.1"
34
+ },
35
+ "files": [
36
+ "dist"
37
+ ]
38
+ }