@yt-kit/core 0.5.0 → 0.6.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 +0 -6
- package/dist/cache/CacheManager.d.ts +12 -0
- package/dist/cache/getFromCache.d.ts +1 -0
- package/dist/cache/saveInCache.d.ts +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -7
- package/dist/lib/timeUtils.d.ts +16 -0
- package/dist/yt-dlp/findFormatId.d.ts +7 -0
- package/dist/yt-dlp-downloader/YtDlpDownloader.d.ts +0 -7
- package/package.json +12 -4
- 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-downloader/YtDlpDownloader.js +0 -91
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,12 @@
|
|
|
1
|
+
export interface CachedData {
|
|
2
|
+
content: string;
|
|
3
|
+
timestamp: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class CacheManager {
|
|
6
|
+
private store;
|
|
7
|
+
private defaultTtl;
|
|
8
|
+
get(key: string): CachedData | null;
|
|
9
|
+
set(key: string, value: CachedData): void;
|
|
10
|
+
delete(key: string): void;
|
|
11
|
+
}
|
|
12
|
+
export declare const cache: CacheManager;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getFromCache(key: string): import("./CacheManager").CachedData | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { downloadAudio, downloadVideo } from './tasks/download/download';
|
|
2
|
+
export { findFormatId } from './yt-dlp/findFormatId';
|
|
3
|
+
export { formYoutubeUrl } from './lib/ytUtils';
|
|
2
4
|
export * from './types/videoTypes';
|
|
3
5
|
export * from './types/childProcessTypes';
|
|
4
6
|
export { STANDARD_RESOLUTIONS } from './lib/constants';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export * from './tasks/download/download';
|
|
3
|
-
// Tipos
|
|
4
|
-
export * from './types/videoTypes';
|
|
5
|
-
export * from './types/childProcessTypes';
|
|
6
|
-
// Constantes públicas (seguras de exportar)
|
|
7
|
-
export { STANDARD_RESOLUTIONS } from './lib/constants';
|
|
1
|
+
var q=[18,144,240,360,480,720,1080,1440,2160],R={"yt-dlp":"yt-dlp-linux"},P="%(ytId)s.%(ext)s",T={ID:"%(id)s",YT_ID:"%(ytId)s"};function l(t){return`https://youtube.com/watch?v=${t}`}import{spawn as K}from"node:child_process";import{stdout as b,stderr as B}from"node:process";function C(t,e){(t==="data"?b:B).write(e)}function d(t,e,r){let o=R[t];return new Promise((i,p)=>{let f=K(o,e),c="",m="";f.stdout.on("data",(a)=>{c+=a;let s=a.toString();if(r)C("data",s)}),f.stderr.on("data",(a)=>{m+=a;let s=a.toString();if(r)C("err",s)}),f.on("close",(a)=>{if(a===0)i(c.toString());else p(Error(m.toString()))}),f.on("error",(a)=>{p(a)})})}function M(t,e){let r=t;for(let[o,i]of e)r=r.replaceAll(o,i);return r}function N(t){return t.replaceAll("/","⁄")}function E({filename:t,id:e,ytId:r}){let o=new Map([[T.ID,e],[T.YT_ID,r]]),i=M(t,o);return N(i)}class y{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:i}=r,p=i==="video",f=r.outputPath,c=E({filename:r.filename,id:r.id,ytId:e}),m="aac";return["-f",o,...p?[]:["-x","--audio-format","aac"],"-o",c,"-P",f,t]}}async function $(t,e){if(!t||!e.id)return;let r=l(t),o=O("video",e);return new y().download(r,t,o)}async function V(t,e){if(!t||!e.id)return;let r=l(t),o=O("audio",e);return new y().download(r,t,o)}function O(t,e){return{id:e.id,type:t,outputPath:e.outputPath??".",filename:e.filename??P}}function w({a:t,b:e,compareResolution:r,type:o}){let i=o==="video"&&r&&t.quality!==null&&e.quality!==null,p=o==="video"&&r&&t.height!==null&&e.height!==null,f=o==="video"&&t.fps!==null&&e.fps!==null,c=o==="audio"&&t.asr!==null&&e.asr!==null,m=t.tbr!==null&&e.tbr!==null,a=0,s=0;if(i){if((t.quality??0)>(e.quality??0))a+=3;else if((t.quality??0)<(e.quality??0))s+=3}if(p){if((t.height??0)>(e.height??0))a+=3;else if((t.height??0)<(e.height??0))s+=3}if(f){if((t.fps??0)>(e.fps??0))a+=2;else if((t.fps??0)<(e.fps??0))s+=2}if(c){if((t.asr??0)>(e.asr??0))a+=2;else if((t.asr??0)<(e.asr??0))s+=2}if(m){if((t.tbr??0)>(e.tbr??0))a+=1;else if((t.tbr??0)<(e.tbr??0))s+=1}return{aScore:a,bScore:s}}function h(t,e,{type:r,compareResolution:o}){if(!t||!e)return;let{aScore:i,bScore:p}=w({a:t,b:e,type:r,compareResolution:o});return i>p?t:e}function A(t,e,{type:r,compareResolution:o}){if(!t||!e)return;let{aScore:i,bScore:p}=w({a:t,b:e,type:r,compareResolution:o});return i>p?e:t}var Y={day:86400000};function v(t,e){if(!Y[e])return t;return Y[e]*t}class _{store=new Map;defaultTtl=v(10,"day");get(t){let e=this.store.get(t);if(!e)return null;if(Date.now()-e.timestamp>this.defaultTtl)return this.delete(t),null;return e}set(t,e){this.store.set(t,{...e,timestamp:Date.now()})}delete(t){this.store.delete(t)}}var g=new _;function L(t){return g.get(t)}function U(t,e){return g.set(t,e)}async function z(t,e){let r=l(t),o=`formats-${t}`,i=Boolean(e.match(/\d/)),p=i?!1:"N/A",f=["--print","%(formats)j",r],m=L(o)?.content??"";if(!m){let n;try{n=await d("yt-dlp",f)}catch(x){throw console.error("Error consiguiendo el ID del formato"),x}if(typeof n!=="string")throw Error("La salida del proceso es de tipo inválido (se esperaba string)");m=n,U(o,{content:m,timestamp:Date.now()})}let a=[];try{a=JSON.parse(m)}catch(n){throw console.error("Error convirtiendo la salida de yt-dlp a JSON"),n}if(!Array.isArray(a))throw Error("Se esperaba un array");let s=void 0,D=void 0,S=void 0,F=void 0,u=void 0;for(let n of a){let x=n.resolution==="audio only";if(i&&n.format_note===e){p=!0,u=h(u,n,{compareResolution:!1,type:"video"})??n;continue}if(x)S=h(S,n,{compareResolution:!1,type:"audio"})??n,F=A(F,n,{compareResolution:!1,type:"audio"})??n;else s=h(s,n,{compareResolution:!0,type:"video"})??n,D=A(D,n,{compareResolution:!0,type:"video"})??n}if(!i)u={"best-video":s,"worst-video":D,"best-audio":S,"worst-audio":F}[e];return{foundSpecific:p,formatId:u?.format_id,desiredFormat:u}}export{l as formYoutubeUrl,z as findFormatId,$ as downloadVideo,V as downloadAudio,q as STANDARD_RESOLUTIONS};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type TimeUnit = 'day';
|
|
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 {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FormatsToFind } from '../types/videoTypes';
|
|
2
|
+
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
3
|
+
export declare function findFormatId(ytId: string, formatToFind: FormatsToFind): Promise<{
|
|
4
|
+
foundSpecific: string | boolean;
|
|
5
|
+
formatId: string | undefined;
|
|
6
|
+
desiredFormat: YtDlpFormat | undefined;
|
|
7
|
+
}>;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { Downloader, DownloadTasksOptions, DownloadResult } from '../interfaces/Downloader';
|
|
2
|
-
import type { FormatsToFind } from '../types/videoTypes';
|
|
3
|
-
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
4
2
|
export declare class YtDlpDownloader implements Downloader {
|
|
5
3
|
download(url: string, ytId: string, options: DownloadTasksOptions): Promise<DownloadResult>;
|
|
6
|
-
findFormatId(url: string, formatToFind: FormatsToFind): Promise<{
|
|
7
|
-
foundSpecific: string | boolean;
|
|
8
|
-
formatId: string | undefined;
|
|
9
|
-
desiredFormat: YtDlpFormat | undefined;
|
|
10
|
-
}>;
|
|
11
4
|
private buildYtDlpArgs;
|
|
12
5
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yt-kit/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -11,16 +11,24 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/ubiufboeuf/yt-kit.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/ubiufboeuf/yt-kit/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/ubiufboeuf/yt-kit#readme",
|
|
14
22
|
"scripts": {
|
|
15
23
|
"start": "bun pruebas.ts",
|
|
16
|
-
"build": "tsc -p tsconfig.build.json",
|
|
24
|
+
"build": "bun build.ts && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
17
25
|
"prepublishOnly": "bun run build"
|
|
18
26
|
},
|
|
19
27
|
"dependencies": {
|
|
20
|
-
"eslint": "9.39.1",
|
|
21
28
|
"typescript": "5"
|
|
22
29
|
},
|
|
23
30
|
"devDependencies": {
|
|
31
|
+
"eslint": "9.39.1",
|
|
24
32
|
"@eslint/js": "9.39.1",
|
|
25
33
|
"@stylistic/eslint-plugin": "5.6.1",
|
|
26
34
|
"globals": "16.5.0",
|
|
@@ -32,4 +40,4 @@
|
|
|
32
40
|
"files": [
|
|
33
41
|
"dist"
|
|
34
42
|
]
|
|
35
|
-
}
|
|
43
|
+
}
|
|
@@ -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,91 +0,0 @@
|
|
|
1
|
-
import { spawnAsync } from '../lib/spawnAsync';
|
|
2
|
-
import { resolveFilename } from '../lib/resolveFilename';
|
|
3
|
-
import { getBetterFormat, getWorstFormat } from '../lib/compareFormats';
|
|
4
|
-
export class YtDlpDownloader {
|
|
5
|
-
async download(url, ytId, options) {
|
|
6
|
-
const args = this.buildYtDlpArgs(url, ytId, options);
|
|
7
|
-
// const result = await spawnAsync('yt-dlp', args, true)
|
|
8
|
-
await spawnAsync('yt-dlp', args, true);
|
|
9
|
-
return {
|
|
10
|
-
duration: -1,
|
|
11
|
-
path: 'unknown'
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
async findFormatId(url, formatToFind) {
|
|
15
|
-
const isSpecificResolution = Boolean(formatToFind.match(/\d/));
|
|
16
|
-
let foundSpecific = isSpecificResolution ? false : 'N/A';
|
|
17
|
-
const args = ['--print', '%(formats)j', url];
|
|
18
|
-
let output = '';
|
|
19
|
-
try {
|
|
20
|
-
output = await spawnAsync('yt-dlp', args);
|
|
21
|
-
}
|
|
22
|
-
catch (err) {
|
|
23
|
-
console.error('Error consiguiendo el ID del formato');
|
|
24
|
-
throw err;
|
|
25
|
-
}
|
|
26
|
-
let formats = [];
|
|
27
|
-
try {
|
|
28
|
-
formats = JSON.parse(output);
|
|
29
|
-
}
|
|
30
|
-
catch (err) {
|
|
31
|
-
console.error('Error convirtiendo la salida de yt-dlp a JSON');
|
|
32
|
-
throw err;
|
|
33
|
-
}
|
|
34
|
-
if (!Array.isArray(formats)) {
|
|
35
|
-
throw new Error('Se esperaba un array');
|
|
36
|
-
}
|
|
37
|
-
let bestVideo = undefined;
|
|
38
|
-
let worstVideo = undefined;
|
|
39
|
-
let bestAudio = undefined;
|
|
40
|
-
let worstAudio = undefined;
|
|
41
|
-
let desiredFormat = undefined;
|
|
42
|
-
for (const format of formats) {
|
|
43
|
-
const audioOnly = format.resolution === 'audio only';
|
|
44
|
-
if (isSpecificResolution && format.format_note === formatToFind) {
|
|
45
|
-
foundSpecific = true;
|
|
46
|
-
desiredFormat = getBetterFormat(desiredFormat, format, { compareResolution: false, type: 'video' }) ?? format;
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
if (audioOnly) {
|
|
50
|
-
bestAudio = getBetterFormat(bestAudio, format, { compareResolution: false, type: 'audio' }) ?? format;
|
|
51
|
-
worstAudio = getWorstFormat(worstAudio, format, { compareResolution: false, type: 'audio' }) ?? format;
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
bestVideo = getBetterFormat(bestVideo, format, { compareResolution: true, type: 'video' }) ?? format;
|
|
55
|
-
worstVideo = getWorstFormat(worstVideo, format, { compareResolution: true, type: 'video' }) ?? format;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (!isSpecificResolution) {
|
|
59
|
-
const formats = {
|
|
60
|
-
'best-video': bestVideo,
|
|
61
|
-
'worst-video': worstVideo,
|
|
62
|
-
'best-audio': bestAudio,
|
|
63
|
-
'worst-audio': worstAudio
|
|
64
|
-
};
|
|
65
|
-
desiredFormat = formats[formatToFind];
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
foundSpecific,
|
|
69
|
-
formatId: desiredFormat?.format_id,
|
|
70
|
-
desiredFormat
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
buildYtDlpArgs(url, ytId, options) {
|
|
74
|
-
const { id, type } = options;
|
|
75
|
-
const isVideo = type === 'video';
|
|
76
|
-
const exportRoute = options.outputPath;
|
|
77
|
-
const exportName = resolveFilename({ filename: options.filename, id: options.id, ytId });
|
|
78
|
-
const audioFormat = 'aac';
|
|
79
|
-
const audioFormatPreferences = isVideo
|
|
80
|
-
? []
|
|
81
|
-
: ['-x', '--audio-format', audioFormat];
|
|
82
|
-
const args = [
|
|
83
|
-
'-f', id,
|
|
84
|
-
...audioFormatPreferences,
|
|
85
|
-
'-o', exportName,
|
|
86
|
-
'-P', exportRoute,
|
|
87
|
-
url
|
|
88
|
-
];
|
|
89
|
-
return args;
|
|
90
|
-
}
|
|
91
|
-
}
|