ytdlp-react-native 1.0.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/CHANGELOG.md +74 -0
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/android/build.gradle +25 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/ytdlp/ExpoYtDlpModule.kt +74 -0
- package/android/src/main/java/expo/modules/ytdlp/YtDlpDownloadManager.kt +97 -0
- package/android/src/main/java/expo/modules/ytdlp/YtDlpEngine.kt +277 -0
- package/android/src/main/java/expo/modules/ytdlp/YtDlpException.kt +14 -0
- package/android/src/main/java/expo/modules/ytdlp/YtDlpFileUtil.kt +89 -0
- package/android/src/main/java/expo/modules/ytdlp/YtDlpTask.kt +225 -0
- package/build/ExpoYtDlpModule.d.ts +35 -0
- package/build/ExpoYtDlpModule.d.ts.map +1 -0
- package/build/ExpoYtDlpModule.js +10 -0
- package/build/ExpoYtDlpModule.js.map +1 -0
- package/build/ExpoYtDlpModule.web.d.ts +11 -0
- package/build/ExpoYtDlpModule.web.d.ts.map +1 -0
- package/build/ExpoYtDlpModule.web.js +13 -0
- package/build/ExpoYtDlpModule.web.js.map +1 -0
- package/build/YtDlp.d.ts +23 -0
- package/build/YtDlp.d.ts.map +1 -0
- package/build/YtDlp.js +160 -0
- package/build/YtDlp.js.map +1 -0
- package/build/constants.d.ts +9 -0
- package/build/constants.d.ts.map +1 -0
- package/build/constants.js +9 -0
- package/build/constants.js.map +1 -0
- package/build/downloadTask.d.ts +30 -0
- package/build/downloadTask.d.ts.map +1 -0
- package/build/downloadTask.js +111 -0
- package/build/downloadTask.js.map +1 -0
- package/build/errors.d.ts +27 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +111 -0
- package/build/errors.js.map +1 -0
- package/build/events.d.ts +20 -0
- package/build/events.d.ts.map +1 -0
- package/build/events.js +96 -0
- package/build/events.js.map +1 -0
- package/build/index.d.ts +14 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +13 -0
- package/build/index.js.map +1 -0
- package/build/mappers.d.ts +15 -0
- package/build/mappers.d.ts.map +1 -0
- package/build/mappers.js +149 -0
- package/build/mappers.js.map +1 -0
- package/build/types.d.ts +183 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/expo-module.config.json +6 -0
- package/package.json +68 -0
- package/src/ExpoYtDlpModule.ts +41 -0
- package/src/ExpoYtDlpModule.web.ts +15 -0
- package/src/YtDlp.ts +151 -0
- package/src/constants.ts +11 -0
- package/src/downloadTask.ts +159 -0
- package/src/errors.ts +133 -0
- package/src/events.ts +116 -0
- package/src/index.ts +17 -0
- package/src/mappers.ts +168 -0
- package/src/types.ts +219 -0
package/build/events.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for reacting to native `downloadEvent` emissions.
|
|
3
|
+
*/
|
|
4
|
+
import { NativeExpoYtDlp } from './ExpoYtDlpModule';
|
|
5
|
+
import { fromNativeCode } from './errors';
|
|
6
|
+
const EVENT_NAME = 'downloadEvent';
|
|
7
|
+
/**
|
|
8
|
+
* Returns a per-task subscription backed by the native event stream.
|
|
9
|
+
* `taskId` is used to filter events that belong to another task.
|
|
10
|
+
*/
|
|
11
|
+
export function subscribeToTask(taskId, handler) {
|
|
12
|
+
return subscribeToDownloadEvents((event) => {
|
|
13
|
+
if (event.taskId === taskId) {
|
|
14
|
+
handler(event);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export function subscribeToDownloadEvents(handler) {
|
|
19
|
+
if (!NativeExpoYtDlp) {
|
|
20
|
+
return { remove: () => { } };
|
|
21
|
+
}
|
|
22
|
+
// The native module is itself an EventEmitter (Expo SDK 52+); the old
|
|
23
|
+
// `new NativeEventEmitter(module)` path requires `addListener`/`removeListeners`
|
|
24
|
+
// that Expo modules do not expose.
|
|
25
|
+
const subscription = NativeExpoYtDlp.addListener(EVENT_NAME, (event) => {
|
|
26
|
+
try {
|
|
27
|
+
handler(normalizeEvent(event));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Never let a listener crash the JS runtime.
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return { remove: () => subscription.remove() };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Adds task-level listeners to a [DownloadTask] from a raw subscription
|
|
37
|
+
* factory. Keeps the event filtering in one place.
|
|
38
|
+
*/
|
|
39
|
+
export function attachTaskListeners(taskId, listeners) {
|
|
40
|
+
const subs = [];
|
|
41
|
+
subs.push(subscribeToTask(taskId, (event) => {
|
|
42
|
+
switch (event.type) {
|
|
43
|
+
case 'progress':
|
|
44
|
+
if (event.progress && listeners.progress)
|
|
45
|
+
listeners.progress(event.progress);
|
|
46
|
+
break;
|
|
47
|
+
case 'state':
|
|
48
|
+
if (listeners.state)
|
|
49
|
+
listeners.state({ taskId: event.taskId, status: event.status });
|
|
50
|
+
break;
|
|
51
|
+
case 'completed':
|
|
52
|
+
if (event.result && listeners.completed)
|
|
53
|
+
listeners.completed(event.result);
|
|
54
|
+
break;
|
|
55
|
+
case 'cancelled':
|
|
56
|
+
if (listeners.cancelled)
|
|
57
|
+
listeners.cancelled();
|
|
58
|
+
if (listeners.state)
|
|
59
|
+
listeners.state({ taskId: event.taskId, status: 'cancelled' });
|
|
60
|
+
break;
|
|
61
|
+
case 'error':
|
|
62
|
+
if (event.error) {
|
|
63
|
+
const error = fromNativeCode(event.error.code, event.error.message);
|
|
64
|
+
if (listeners.error)
|
|
65
|
+
listeners.error(error);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}));
|
|
70
|
+
return subs;
|
|
71
|
+
}
|
|
72
|
+
function normalizeEvent(event) {
|
|
73
|
+
if (event.type === 'progress' && event.progress) {
|
|
74
|
+
return {
|
|
75
|
+
...event,
|
|
76
|
+
progress: {
|
|
77
|
+
taskId: event.taskId,
|
|
78
|
+
status: event.status,
|
|
79
|
+
phase: event.progress.phase,
|
|
80
|
+
percent: finiteOrUndefined(event.progress.percent),
|
|
81
|
+
downloadedBytes: finiteOrUndefined(event.progress.downloadedBytes),
|
|
82
|
+
totalBytes: finiteOrUndefined(event.progress.totalBytes),
|
|
83
|
+
speedBytesPerSecond: finiteOrUndefined(event.progress.speedBytesPerSecond),
|
|
84
|
+
etaSeconds: finiteOrUndefined(event.progress.etaSeconds),
|
|
85
|
+
filename: event.progress.filename,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return event;
|
|
90
|
+
}
|
|
91
|
+
function finiteOrUndefined(value) {
|
|
92
|
+
if (value === undefined || value === null)
|
|
93
|
+
return undefined;
|
|
94
|
+
return Number.isFinite(value) ? value : undefined;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared helpers for reacting to native `downloadEvent` emissions.\n */\nimport { NativeExpoYtDlp } from './ExpoYtDlpModule';\nimport { fromNativeCode, type YtDlpError } from './errors';\nimport type {\n DownloadEvent,\n DownloadProgress,\n DownloadResult,\n DownloadStateEvent,\n Subscription,\n} from './types';\n\nconst EVENT_NAME = 'downloadEvent';\n\n/**\n * Returns a per-task subscription backed by the native event stream.\n * `taskId` is used to filter events that belong to another task.\n */\nexport function subscribeToTask(\n taskId: string,\n handler: (event: DownloadEvent) => void\n): Subscription {\n return subscribeToDownloadEvents((event) => {\n if (event.taskId === taskId) {\n handler(event);\n }\n });\n}\n\nexport function subscribeToDownloadEvents(handler: (event: DownloadEvent) => void): Subscription {\n if (!NativeExpoYtDlp) {\n return { remove: () => {} };\n }\n // The native module is itself an EventEmitter (Expo SDK 52+); the old\n // `new NativeEventEmitter(module)` path requires `addListener`/`removeListeners`\n // that Expo modules do not expose.\n const subscription = NativeExpoYtDlp.addListener(EVENT_NAME, (event: DownloadEvent) => {\n try {\n handler(normalizeEvent(event));\n } catch {\n // Never let a listener crash the JS runtime.\n }\n });\n return { remove: () => subscription.remove() };\n}\n\n/**\n * Adds task-level listeners to a [DownloadTask] from a raw subscription\n * factory. Keeps the event filtering in one place.\n */\nexport function attachTaskListeners(\n taskId: string,\n listeners: {\n progress?: (progress: DownloadProgress) => void;\n state?: (state: DownloadStateEvent) => void;\n completed?: (result: DownloadResult) => void;\n cancelled?: () => void;\n error?: (error: YtDlpError) => void;\n }\n): Subscription[] {\n const subs: Subscription[] = [];\n\n subs.push(\n subscribeToTask(taskId, (event) => {\n switch (event.type) {\n case 'progress':\n if (event.progress && listeners.progress) listeners.progress(event.progress);\n break;\n case 'state':\n if (listeners.state) listeners.state({ taskId: event.taskId, status: event.status });\n break;\n case 'completed':\n if (event.result && listeners.completed) listeners.completed(event.result);\n break;\n case 'cancelled':\n if (listeners.cancelled) listeners.cancelled();\n if (listeners.state) listeners.state({ taskId: event.taskId, status: 'cancelled' });\n break;\n case 'error':\n if (event.error) {\n const error = fromNativeCode(event.error.code, event.error.message);\n if (listeners.error) listeners.error(error);\n }\n break;\n }\n })\n );\n\n return subs;\n}\n\nfunction normalizeEvent(event: DownloadEvent): DownloadEvent {\n if (event.type === 'progress' && event.progress) {\n return {\n ...event,\n progress: {\n taskId: event.taskId,\n status: event.status,\n phase: event.progress.phase,\n percent: finiteOrUndefined(event.progress.percent),\n downloadedBytes: finiteOrUndefined(event.progress.downloadedBytes),\n totalBytes: finiteOrUndefined(event.progress.totalBytes),\n speedBytesPerSecond: finiteOrUndefined(event.progress.speedBytesPerSecond),\n etaSeconds: finiteOrUndefined(event.progress.etaSeconds),\n filename: event.progress.filename,\n },\n };\n }\n return event;\n}\n\nfunction finiteOrUndefined(value: number | undefined): number | undefined {\n if (value === undefined || value === null) return undefined;\n return Number.isFinite(value) ? value : undefined;\n}\n"]}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { cancel, download, extractInfo, getFormats, getVersion } from './YtDlp';
|
|
2
|
+
import { YtDlpError } from './errors';
|
|
3
|
+
export type * from './types';
|
|
4
|
+
/** Main SDK facade. */
|
|
5
|
+
export declare const YtDlp: {
|
|
6
|
+
getVersion: typeof getVersion;
|
|
7
|
+
extractInfo: typeof extractInfo;
|
|
8
|
+
getFormats: typeof getFormats;
|
|
9
|
+
download: typeof download;
|
|
10
|
+
cancel: typeof cancel;
|
|
11
|
+
};
|
|
12
|
+
export { YtDlpError };
|
|
13
|
+
export default YtDlp;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,mBAAmB,SAAS,CAAC;AAE7B,uBAAuB;AACvB,eAAO,MAAM,KAAK;;;;;;CAMjB,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,eAAe,KAAK,CAAC"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { cancel, download, extractInfo, getFormats, getVersion } from './YtDlp';
|
|
2
|
+
import { YtDlpError } from './errors';
|
|
3
|
+
/** Main SDK facade. */
|
|
4
|
+
export const YtDlp = {
|
|
5
|
+
getVersion,
|
|
6
|
+
extractInfo,
|
|
7
|
+
getFormats,
|
|
8
|
+
download,
|
|
9
|
+
cancel,
|
|
10
|
+
};
|
|
11
|
+
export { YtDlpError };
|
|
12
|
+
export default YtDlp;
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC,uBAAuB;AACvB,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,UAAU;IACV,WAAW;IACX,UAAU;IACV,QAAQ;IACR,MAAM;CACP,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,eAAe,KAAK,CAAC","sourcesContent":["import { cancel, download, extractInfo, getFormats, getVersion } from './YtDlp';\nimport { YtDlpError } from './errors';\n\nexport type * from './types';\n\n/** Main SDK facade. */\nexport const YtDlp = {\n getVersion,\n extractInfo,\n getFormats,\n download,\n cancel,\n};\n\nexport { YtDlpError };\n\nexport default YtDlp;\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapping from the raw JSON produced by yt-dlp into the stable public types.
|
|
3
|
+
*
|
|
4
|
+
* Everything is defensive: unknown fields become `undefined`, never fake
|
|
5
|
+
* values (see AGENTS.md §11, §69, §70).
|
|
6
|
+
*/
|
|
7
|
+
import type { DownloadProgress, Format, VideoInfo } from './types';
|
|
8
|
+
export declare function mapVideoInfo(raw: unknown): VideoInfo;
|
|
9
|
+
export declare function mapFormat(raw: unknown): Format;
|
|
10
|
+
/**
|
|
11
|
+
* Maps the raw progress payload from the native `downloadEvent` into a
|
|
12
|
+
* `DownloadProgress`, replacing any non-finite numbers with `undefined`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mapDownloadProgress(raw: unknown, taskId: string): DownloadProgress | null;
|
|
15
|
+
//# sourceMappingURL=mappers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mappers.d.ts","sourceRoot":"","sources":["../src/mappers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAa,SAAS,EAAE,MAAM,SAAS,CAAC;AAM9E,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAqCpD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAgC9C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkBzF"}
|
package/build/mappers.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const NONE_CODEC = 'none';
|
|
2
|
+
export function mapVideoInfo(raw) {
|
|
3
|
+
const info = asRecord(raw);
|
|
4
|
+
const formats = Array.isArray(info.formats) ? info.formats.map(mapFormat) : [];
|
|
5
|
+
const liveStatus = stringOf(info.live_status);
|
|
6
|
+
const thumbnails = normalizeThumbnails(info.thumbnails, stringOf(info.thumbnail));
|
|
7
|
+
return {
|
|
8
|
+
id: stringOf(info.id),
|
|
9
|
+
title: stringOf(info.title),
|
|
10
|
+
description: stringOf(info.description),
|
|
11
|
+
uploader: stringOf(info.uploader),
|
|
12
|
+
uploaderId: stringOf(info.uploader_id),
|
|
13
|
+
uploaderUrl: stringOf(info.uploader_url),
|
|
14
|
+
channel: stringOf(info.channel),
|
|
15
|
+
channelId: stringOf(info.channel_id),
|
|
16
|
+
channelUrl: stringOf(info.channel_url),
|
|
17
|
+
webpageUrl: stringOf(info.webpage_url),
|
|
18
|
+
originalUrl: stringOf(info.original_url),
|
|
19
|
+
thumbnail: firstThumbnailUrl(thumbnails) ?? stringOf(info.thumbnail),
|
|
20
|
+
thumbnails,
|
|
21
|
+
duration: numberOf(info.duration),
|
|
22
|
+
durationString: stringOf(info.duration_string),
|
|
23
|
+
uploadDate: stringOf(info.upload_date),
|
|
24
|
+
timestamp: numberOf(info.timestamp),
|
|
25
|
+
viewCount: numberOf(info.view_count),
|
|
26
|
+
likeCount: numberOf(info.like_count),
|
|
27
|
+
commentCount: numberOf(info.comment_count),
|
|
28
|
+
ageLimit: numberOf(info.age_limit),
|
|
29
|
+
isLive: liveStatus === 'is_live',
|
|
30
|
+
wasLive: liveStatus === 'was_live',
|
|
31
|
+
extractor: stringOf(info.extractor),
|
|
32
|
+
extractorKey: stringOf(info.extractor_key),
|
|
33
|
+
webpageUrlDomain: stringOf(info.webpage_url_domain),
|
|
34
|
+
formats,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function mapFormat(raw) {
|
|
38
|
+
const format = asRecord(raw);
|
|
39
|
+
const vcodec = stringOf(format.vcodec);
|
|
40
|
+
const acodec = stringOf(format.acodec);
|
|
41
|
+
const hasVideo = vcodec !== undefined && vcodec.toLowerCase() !== NONE_CODEC;
|
|
42
|
+
const hasAudio = acodec !== undefined && acodec.toLowerCase() !== NONE_CODEC;
|
|
43
|
+
return {
|
|
44
|
+
id: stringOf(format.format_id) ?? stringOf(format.id) ?? '',
|
|
45
|
+
url: stringOf(format.url),
|
|
46
|
+
ext: stringOf(format.ext),
|
|
47
|
+
protocol: stringOf(format.protocol),
|
|
48
|
+
format: stringOf(format.format),
|
|
49
|
+
formatNote: stringOf(format.format_note),
|
|
50
|
+
width: numberOf(format.width),
|
|
51
|
+
height: numberOf(format.height),
|
|
52
|
+
fps: numberOf(format.fps),
|
|
53
|
+
vcodec,
|
|
54
|
+
acodec,
|
|
55
|
+
abr: numberOf(format.abr),
|
|
56
|
+
vbr: numberOf(format.vbr),
|
|
57
|
+
tbr: numberOf(format.tbr),
|
|
58
|
+
filesize: numberOf(format.filesize),
|
|
59
|
+
filesizeApprox: numberOf(format.filesize_approx),
|
|
60
|
+
quality: numberOf(format.quality),
|
|
61
|
+
audioOnly: hasAudio && !hasVideo,
|
|
62
|
+
videoOnly: hasVideo && !hasAudio,
|
|
63
|
+
hasVideo,
|
|
64
|
+
hasAudio,
|
|
65
|
+
language: stringOf(format.language),
|
|
66
|
+
container: stringOf(format.container),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Maps the raw progress payload from the native `downloadEvent` into a
|
|
71
|
+
* `DownloadProgress`, replacing any non-finite numbers with `undefined`.
|
|
72
|
+
*/
|
|
73
|
+
export function mapDownloadProgress(raw, taskId) {
|
|
74
|
+
const progress = asRecord(raw);
|
|
75
|
+
if (!progress)
|
|
76
|
+
return null;
|
|
77
|
+
const percent = numberOf(progress.percent);
|
|
78
|
+
const phaseRaw = stringOf(progress.phase);
|
|
79
|
+
return {
|
|
80
|
+
taskId,
|
|
81
|
+
status: statusOf(progress.status),
|
|
82
|
+
phase: phaseRaw === 'extracting' || phaseRaw === 'processing' ? phaseRaw : 'downloading',
|
|
83
|
+
percent,
|
|
84
|
+
downloadedBytes: numberOf(progress.downloadedBytes),
|
|
85
|
+
totalBytes: numberOf(progress.totalBytes),
|
|
86
|
+
speedBytesPerSecond: numberOf(progress.speedBytesPerSecond),
|
|
87
|
+
etaSeconds: numberOf(progress.etaSeconds),
|
|
88
|
+
filename: stringOf(progress.filename),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function statusOf(value) {
|
|
92
|
+
const s = stringOf(value);
|
|
93
|
+
switch (s) {
|
|
94
|
+
case 'queued':
|
|
95
|
+
case 'extracting':
|
|
96
|
+
case 'downloading':
|
|
97
|
+
case 'processing':
|
|
98
|
+
case 'completed':
|
|
99
|
+
case 'cancelled':
|
|
100
|
+
case 'failed':
|
|
101
|
+
return s;
|
|
102
|
+
default:
|
|
103
|
+
return 'downloading';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function normalizeThumbnails(value, fallbackUrl) {
|
|
107
|
+
const result = [];
|
|
108
|
+
if (Array.isArray(value)) {
|
|
109
|
+
for (const item of value) {
|
|
110
|
+
const record = asRecord(item);
|
|
111
|
+
const url = stringOf(record.url);
|
|
112
|
+
if (!url)
|
|
113
|
+
continue;
|
|
114
|
+
result.push({
|
|
115
|
+
url,
|
|
116
|
+
width: numberOf(record.width),
|
|
117
|
+
height: numberOf(record.height),
|
|
118
|
+
resolution: stringOf(record.resolution),
|
|
119
|
+
id: stringOf(record.id),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (result.length === 0 && fallbackUrl) {
|
|
124
|
+
result.push({ url: fallbackUrl });
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
function firstThumbnailUrl(thumbnails) {
|
|
129
|
+
return thumbnails[0]?.url;
|
|
130
|
+
}
|
|
131
|
+
function stringOf(value) {
|
|
132
|
+
if (typeof value === 'string' && value.length > 0)
|
|
133
|
+
return value;
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
function numberOf(value) {
|
|
137
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
138
|
+
return value;
|
|
139
|
+
if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) {
|
|
140
|
+
return Number(value);
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
function asRecord(value) {
|
|
145
|
+
if (typeof value === 'object' && value !== null)
|
|
146
|
+
return value;
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=mappers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mappers.js","sourceRoot":"","sources":["../src/mappers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mapping from the raw JSON produced by yt-dlp into the stable public types.\n *\n * Everything is defensive: unknown fields become `undefined`, never fake\n * values (see AGENTS.md §11, §69, §70).\n */\nimport type { DownloadProgress, Format, Thumbnail, VideoInfo } from './types';\n\ntype RawRecord = Record<string, unknown>;\n\nconst NONE_CODEC = 'none';\n\nexport function mapVideoInfo(raw: unknown): VideoInfo {\n const info = asRecord(raw);\n\n const formats = Array.isArray(info.formats) ? info.formats.map(mapFormat) : [];\n\n const liveStatus = stringOf(info.live_status);\n const thumbnails = normalizeThumbnails(info.thumbnails, stringOf(info.thumbnail));\n\n return {\n id: stringOf(info.id),\n title: stringOf(info.title),\n description: stringOf(info.description),\n uploader: stringOf(info.uploader),\n uploaderId: stringOf(info.uploader_id),\n uploaderUrl: stringOf(info.uploader_url),\n channel: stringOf(info.channel),\n channelId: stringOf(info.channel_id),\n channelUrl: stringOf(info.channel_url),\n webpageUrl: stringOf(info.webpage_url),\n originalUrl: stringOf(info.original_url),\n thumbnail: firstThumbnailUrl(thumbnails) ?? stringOf(info.thumbnail),\n thumbnails,\n duration: numberOf(info.duration),\n durationString: stringOf(info.duration_string),\n uploadDate: stringOf(info.upload_date),\n timestamp: numberOf(info.timestamp),\n viewCount: numberOf(info.view_count),\n likeCount: numberOf(info.like_count),\n commentCount: numberOf(info.comment_count),\n ageLimit: numberOf(info.age_limit),\n isLive: liveStatus === 'is_live',\n wasLive: liveStatus === 'was_live',\n extractor: stringOf(info.extractor),\n extractorKey: stringOf(info.extractor_key),\n webpageUrlDomain: stringOf(info.webpage_url_domain),\n formats,\n };\n}\n\nexport function mapFormat(raw: unknown): Format {\n const format = asRecord(raw);\n const vcodec = stringOf(format.vcodec);\n const acodec = stringOf(format.acodec);\n const hasVideo = vcodec !== undefined && vcodec.toLowerCase() !== NONE_CODEC;\n const hasAudio = acodec !== undefined && acodec.toLowerCase() !== NONE_CODEC;\n\n return {\n id: stringOf(format.format_id) ?? stringOf(format.id) ?? '',\n url: stringOf(format.url),\n ext: stringOf(format.ext),\n protocol: stringOf(format.protocol),\n format: stringOf(format.format),\n formatNote: stringOf(format.format_note),\n width: numberOf(format.width),\n height: numberOf(format.height),\n fps: numberOf(format.fps),\n vcodec,\n acodec,\n abr: numberOf(format.abr),\n vbr: numberOf(format.vbr),\n tbr: numberOf(format.tbr),\n filesize: numberOf(format.filesize),\n filesizeApprox: numberOf(format.filesize_approx),\n quality: numberOf(format.quality),\n audioOnly: hasAudio && !hasVideo,\n videoOnly: hasVideo && !hasAudio,\n hasVideo,\n hasAudio,\n language: stringOf(format.language),\n container: stringOf(format.container),\n };\n}\n\n/**\n * Maps the raw progress payload from the native `downloadEvent` into a\n * `DownloadProgress`, replacing any non-finite numbers with `undefined`.\n */\nexport function mapDownloadProgress(raw: unknown, taskId: string): DownloadProgress | null {\n const progress = asRecord(raw);\n if (!progress) return null;\n\n const percent = numberOf(progress.percent);\n const phaseRaw = stringOf(progress.phase);\n\n return {\n taskId,\n status: statusOf(progress.status),\n phase: phaseRaw === 'extracting' || phaseRaw === 'processing' ? phaseRaw : 'downloading',\n percent,\n downloadedBytes: numberOf(progress.downloadedBytes),\n totalBytes: numberOf(progress.totalBytes),\n speedBytesPerSecond: numberOf(progress.speedBytesPerSecond),\n etaSeconds: numberOf(progress.etaSeconds),\n filename: stringOf(progress.filename),\n };\n}\n\nfunction statusOf(value: unknown): DownloadProgress['status'] {\n const s = stringOf(value);\n switch (s) {\n case 'queued':\n case 'extracting':\n case 'downloading':\n case 'processing':\n case 'completed':\n case 'cancelled':\n case 'failed':\n return s;\n default:\n return 'downloading';\n }\n}\n\nfunction normalizeThumbnails(value: unknown, fallbackUrl?: string): Thumbnail[] {\n const result: Thumbnail[] = [];\n if (Array.isArray(value)) {\n for (const item of value) {\n const record = asRecord(item);\n const url = stringOf(record.url);\n if (!url) continue;\n result.push({\n url,\n width: numberOf(record.width),\n height: numberOf(record.height),\n resolution: stringOf(record.resolution),\n id: stringOf(record.id),\n });\n }\n }\n if (result.length === 0 && fallbackUrl) {\n result.push({ url: fallbackUrl });\n }\n return result;\n}\n\nfunction firstThumbnailUrl(thumbnails: Thumbnail[]): string | undefined {\n return thumbnails[0]?.url;\n}\n\nfunction stringOf(value: unknown): string | undefined {\n if (typeof value === 'string' && value.length > 0) return value;\n return undefined;\n}\n\nfunction numberOf(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) {\n return Number(value);\n }\n return undefined;\n}\n\nfunction asRecord(value: unknown): RawRecord {\n if (typeof value === 'object' && value !== null) return value as RawRecord;\n return {};\n}\n"]}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for expo-ytdlp-native.
|
|
3
|
+
*
|
|
4
|
+
* These types are the stable contract of the package. Native details never
|
|
5
|
+
* leak into this surface (see AGENTS.md §68).
|
|
6
|
+
*/
|
|
7
|
+
import type { YtDlpError } from './errors';
|
|
8
|
+
export type DownloadStatus = 'queued' | 'extracting' | 'downloading' | 'processing' | 'completed' | 'cancelled' | 'failed';
|
|
9
|
+
export type DownloadPhase = 'extracting' | 'downloading' | 'processing';
|
|
10
|
+
export interface Thumbnail {
|
|
11
|
+
url: string;
|
|
12
|
+
width?: number;
|
|
13
|
+
height?: number;
|
|
14
|
+
resolution?: string;
|
|
15
|
+
id?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Normalized media information. Every field is optional except `formats`. */
|
|
18
|
+
export interface VideoInfo {
|
|
19
|
+
id?: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
uploader?: string;
|
|
23
|
+
uploaderId?: string;
|
|
24
|
+
uploaderUrl?: string;
|
|
25
|
+
channel?: string;
|
|
26
|
+
channelId?: string;
|
|
27
|
+
channelUrl?: string;
|
|
28
|
+
webpageUrl?: string;
|
|
29
|
+
originalUrl?: string;
|
|
30
|
+
thumbnail?: string;
|
|
31
|
+
thumbnails?: Thumbnail[];
|
|
32
|
+
duration?: number;
|
|
33
|
+
durationString?: string;
|
|
34
|
+
uploadDate?: string;
|
|
35
|
+
timestamp?: number;
|
|
36
|
+
viewCount?: number;
|
|
37
|
+
likeCount?: number;
|
|
38
|
+
commentCount?: number;
|
|
39
|
+
ageLimit?: number;
|
|
40
|
+
isLive?: boolean;
|
|
41
|
+
wasLive?: boolean;
|
|
42
|
+
extractor?: string;
|
|
43
|
+
extractorKey?: string;
|
|
44
|
+
webpageUrlDomain?: string;
|
|
45
|
+
formats: Format[];
|
|
46
|
+
}
|
|
47
|
+
/** Normalized format model. Unknown native values become `undefined`. */
|
|
48
|
+
export interface Format {
|
|
49
|
+
id: string;
|
|
50
|
+
url?: string;
|
|
51
|
+
ext?: string;
|
|
52
|
+
protocol?: string;
|
|
53
|
+
format?: string;
|
|
54
|
+
formatNote?: string;
|
|
55
|
+
width?: number;
|
|
56
|
+
height?: number;
|
|
57
|
+
fps?: number;
|
|
58
|
+
vcodec?: string;
|
|
59
|
+
acodec?: string;
|
|
60
|
+
abr?: number;
|
|
61
|
+
vbr?: number;
|
|
62
|
+
tbr?: number;
|
|
63
|
+
filesize?: number;
|
|
64
|
+
filesizeApprox?: number;
|
|
65
|
+
quality?: number;
|
|
66
|
+
audioOnly: boolean;
|
|
67
|
+
videoOnly: boolean;
|
|
68
|
+
hasVideo: boolean;
|
|
69
|
+
hasAudio: boolean;
|
|
70
|
+
language?: string;
|
|
71
|
+
container?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface OutputOptions {
|
|
74
|
+
/**
|
|
75
|
+
* Directory name, relative to the app-specific external storage directory.
|
|
76
|
+
* Single path segments only; `..` is rejected.
|
|
77
|
+
*/
|
|
78
|
+
directory?: string;
|
|
79
|
+
/**
|
|
80
|
+
* yt-dlp output template, e.g. `%(title)s.%(ext)s`.
|
|
81
|
+
* Static parts are sanitized; template directives are preserved.
|
|
82
|
+
*/
|
|
83
|
+
filename?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface SubtitleOptions {
|
|
86
|
+
enabled?: boolean;
|
|
87
|
+
languages?: string[];
|
|
88
|
+
autoGenerated?: boolean;
|
|
89
|
+
}
|
|
90
|
+
export interface CookieOptions {
|
|
91
|
+
source: 'file';
|
|
92
|
+
path: string;
|
|
93
|
+
}
|
|
94
|
+
export interface NetworkOptions {
|
|
95
|
+
timeout?: number;
|
|
96
|
+
retries?: number;
|
|
97
|
+
}
|
|
98
|
+
export interface PlaylistOptions {
|
|
99
|
+
enabled?: boolean;
|
|
100
|
+
start?: number;
|
|
101
|
+
end?: number;
|
|
102
|
+
}
|
|
103
|
+
export interface ExtractOptions {
|
|
104
|
+
/** Cookies used during extraction (e.g. for login-gated sources). */
|
|
105
|
+
cookies?: CookieOptions;
|
|
106
|
+
/** Additional HTTP headers sent during extraction. Never logged. */
|
|
107
|
+
headers?: Record<string, string>;
|
|
108
|
+
/** Custom `User-Agent`. */
|
|
109
|
+
userAgent?: string;
|
|
110
|
+
proxy?: string;
|
|
111
|
+
}
|
|
112
|
+
export interface DownloadOptions {
|
|
113
|
+
url: string;
|
|
114
|
+
/** Raw yt-dlp format expression, e.g. `best`, `bestvideo+bestaudio`. */
|
|
115
|
+
format?: string;
|
|
116
|
+
output?: OutputOptions;
|
|
117
|
+
merge?: boolean;
|
|
118
|
+
subtitles?: SubtitleOptions;
|
|
119
|
+
cookies?: CookieOptions;
|
|
120
|
+
/** Additional HTTP headers. Validated; secrets are never logged. */
|
|
121
|
+
headers?: Record<string, string>;
|
|
122
|
+
userAgent?: string;
|
|
123
|
+
referer?: string;
|
|
124
|
+
proxy?: string;
|
|
125
|
+
playlist?: PlaylistOptions;
|
|
126
|
+
network?: NetworkOptions;
|
|
127
|
+
}
|
|
128
|
+
export interface DownloadProgress {
|
|
129
|
+
taskId: string;
|
|
130
|
+
status: DownloadStatus;
|
|
131
|
+
phase: DownloadPhase;
|
|
132
|
+
percent?: number;
|
|
133
|
+
downloadedBytes?: number;
|
|
134
|
+
totalBytes?: number;
|
|
135
|
+
speedBytesPerSecond?: number;
|
|
136
|
+
etaSeconds?: number;
|
|
137
|
+
filename?: string;
|
|
138
|
+
}
|
|
139
|
+
export interface DownloadResult {
|
|
140
|
+
taskId: string;
|
|
141
|
+
path?: string;
|
|
142
|
+
uri?: string;
|
|
143
|
+
filename?: string;
|
|
144
|
+
mimeType?: string;
|
|
145
|
+
size?: number;
|
|
146
|
+
duration?: number;
|
|
147
|
+
}
|
|
148
|
+
export type DownloadEventType = 'progress' | 'state' | 'completed' | 'error' | 'cancelled';
|
|
149
|
+
export interface DownloadEvent {
|
|
150
|
+
taskId: string;
|
|
151
|
+
type: DownloadEventType;
|
|
152
|
+
status: DownloadStatus;
|
|
153
|
+
phase: DownloadPhase;
|
|
154
|
+
progress?: DownloadProgress;
|
|
155
|
+
result?: DownloadResult;
|
|
156
|
+
error?: {
|
|
157
|
+
code: string;
|
|
158
|
+
message: string;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
export type DownloadStateEvent = {
|
|
162
|
+
taskId: string;
|
|
163
|
+
status: DownloadStatus;
|
|
164
|
+
};
|
|
165
|
+
export interface Subscription {
|
|
166
|
+
remove(): void;
|
|
167
|
+
}
|
|
168
|
+
export interface DownloadTask {
|
|
169
|
+
id: string;
|
|
170
|
+
cancel(): Promise<void>;
|
|
171
|
+
getStatus(): Promise<DownloadStatus>;
|
|
172
|
+
getProgress(): Promise<DownloadProgress | null>;
|
|
173
|
+
addListener(event: 'progress', listener: (progress: DownloadProgress) => void): Subscription;
|
|
174
|
+
addListener(event: 'state', listener: (state: DownloadStateEvent) => void): Subscription;
|
|
175
|
+
addListener(event: 'completed', listener: (result: DownloadResult) => void): Subscription;
|
|
176
|
+
addListener(event: 'error', listener: (error: YtDlpError) => void): Subscription;
|
|
177
|
+
}
|
|
178
|
+
export interface YtDlpVersion {
|
|
179
|
+
ytDlp: string;
|
|
180
|
+
library: string;
|
|
181
|
+
}
|
|
182
|
+
export type YtDlpErrorCode = 'INVALID_URL' | 'EXTRACTION_FAILED' | 'DOWNLOAD_FAILED' | 'CANCELLED' | 'FORMAT_UNAVAILABLE' | 'NETWORK_ERROR' | 'AUTHENTICATION_REQUIRED' | 'GEO_RESTRICTED' | 'PRIVATE_CONTENT' | 'AGE_RESTRICTED' | 'PROCESSING_FAILED' | 'STORAGE_ERROR' | 'INIT_FAILED' | 'UNSUPPORTED_PLATFORM' | 'UNKNOWN';
|
|
183
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Public types for expo-ytdlp-native.\n *\n * These types are the stable contract of the package. Native details never\n * leak into this surface (see AGENTS.md §68).\n */\nimport type { YtDlpError } from './errors';\n\nexport type DownloadStatus =\n 'queued' | 'extracting' | 'downloading' | 'processing' | 'completed' | 'cancelled' | 'failed';\n\nexport type DownloadPhase = 'extracting' | 'downloading' | 'processing';\n\nexport interface Thumbnail {\n url: string;\n width?: number;\n height?: number;\n resolution?: string;\n id?: string;\n}\n\n/** Normalized media information. Every field is optional except `formats`. */\nexport interface VideoInfo {\n id?: string;\n title?: string;\n description?: string;\n uploader?: string;\n uploaderId?: string;\n uploaderUrl?: string;\n channel?: string;\n channelId?: string;\n channelUrl?: string;\n webpageUrl?: string;\n originalUrl?: string;\n thumbnail?: string;\n thumbnails?: Thumbnail[];\n duration?: number;\n durationString?: string;\n uploadDate?: string;\n timestamp?: number;\n viewCount?: number;\n likeCount?: number;\n commentCount?: number;\n ageLimit?: number;\n isLive?: boolean;\n wasLive?: boolean;\n extractor?: string;\n extractorKey?: string;\n webpageUrlDomain?: string;\n formats: Format[];\n}\n\n/** Normalized format model. Unknown native values become `undefined`. */\nexport interface Format {\n id: string;\n url?: string;\n ext?: string;\n protocol?: string;\n format?: string;\n formatNote?: string;\n width?: number;\n height?: number;\n fps?: number;\n vcodec?: string;\n acodec?: string;\n abr?: number;\n vbr?: number;\n tbr?: number;\n filesize?: number;\n filesizeApprox?: number;\n quality?: number;\n audioOnly: boolean;\n videoOnly: boolean;\n hasVideo: boolean;\n hasAudio: boolean;\n language?: string;\n container?: string;\n}\n\nexport interface OutputOptions {\n /**\n * Directory name, relative to the app-specific external storage directory.\n * Single path segments only; `..` is rejected.\n */\n directory?: string;\n /**\n * yt-dlp output template, e.g. `%(title)s.%(ext)s`.\n * Static parts are sanitized; template directives are preserved.\n */\n filename?: string;\n}\n\nexport interface SubtitleOptions {\n enabled?: boolean;\n languages?: string[];\n autoGenerated?: boolean;\n}\n\nexport interface CookieOptions {\n source: 'file';\n path: string;\n}\n\nexport interface NetworkOptions {\n timeout?: number;\n retries?: number;\n}\n\nexport interface PlaylistOptions {\n enabled?: boolean;\n start?: number;\n end?: number;\n}\n\nexport interface ExtractOptions {\n /** Cookies used during extraction (e.g. for login-gated sources). */\n cookies?: CookieOptions;\n /** Additional HTTP headers sent during extraction. Never logged. */\n headers?: Record<string, string>;\n /** Custom `User-Agent`. */\n userAgent?: string;\n proxy?: string;\n}\n\nexport interface DownloadOptions {\n url: string;\n /** Raw yt-dlp format expression, e.g. `best`, `bestvideo+bestaudio`. */\n format?: string;\n output?: OutputOptions;\n merge?: boolean;\n subtitles?: SubtitleOptions;\n cookies?: CookieOptions;\n /** Additional HTTP headers. Validated; secrets are never logged. */\n headers?: Record<string, string>;\n userAgent?: string;\n referer?: string;\n proxy?: string;\n playlist?: PlaylistOptions;\n network?: NetworkOptions;\n}\n\nexport interface DownloadProgress {\n taskId: string;\n status: DownloadStatus;\n phase: DownloadPhase;\n percent?: number;\n downloadedBytes?: number;\n totalBytes?: number;\n speedBytesPerSecond?: number;\n etaSeconds?: number;\n filename?: string;\n}\n\nexport interface DownloadResult {\n taskId: string;\n path?: string;\n uri?: string;\n filename?: string;\n mimeType?: string;\n size?: number;\n duration?: number;\n}\n\nexport type DownloadEventType = 'progress' | 'state' | 'completed' | 'error' | 'cancelled';\n\nexport interface DownloadEvent {\n taskId: string;\n type: DownloadEventType;\n status: DownloadStatus;\n phase: DownloadPhase;\n progress?: DownloadProgress;\n result?: DownloadResult;\n error?: {\n code: string;\n message: string;\n };\n}\n\nexport type DownloadStateEvent = {\n taskId: string;\n status: DownloadStatus;\n};\n\nexport interface Subscription {\n remove(): void;\n}\n\nexport interface DownloadTask {\n id: string;\n cancel(): Promise<void>;\n getStatus(): Promise<DownloadStatus>;\n getProgress(): Promise<DownloadProgress | null>;\n addListener(event: 'progress', listener: (progress: DownloadProgress) => void): Subscription;\n addListener(event: 'state', listener: (state: DownloadStateEvent) => void): Subscription;\n addListener(event: 'completed', listener: (result: DownloadResult) => void): Subscription;\n addListener(event: 'error', listener: (error: YtDlpError) => void): Subscription;\n}\n\nexport interface YtDlpVersion {\n ytDlp: string;\n library: string;\n}\n\nexport type YtDlpErrorCode =\n | 'INVALID_URL'\n | 'EXTRACTION_FAILED'\n | 'DOWNLOAD_FAILED'\n | 'CANCELLED'\n | 'FORMAT_UNAVAILABLE'\n | 'NETWORK_ERROR'\n | 'AUTHENTICATION_REQUIRED'\n | 'GEO_RESTRICTED'\n | 'PRIVATE_CONTENT'\n | 'AGE_RESTRICTED'\n | 'PROCESSING_FAILED'\n | 'STORAGE_ERROR'\n | 'INIT_FAILED'\n | 'UNSUPPORTED_PLATFORM'\n | 'UNKNOWN';\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ytdlp-react-native",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A native Android Expo module providing a TypeScript API around yt-dlp.",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"android",
|
|
9
|
+
"build",
|
|
10
|
+
"src",
|
|
11
|
+
"expo-module.config.json",
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "node internal/module_scripts/build.js",
|
|
18
|
+
"clean": "node internal/module_scripts/clean.js",
|
|
19
|
+
"lint": "eslint src/",
|
|
20
|
+
"test": "node internal/module_scripts/test.js",
|
|
21
|
+
"prepare": "node internal/module_scripts/prepare.js",
|
|
22
|
+
"open:ios": "node internal/module_scripts/open-ios.js",
|
|
23
|
+
"open:android": "node internal/module_scripts/open-android.js"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"react-native",
|
|
27
|
+
"expo",
|
|
28
|
+
"ytdlp-react-native",
|
|
29
|
+
"ExpoYtDlp"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/devusimple/ytdlp-react-native.git"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/devusimple/ytdlp-react-native/issues"
|
|
37
|
+
},
|
|
38
|
+
"author": "Mehedi Hasan <huzzat2@gmail.com> (devusimple)",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"homepage": "https://github.com/devusimple/ytdlp-react-native#readme",
|
|
41
|
+
"dependencies": {},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@babel/core": "^7.26.0",
|
|
44
|
+
"@types/jest": "^29.2.1",
|
|
45
|
+
"@types/react": "~19.1.1",
|
|
46
|
+
"babel-preset-expo": "~55.0.8",
|
|
47
|
+
"eslint": "~9.39.4",
|
|
48
|
+
"eslint-config-universe": "^15.0.3",
|
|
49
|
+
"expo": "^57.0.13",
|
|
50
|
+
"jest": "^29.7.0",
|
|
51
|
+
"jest-expo": "~55.0.9",
|
|
52
|
+
"prettier": "^3.0.0",
|
|
53
|
+
"react-native": "0.82.1",
|
|
54
|
+
"typescript": "^5.9.2"
|
|
55
|
+
},
|
|
56
|
+
"jest": {
|
|
57
|
+
"preset": "jest-expo",
|
|
58
|
+
"roots": [
|
|
59
|
+
"<rootDir>/src"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"expo": "*",
|
|
64
|
+
"expo-modules-core": "*",
|
|
65
|
+
"react": "*",
|
|
66
|
+
"react-native": "*"
|
|
67
|
+
}
|
|
68
|
+
}
|