@yt-kit/core 0.5.1 → 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/README.md +0 -6
- package/dist/cache/CacheManager.d.ts +9 -0
- package/dist/cache/getFromDisk.d.ts +2 -0
- package/dist/cache/removeFromDisk.d.ts +2 -0
- package/dist/cache/saveInDisk.d.ts +2 -0
- package/dist/config/Configuration.d.ts +8 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.js +1 -10
- package/dist/lib/compareFormats.d.ts +5 -6
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/{resolveFilename.d.ts → resolveFilenamePattern.d.ts} +1 -1
- package/dist/lib/resolvePath.d.ts +1 -0
- package/dist/lib/timeUtils.d.ts +17 -0
- package/dist/types/cacheTypes.d.ts +13 -0
- package/dist/types/configTypes.d.ts +6 -0
- package/dist/validations/cache.d.ts +2 -0
- package/dist/yt-dlp/findFormatId.d.ts +1 -1
- package/package.json +2 -2
- package/dist/interfaces/Downloader.js +0 -1
- package/dist/lib/compareFormats.js +0 -52
- package/dist/lib/constants.js +0 -9
- package/dist/lib/expandPattern.js +0 -7
- package/dist/lib/logger.js +0 -8
- package/dist/lib/resolveFilename.js +0 -11
- package/dist/lib/sanitizeFilename.js +0 -6
- package/dist/lib/spawnAsync.js +0 -34
- package/dist/lib/ytUtils.js +0 -4
- package/dist/tasks/download/download.js +0 -28
- package/dist/types/childProcessTypes.js +0 -1
- package/dist/types/downloaderTaskTypes.js +0 -1
- package/dist/types/videoTypes.js +0 -1
- package/dist/types/ytDlpFormatTypes.js +0 -1
- package/dist/yt-dlp/findFormatId.js +0 -61
- package/dist/yt-dlp-downloader/YtDlpDownloader.js +0 -31
package/README.md
CHANGED
|
@@ -14,9 +14,3 @@ pnpm add -E @yt-kit/core
|
|
|
14
14
|
# Con bun
|
|
15
15
|
bun add -E @yt-kit/core
|
|
16
16
|
```
|
|
17
|
-
|
|
18
|
-
## Sobre la estructura de carpetas
|
|
19
|
-
|
|
20
|
-
El archivo `pruebas.ts` es un archivo para probar el funcionamiento del proyecto antes de lanzar una nueva versión.
|
|
21
|
-
|
|
22
|
-
`src/index.ts` es el archivo principal para las builds, no para desarrollo. En todo caso, el archivo "principal" sería `pruebas.ts`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CachedData, CacheKey, ValueToCache } from '../types/cacheTypes';
|
|
2
|
+
export declare class CacheManager {
|
|
3
|
+
private store;
|
|
4
|
+
private defaultTtl;
|
|
5
|
+
get(key: CacheKey, json?: boolean): Promise<CachedData | null>;
|
|
6
|
+
set(key: CacheKey, value: ValueToCache): Promise<void>;
|
|
7
|
+
delete(key: string): void;
|
|
8
|
+
}
|
|
9
|
+
export declare const cache: CacheManager;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ConfigKey, ConfigValue } from '../types/configTypes';
|
|
2
|
+
export declare class Configuration {
|
|
3
|
+
private store;
|
|
4
|
+
get<K extends ConfigKey>(key: K): ConfigValue<K> | null;
|
|
5
|
+
set<K extends ConfigKey>(key: K, value: ConfigValue<K>): void;
|
|
6
|
+
delete<K extends ConfigKey>(key: K): void;
|
|
7
|
+
}
|
|
8
|
+
export declare const config: Configuration;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
export { CacheManager } from './cache/CacheManager';
|
|
2
|
+
export { Configuration } from './config/Configuration';
|
|
1
3
|
export { downloadAudio, downloadVideo } from './tasks/download/download';
|
|
2
4
|
export { findFormatId } from './yt-dlp/findFormatId';
|
|
5
|
+
export { getFromDisk } from './cache/getFromDisk';
|
|
6
|
+
export { saveInDisk } from './cache/saveInDisk';
|
|
3
7
|
export { formYoutubeUrl } from './lib/ytUtils';
|
|
4
|
-
export
|
|
5
|
-
export
|
|
8
|
+
export { getBetterFormat, getWorstFormat } from './lib/compareFormats';
|
|
9
|
+
export { resolveFilenamePattern } from './lib/resolveFilenamePattern';
|
|
10
|
+
export { expandPattern } from './lib/expandPattern';
|
|
11
|
+
export { resolvePath } from './lib/resolvePath';
|
|
12
|
+
export type * from './types/videoTypes';
|
|
13
|
+
export type * from './types/childProcessTypes';
|
|
14
|
+
export type * from './types/configTypes';
|
|
15
|
+
export type * from './types/cacheTypes';
|
|
16
|
+
export type { Pattern, PatternData } from './lib/expandPattern';
|
|
6
17
|
export { STANDARD_RESOLUTIONS } from './lib/constants';
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { downloadAudio, downloadVideo } from './tasks/download/download';
|
|
3
|
-
export { findFormatId } from './yt-dlp/findFormatId';
|
|
4
|
-
// Utilidades
|
|
5
|
-
export { formYoutubeUrl } from './lib/ytUtils';
|
|
6
|
-
// Tipos
|
|
7
|
-
export * from './types/videoTypes';
|
|
8
|
-
export * from './types/childProcessTypes';
|
|
9
|
-
// Constantes públicas (seguras de exportar)
|
|
10
|
-
export { STANDARD_RESOLUTIONS } from './lib/constants';
|
|
1
|
+
class A{store=new Map;get(t){let e=this.store.get(t);if(!e)return null;return e}set(t,e){this.store.set(t,e)}delete(t){this.store.delete(t)}}var l=new A;var V={day:86400000,hrs:3600000,min:60000,sec:1000,nano:0.001};function _(t,e){if(!V[e])return t;return t*V[e]}function Y(t){if(typeof t!=="string")return!1;return!0}import{readFile as W}from"node:fs/promises";import{homedir as J}from"node:os";function c(t){return t.replace("~",J())}async function h(t,e=!1){let r=l.get("cache")?.cacheLocation;if(!r)return;let o=c(r),s;try{s=await W(o,"utf8")}catch(a){console.error(`Error leyendo la caché en el almacenamiento para ${t} :`,a)}if(e&&s)try{s=JSON.parse(s)}catch(a){console.error(`Error convirtiendo la caché de ${t} a JSON:`,a)}if(!s)return;return{content:e?s.content:s,timestamp:Date.now()}}import{rm as L}from"node:fs/promises";async function q(t){let e=l.get("cache")?.cacheLocation;if(!e)return;let r=c(e);try{await L(r)}catch(o){console.error(`Error borrando la caché de ${t} en el almacenamiento:`,o)}}import{mkdir as Q,writeFile as G}from"node:fs/promises";import{dirname as H}from"node:path";async function C(t,e){let r=l.get("cache")?.cacheLocation;if(!r)return;let o=c(r),s=H(o);try{Q(s,{recursive:!0}),await G(o,JSON.stringify(e),"utf8")}catch(a){console.error(`Error cacheando ${t} en el almacenamiento:`,a)}}class E{store=new Map;defaultTtl=_(10,"day");async get(t,e=!1){if(!Y(t))throw Error("CacheKey inválida",{cause:t});let r=l.get("cache")?.method??"memory",o=null;if(r==="memory")o=this.store.get(t);if(r==="disk")o=await h(t,e);if(r==="hybrid"){if(o=this.store.get(t),!o)o=await h(t)}if(!o)return null;if(Date.now()-o.timestamp>this.defaultTtl){if(r!=="disk")this.delete(t);if(r==="disk")q(t);return null}return o}async set(t,e){if(!Y(t))throw Error("CacheKey inválida",{cause:t});let r=l.get("cache")?.method??"memory",o={...e,timestamp:Date.now()};if(r==="memory")this.store.set(t,o);if(r==="disk")await C(t,o);if(r==="hybrid")this.store.set(t,o),await C(t,o)}delete(t){this.store.delete(t)}}var T=new E;var X=[18,144,240,360,480,720,1080,1440,2160],v={"yt-dlp":"yt-dlp"},U="%(ytId)s.%(ext)s",M={ID:"%(id)s",YT_ID:"%(ytId)s"};function d(t){return`https://youtube.com/watch?v=${t}`}import{spawn as I}from"node:child_process";import{stdout as Z,stderr as j}from"node:process";function O(t,e){(t==="data"?Z:j).write(e)}function D(t,e,r){let o=v[t];return new Promise((s,a)=>{let p=I(o,e),u="",m="";p.stdout.on("data",(i)=>{u+=i;let f=i.toString();if(r)O("data",f)}),p.stderr.on("data",(i)=>{m+=i;let f=i.toString();if(r)O("err",f)}),p.on("close",(i)=>{if(i===0)s(u.toString());else a(Error(m.toString()))}),p.on("error",(i)=>{a(i)})})}function N(t,e){let r=t;for(let[o,s]of e)r=r.replaceAll(o,s);return r}function B(t){return t.replaceAll("/","⁄")}function P({filename:t,id:e,ytId:r}){let o=new Map([[M.ID,e],[M.YT_ID,r]]),s=N(t,o);return B(s)}class S{async download(t,e,r){let o=this.buildYtDlpArgs(t,e,r);return await D("yt-dlp",o,!0),{duration:-1,path:"unknown"}}buildYtDlpArgs(t,e,r){let{id:o,type:s}=r,a=s==="video",p=r.outputPath,u=P({filename:r.filename,id:r.id,ytId:e}),m="aac";return["-f",o,...a?[]:["-x","--audio-format","aac"],"-o",u,"-P",p,t]}}async function b(t,e){if(!t||!e.id)return;let r=d(t),o=$("video",e);return new S().download(r,t,o)}async function k(t,e){if(!t||!e.id)return;let r=d(t),o=$("audio",e);return new S().download(r,t,o)}function $(t,e){return{id:e.id,type:t,outputPath:e.outputPath??".",filename:e.filename??U}}function z({a:t,b:e,compareResolution:r,type:o}){let s=o==="video"&&r&&t.quality!==null&&e.quality!==null,a=o==="video"&&r&&t.height!==null&&e.height!==null,p=o==="video"&&t.fps!==null&&e.fps!==null,u=o==="audio"&&t.asr!==null&&e.asr!==null,m=t.tbr!==null&&e.tbr!==null,i=0,f=0;if(s){if((t.quality??0)>(e.quality??0))i+=3;else if((t.quality??0)<(e.quality??0))f+=3}if(a){if((t.height??0)>(e.height??0))i+=3;else if((t.height??0)<(e.height??0))f+=3}if(p){if((t.fps??0)>(e.fps??0))i+=2;else if((t.fps??0)<(e.fps??0))f+=2}if(u){if((t.asr??0)>(e.asr??0))i+=2;else if((t.asr??0)<(e.asr??0))f+=2}if(m){if((t.tbr??0)>(e.tbr??0))i+=1;else if((t.tbr??0)<(e.tbr??0))f+=1}return{aScore:i,bScore:f}}function g(t,e,{type:r,compareResolution:o}){if(!t||!e)return;let{aScore:s,bScore:a}=z({a:t,b:e,type:r,compareResolution:o});return s>a?t:e}function x(t,e,{type:r,compareResolution:o}){if(!t||!e)return;let{aScore:s,bScore:a}=z({a:t,b:e,type:r,compareResolution:o});return s>a?e:t}async function tt(t,e){let r=d(t),o=`formats-${t}`,s=Boolean(e.match(/\d/)),a=s?!1:"N/A",p=["--print","%(formats)j",r],m=(await T.get(o))?.content??"";if(!m){let n;try{n=await D("yt-dlp",p)}catch(R){throw console.error("Error consiguiendo el ID del formato"),R}if(typeof n!=="string")throw Error("La salida del proceso es de tipo inválido (se esperaba string)");m=n,T.set(o,{content:m})}let i=[];try{i=JSON.parse(m)}catch(n){throw console.error("Error convirtiendo la salida de yt-dlp a JSON"),n}if(!Array.isArray(i))throw Error("Se esperaba un array");let f=void 0,K=void 0,w=void 0,F=void 0,y=void 0;for(let n of i){let R=n.resolution==="audio only";if(s&&n.format_note===e){a=!0,y=g(y,n,{compareResolution:!1,type:"video"})??n;continue}if(R)w=g(w,n,{compareResolution:!1,type:"audio"})??n,F=x(F,n,{compareResolution:!1,type:"audio"})??n;else f=g(f,n,{compareResolution:!0,type:"video"})??n,K=x(K,n,{compareResolution:!0,type:"video"})??n}if(!s)y={"best-video":f,"worst-video":K,"best-audio":w,"worst-audio":F}[e];return{foundSpecific:a,formatId:y?.format_id,desiredFormat:y}}export{C as saveInDisk,c as resolvePath,P as resolveFilenamePattern,x as getWorstFormat,h as getFromDisk,g as getBetterFormat,d as formYoutubeUrl,tt as findFormatId,N as expandPattern,b as downloadVideo,k as downloadAudio,X as STANDARD_RESOLUTIONS,A as Configuration,E as CacheManager};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { MediaType } from '../types/videoTypes';
|
|
2
2
|
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
3
|
-
|
|
3
|
+
interface CompareOptions {
|
|
4
4
|
type: MediaType;
|
|
5
5
|
compareResolution: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}): YtDlpFormat | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function getBetterFormat(a: YtDlpFormat | undefined, b: YtDlpFormat | undefined, { type, compareResolution }: CompareOptions): YtDlpFormat | undefined;
|
|
8
|
+
export declare function getWorstFormat(a: YtDlpFormat | undefined, b: YtDlpFormat | undefined, { type, compareResolution }: CompareOptions): YtDlpFormat | undefined;
|
|
9
|
+
export {};
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const STANDARD_RESOLUTIONS: readonly [18, 144, 240, 360, 480, 720, 1080, 1440, 2160];
|
|
2
2
|
export declare const COMMANDS: {
|
|
3
|
-
readonly 'yt-dlp': "yt-dlp
|
|
3
|
+
readonly 'yt-dlp': "yt-dlp";
|
|
4
4
|
};
|
|
5
5
|
export declare const DEFAULT_FILENAME = "%(ytId)s.%(ext)s";
|
|
6
6
|
export declare const PATTERNS: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolvePath(path: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type TimeUnit = 'day' | 'hrs' | 'min' | 'sec' | 'nano';
|
|
2
|
+
type Miliseconds = number;
|
|
3
|
+
/**
|
|
4
|
+
* Recibe una cantidad `amount` y una unidad `unit`, y devuelve esa cantidad en milisegundos.
|
|
5
|
+
*
|
|
6
|
+
* Si la unidad no es válida, devuelve la cantidad sin convertir.
|
|
7
|
+
*
|
|
8
|
+
* ```js
|
|
9
|
+
* convertTime(10, 'day') // 864000000ms
|
|
10
|
+
* convertTime(4, 'lemon') // 4ms
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @returns Devuelve en milisegundos la cantidad de unidad especificada
|
|
14
|
+
*/
|
|
15
|
+
export declare function timeToMs(amount: number, unit: TimeUnit): Miliseconds;
|
|
16
|
+
export declare function msToTime(ms: number, unit: TimeUnit): number;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type CacheKey = 'formats:' | (string & {});
|
|
2
|
+
export interface CachedData {
|
|
3
|
+
content: string;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ValueToCache {
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CacheConfig {
|
|
10
|
+
method: CacheMethod;
|
|
11
|
+
cacheLocation?: string;
|
|
12
|
+
}
|
|
13
|
+
export type CacheMethod = 'memory' | 'disk' | 'hybrid';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FormatsToFind } from '../types/videoTypes';
|
|
2
2
|
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
3
|
-
export declare function findFormatId(
|
|
3
|
+
export declare function findFormatId(ytId: string, formatToFind: FormatsToFind): Promise<{
|
|
4
4
|
foundSpecific: string | boolean;
|
|
5
5
|
formatId: string | undefined;
|
|
6
6
|
desiredFormat: YtDlpFormat | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yt-kit/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"homepage": "https://github.com/ubiufboeuf/yt-kit#readme",
|
|
22
22
|
"scripts": {
|
|
23
23
|
"start": "bun pruebas.ts",
|
|
24
|
-
"build": "tsc -p tsconfig.build.json",
|
|
24
|
+
"build": "bun build.ts && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
25
25
|
"prepublishOnly": "bun run build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
function compareFormats({ a, b, compareResolution, type }) {
|
|
2
|
-
const canCompareQuality = (type === 'video') && compareResolution && (a.quality !== null) && (b.quality !== null);
|
|
3
|
-
const canCompareResolution = (type === 'video') && compareResolution && (a.height !== null) && (b.height !== null);
|
|
4
|
-
const canCompareFps = (type === 'video') && (a.fps !== null) && (b.fps !== null);
|
|
5
|
-
const canCompareAsr = (type === 'audio') && (a.asr !== null) && (b.asr !== null);
|
|
6
|
-
const canCompareTbr = (a.tbr !== null) && (b.tbr !== null);
|
|
7
|
-
let aScore = 0;
|
|
8
|
-
let bScore = 0;
|
|
9
|
-
if (canCompareQuality) {
|
|
10
|
-
if ((a.quality ?? 0) > (b.quality ?? 0))
|
|
11
|
-
aScore += 3;
|
|
12
|
-
else if ((a.quality ?? 0) < (b.quality ?? 0))
|
|
13
|
-
bScore += 3;
|
|
14
|
-
}
|
|
15
|
-
if (canCompareResolution) {
|
|
16
|
-
if ((a.height ?? 0) > (b.height ?? 0))
|
|
17
|
-
aScore += 3;
|
|
18
|
-
else if ((a.height ?? 0) < (b.height ?? 0))
|
|
19
|
-
bScore += 3;
|
|
20
|
-
}
|
|
21
|
-
if (canCompareFps) {
|
|
22
|
-
if ((a.fps ?? 0) > (b.fps ?? 0))
|
|
23
|
-
aScore += 2;
|
|
24
|
-
else if ((a.fps ?? 0) < (b.fps ?? 0))
|
|
25
|
-
bScore += 2;
|
|
26
|
-
}
|
|
27
|
-
if (canCompareAsr) {
|
|
28
|
-
if ((a.asr ?? 0) > (b.asr ?? 0))
|
|
29
|
-
aScore += 2;
|
|
30
|
-
else if ((a.asr ?? 0) < (b.asr ?? 0))
|
|
31
|
-
bScore += 2;
|
|
32
|
-
}
|
|
33
|
-
if (canCompareTbr) {
|
|
34
|
-
if ((a.tbr ?? 0) > (b.tbr ?? 0))
|
|
35
|
-
aScore += 1;
|
|
36
|
-
else if ((a.tbr ?? 0) < (b.tbr ?? 0))
|
|
37
|
-
bScore += 1;
|
|
38
|
-
}
|
|
39
|
-
return { aScore, bScore };
|
|
40
|
-
}
|
|
41
|
-
export function getBetterFormat(a, b, { type, compareResolution }) {
|
|
42
|
-
if (!a || !b)
|
|
43
|
-
return;
|
|
44
|
-
const { aScore, bScore } = compareFormats({ a, b, type, compareResolution });
|
|
45
|
-
return aScore > bScore ? a : b;
|
|
46
|
-
}
|
|
47
|
-
export function getWorstFormat(a, b, { type, compareResolution }) {
|
|
48
|
-
if (!a || !b)
|
|
49
|
-
return;
|
|
50
|
-
const { aScore, bScore } = compareFormats({ a, b, type, compareResolution });
|
|
51
|
-
return aScore > bScore ? b : a;
|
|
52
|
-
}
|
package/dist/lib/constants.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export const STANDARD_RESOLUTIONS = [18, 144, 240, 360, 480, 720, 1080, 1440, 2160];
|
|
2
|
-
export const COMMANDS = {
|
|
3
|
-
'yt-dlp': 'yt-dlp-linux'
|
|
4
|
-
};
|
|
5
|
-
export const DEFAULT_FILENAME = '%(ytId)s.%(ext)s';
|
|
6
|
-
export const PATTERNS = {
|
|
7
|
-
ID: '%(id)s',
|
|
8
|
-
YT_ID: '%(ytId)s'
|
|
9
|
-
};
|
package/dist/lib/logger.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { PATTERNS } from './constants';
|
|
2
|
-
import { expandPattern } from './expandPattern';
|
|
3
|
-
import { sanitizeFilename } from './sanitizeFilename';
|
|
4
|
-
export function resolveFilename({ filename, id, ytId }) {
|
|
5
|
-
const map = new Map([
|
|
6
|
-
[PATTERNS.ID, id],
|
|
7
|
-
[PATTERNS.YT_ID, ytId]
|
|
8
|
-
]);
|
|
9
|
-
const raw = expandPattern(filename, map);
|
|
10
|
-
return sanitizeFilename(raw);
|
|
11
|
-
}
|
package/dist/lib/spawnAsync.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { COMMANDS } from '../lib/constants';
|
|
3
|
-
import { streamLog } from './logger';
|
|
4
|
-
export function spawnAsync(command, args, showOutput) {
|
|
5
|
-
const _command = COMMANDS[command];
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
const spawnProcess = spawn(_command, args);
|
|
8
|
-
let stdout = '';
|
|
9
|
-
let stderr = '';
|
|
10
|
-
spawnProcess.stdout.on('data', (chunk) => {
|
|
11
|
-
stdout += chunk;
|
|
12
|
-
const chunkStr = chunk.toString();
|
|
13
|
-
if (showOutput)
|
|
14
|
-
streamLog('data', chunkStr);
|
|
15
|
-
});
|
|
16
|
-
spawnProcess.stderr.on('data', (chunk) => {
|
|
17
|
-
stderr += chunk;
|
|
18
|
-
const chunkStr = chunk.toString();
|
|
19
|
-
if (showOutput)
|
|
20
|
-
streamLog('err', chunkStr);
|
|
21
|
-
});
|
|
22
|
-
spawnProcess.on('close', (code) => {
|
|
23
|
-
if (code === 0) {
|
|
24
|
-
resolve(stdout.toString());
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
reject(new Error(stderr.toString()));
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
spawnProcess.on('error', (err) => {
|
|
31
|
-
reject(err);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
}
|
package/dist/lib/ytUtils.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// import { spawnAsync } from 'src/core/lib/spawnAsync'
|
|
2
|
-
// import type { DownloadOptions } from './interfaces/Downloader'
|
|
3
|
-
import { DEFAULT_FILENAME } from '../../lib/constants';
|
|
4
|
-
import { formYoutubeUrl } from '../../lib/ytUtils';
|
|
5
|
-
import { YtDlpDownloader } from '../../yt-dlp-downloader/YtDlpDownloader';
|
|
6
|
-
export async function downloadVideo(ytId, options) {
|
|
7
|
-
if (!ytId || !options.id)
|
|
8
|
-
return;
|
|
9
|
-
const url = formYoutubeUrl(ytId);
|
|
10
|
-
const taskOptions = formDownloadTaskOptions('video', options);
|
|
11
|
-
return new YtDlpDownloader().download(url, ytId, taskOptions);
|
|
12
|
-
}
|
|
13
|
-
export async function downloadAudio(ytId, options) {
|
|
14
|
-
if (!ytId || !options.id)
|
|
15
|
-
return;
|
|
16
|
-
const url = formYoutubeUrl(ytId);
|
|
17
|
-
const taskOptions = formDownloadTaskOptions('audio', options);
|
|
18
|
-
return new YtDlpDownloader().download(url, ytId, taskOptions);
|
|
19
|
-
}
|
|
20
|
-
function formDownloadTaskOptions(type, options) {
|
|
21
|
-
const taskOptions = {
|
|
22
|
-
id: options.id,
|
|
23
|
-
type,
|
|
24
|
-
outputPath: options.outputPath ?? '.',
|
|
25
|
-
filename: options.filename ?? DEFAULT_FILENAME
|
|
26
|
-
};
|
|
27
|
-
return taskOptions;
|
|
28
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/types/videoTypes.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { getBetterFormat, getWorstFormat } from '../lib/compareFormats';
|
|
2
|
-
import { spawnAsync } from '../lib/spawnAsync';
|
|
3
|
-
export async function findFormatId(url, formatToFind) {
|
|
4
|
-
const isSpecificResolution = Boolean(formatToFind.match(/\d/));
|
|
5
|
-
let foundSpecific = isSpecificResolution ? false : 'N/A';
|
|
6
|
-
const args = ['--print', '%(formats)j', url];
|
|
7
|
-
let output = '';
|
|
8
|
-
try {
|
|
9
|
-
output = await spawnAsync('yt-dlp', args);
|
|
10
|
-
}
|
|
11
|
-
catch (err) {
|
|
12
|
-
console.error('Error consiguiendo el ID del formato');
|
|
13
|
-
throw err;
|
|
14
|
-
}
|
|
15
|
-
let formats = [];
|
|
16
|
-
try {
|
|
17
|
-
formats = JSON.parse(output);
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
console.error('Error convirtiendo la salida de yt-dlp a JSON');
|
|
21
|
-
throw err;
|
|
22
|
-
}
|
|
23
|
-
if (!Array.isArray(formats)) {
|
|
24
|
-
throw new Error('Se esperaba un array');
|
|
25
|
-
}
|
|
26
|
-
let bestVideo = undefined;
|
|
27
|
-
let worstVideo = undefined;
|
|
28
|
-
let bestAudio = undefined;
|
|
29
|
-
let worstAudio = undefined;
|
|
30
|
-
let desiredFormat = undefined;
|
|
31
|
-
for (const format of formats) {
|
|
32
|
-
const audioOnly = format.resolution === 'audio only';
|
|
33
|
-
if (isSpecificResolution && format.format_note === formatToFind) {
|
|
34
|
-
foundSpecific = true;
|
|
35
|
-
desiredFormat = getBetterFormat(desiredFormat, format, { compareResolution: false, type: 'video' }) ?? format;
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (audioOnly) {
|
|
39
|
-
bestAudio = getBetterFormat(bestAudio, format, { compareResolution: false, type: 'audio' }) ?? format;
|
|
40
|
-
worstAudio = getWorstFormat(worstAudio, format, { compareResolution: false, type: 'audio' }) ?? format;
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
bestVideo = getBetterFormat(bestVideo, format, { compareResolution: true, type: 'video' }) ?? format;
|
|
44
|
-
worstVideo = getWorstFormat(worstVideo, format, { compareResolution: true, type: 'video' }) ?? format;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (!isSpecificResolution) {
|
|
48
|
-
const formats = {
|
|
49
|
-
'best-video': bestVideo,
|
|
50
|
-
'worst-video': worstVideo,
|
|
51
|
-
'best-audio': bestAudio,
|
|
52
|
-
'worst-audio': worstAudio
|
|
53
|
-
};
|
|
54
|
-
desiredFormat = formats[formatToFind];
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
foundSpecific,
|
|
58
|
-
formatId: desiredFormat?.format_id,
|
|
59
|
-
desiredFormat
|
|
60
|
-
};
|
|
61
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { spawnAsync } from '../lib/spawnAsync';
|
|
2
|
-
import { resolveFilename } from '../lib/resolveFilename';
|
|
3
|
-
export class YtDlpDownloader {
|
|
4
|
-
async download(url, ytId, options) {
|
|
5
|
-
const args = this.buildYtDlpArgs(url, ytId, options);
|
|
6
|
-
// const result = await spawnAsync('yt-dlp', args, true)
|
|
7
|
-
await spawnAsync('yt-dlp', args, true);
|
|
8
|
-
return {
|
|
9
|
-
duration: -1,
|
|
10
|
-
path: 'unknown'
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
buildYtDlpArgs(url, ytId, options) {
|
|
14
|
-
const { id, type } = options;
|
|
15
|
-
const isVideo = type === 'video';
|
|
16
|
-
const exportRoute = options.outputPath;
|
|
17
|
-
const exportName = resolveFilename({ filename: options.filename, id: options.id, ytId });
|
|
18
|
-
const audioFormat = 'aac';
|
|
19
|
-
const audioFormatPreferences = isVideo
|
|
20
|
-
? []
|
|
21
|
-
: ['-x', '--audio-format', audioFormat];
|
|
22
|
-
const args = [
|
|
23
|
-
'-f', id,
|
|
24
|
-
...audioFormatPreferences,
|
|
25
|
-
'-o', exportName,
|
|
26
|
-
'-P', exportRoute,
|
|
27
|
-
url
|
|
28
|
-
];
|
|
29
|
-
return args;
|
|
30
|
-
}
|
|
31
|
-
}
|