@yt-kit/core 0.4.0 → 0.5.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/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-downloader/YtDlpDownloader.d.ts +7 -0
- package/dist/yt-dlp-downloader/YtDlpDownloader.js +60 -0
- package/package.json +1 -1
- 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
|
@@ -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';
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { Downloader, DownloadTasksOptions, DownloadResult } from '../interfaces/Downloader';
|
|
2
|
+
import type { FormatsToFind } from '../types/videoTypes';
|
|
3
|
+
import type { YtDlpFormat } from '../types/ytDlpFormatTypes';
|
|
2
4
|
export declare class YtDlpDownloader implements Downloader {
|
|
3
5
|
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
|
+
}>;
|
|
4
11
|
private buildYtDlpArgs;
|
|
5
12
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawnAsync } from '../lib/spawnAsync';
|
|
2
2
|
import { resolveFilename } from '../lib/resolveFilename';
|
|
3
|
+
import { getBetterFormat, getWorstFormat } from '../lib/compareFormats';
|
|
3
4
|
export class YtDlpDownloader {
|
|
4
5
|
async download(url, ytId, options) {
|
|
5
6
|
const args = this.buildYtDlpArgs(url, ytId, options);
|
|
@@ -10,6 +11,65 @@ export class YtDlpDownloader {
|
|
|
10
11
|
path: 'unknown'
|
|
11
12
|
};
|
|
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
|
+
}
|
|
13
73
|
buildYtDlpArgs(url, ytId, options) {
|
|
14
74
|
const { id, type } = options;
|
|
15
75
|
const isVideo = type === 'video';
|
package/package.json
CHANGED
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
|