@yt-kit/core 0.4.0 → 0.5.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/dist/index.d.ts +3 -1
- package/dist/index.js +4 -1
- package/dist/lib/compareFormats.d.ts +10 -0
- package/dist/lib/compareFormats.js +52 -0
- package/dist/types/videoTypes.d.ts +2 -0
- package/dist/types/ytDlpFormatTypes.d.ts +61 -0
- package/dist/yt-dlp/findFormatId.d.ts +7 -0
- package/dist/yt-dlp/findFormatId.js +61 -0
- package/package.json +11 -3
- package/dist/lib/logs.d.ts +0 -1
- package/dist/lib/logs.js +0 -8
- package/dist/types/downloadTypes.d.ts +0 -1
- package/dist/types/processTypes.d.ts +0 -3
- package/dist/types/processTypes.js +0 -1
- /package/dist/types/{downloadTypes.js → ytDlpFormatTypes.js} +0 -0
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,5 +1,8 @@
|
|
|
1
1
|
// Funcionalidades del programa
|
|
2
|
-
export
|
|
2
|
+
export { downloadAudio, downloadVideo } from './tasks/download/download';
|
|
3
|
+
export { findFormatId } from './yt-dlp/findFormatId';
|
|
4
|
+
// Utilidades
|
|
5
|
+
export { formYoutubeUrl } from './lib/ytUtils';
|
|
3
6
|
// Tipos
|
|
4
7
|
export * from './types/videoTypes';
|
|
5
8
|
export * from './types/childProcessTypes';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MediaType } from '../types/videoTypes';
|
|
2
|
+
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
3
|
+
export declare function getBetterFormat(a: YtDlpFormat | undefined, b: YtDlpFormat | undefined, { type, compareResolution }: {
|
|
4
|
+
type: MediaType;
|
|
5
|
+
compareResolution: boolean;
|
|
6
|
+
}): YtDlpFormat | undefined;
|
|
7
|
+
export declare function getWorstFormat(a: YtDlpFormat | undefined, b: YtDlpFormat | undefined, { type, compareResolution }: {
|
|
8
|
+
type: MediaType;
|
|
9
|
+
compareResolution: boolean;
|
|
10
|
+
}): YtDlpFormat | undefined;
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { STANDARD_RESOLUTIONS } from '../lib/constants';
|
|
2
2
|
export type Height = typeof STANDARD_RESOLUTIONS[number];
|
|
3
3
|
export type Resolution = `${Height}p`;
|
|
4
|
+
export type FormatsToFind = Resolution | 'best-video' | 'worst-video' | 'best-audio' | 'worst-audio';
|
|
5
|
+
export type MediaType = 'audio' | 'video';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type YtDlpFormat = {
|
|
2
|
+
format_id: string;
|
|
3
|
+
format_note: string;
|
|
4
|
+
ext: EXT;
|
|
5
|
+
protocol: Protocol;
|
|
6
|
+
acodec: Acodec;
|
|
7
|
+
vcodec: string;
|
|
8
|
+
url: string;
|
|
9
|
+
width: number | null;
|
|
10
|
+
height: number | null;
|
|
11
|
+
fps: number | null;
|
|
12
|
+
rows?: number;
|
|
13
|
+
columns?: number;
|
|
14
|
+
fragments?: Fragment[];
|
|
15
|
+
audio_ext: AudioEXT;
|
|
16
|
+
video_ext: VideoEXT;
|
|
17
|
+
vbr: number | null;
|
|
18
|
+
abr: number | null;
|
|
19
|
+
tbr: number | null;
|
|
20
|
+
resolution: string;
|
|
21
|
+
aspect_ratio: number | null;
|
|
22
|
+
filesize_approx: number | null;
|
|
23
|
+
http_headers: HTTPHeaders;
|
|
24
|
+
format: string;
|
|
25
|
+
asr?: number | null;
|
|
26
|
+
filesize?: number | null;
|
|
27
|
+
source_preference?: number;
|
|
28
|
+
audio_channels?: number | null;
|
|
29
|
+
quality?: number;
|
|
30
|
+
has_drm?: boolean;
|
|
31
|
+
language?: null | string;
|
|
32
|
+
language_preference?: number;
|
|
33
|
+
preference?: null;
|
|
34
|
+
dynamic_range?: DynamicRange | null;
|
|
35
|
+
container?: Container;
|
|
36
|
+
available_at?: number;
|
|
37
|
+
downloader_options?: DownloaderOptions;
|
|
38
|
+
};
|
|
39
|
+
export type Acodec = 'none' | 'mp4a.40.5' | 'opus' | 'mp4a.40.2';
|
|
40
|
+
export type AudioEXT = 'none' | 'm4a' | 'webm';
|
|
41
|
+
export type Container = 'm4a_dash' | 'webm_dash' | 'mp4_dash';
|
|
42
|
+
export type DownloaderOptions = {
|
|
43
|
+
http_chunk_size: number;
|
|
44
|
+
};
|
|
45
|
+
export type DynamicRange = 'SDR';
|
|
46
|
+
export type EXT = 'mhtml' | 'm4a' | 'webm' | 'mp4';
|
|
47
|
+
export type Fragment = {
|
|
48
|
+
url: string;
|
|
49
|
+
duration: number;
|
|
50
|
+
};
|
|
51
|
+
export type HTTPHeaders = {
|
|
52
|
+
'User-Agent': string;
|
|
53
|
+
Accept: Accept;
|
|
54
|
+
'Accept-Language': AcceptLanguage;
|
|
55
|
+
'Sec-Fetch-Mode': SECFetchMode;
|
|
56
|
+
};
|
|
57
|
+
export type Accept = 'text/html,application/xhtml+xml,application/xmlq=0.9,*/*q=0.8';
|
|
58
|
+
export type AcceptLanguage = 'en-us,enq=0.5';
|
|
59
|
+
export type SECFetchMode = 'navigate';
|
|
60
|
+
export type Protocol = 'mhtml' | 'https';
|
|
61
|
+
export type VideoEXT = 'none' | 'mp4' | 'webm';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FormatsToFind } from '../types/videoTypes';
|
|
2
|
+
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
3
|
+
export declare function findFormatId(url: string, formatToFind: FormatsToFind): Promise<{
|
|
4
|
+
foundSpecific: string | boolean;
|
|
5
|
+
formatId: string | undefined;
|
|
6
|
+
desiredFormat: YtDlpFormat | undefined;
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yt-kit/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
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
24
|
"build": "tsc -p tsconfig.build.json",
|
|
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
|
+
}
|
package/dist/lib/logs.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function streamLog(type: 'data' | 'err', data: any): void;
|
package/dist/lib/logs.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type DownloadType = 'video' | 'audio';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
File without changes
|