react-native-sherpa-onnx 0.3.6 → 0.3.7
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/LICENSE +1 -0
- package/README.md +89 -21
- package/SherpaOnnx.podspec +3 -0
- package/THIRD_PARTY_LICENSES/README.md +62 -0
- package/THIRD_PARTY_LICENSES/ffmpeg.txt +502 -0
- package/THIRD_PARTY_LICENSES/libarchive.txt +65 -0
- package/THIRD_PARTY_LICENSES/nvidia_omla.txt +181 -0
- package/THIRD_PARTY_LICENSES/onnxruntime.txt +21 -0
- package/THIRD_PARTY_LICENSES/opus.txt +44 -0
- package/THIRD_PARTY_LICENSES/sherpa-onnx.txt +201 -0
- package/THIRD_PARTY_LICENSES/shine.txt +482 -0
- package/THIRD_PARTY_LICENSES/zstd.txt +30 -0
- package/android/build.gradle +7 -3
- package/android/prebuilt-download.gradle +344 -152
- package/android/prebuilt-versions.gradle +1 -1
- package/android/src/main/assets/model_licenses/asr-models-license-status.csv +409 -0
- package/android/src/main/assets/model_licenses/qnn-asr-models-license-status.csv +695 -0
- package/android/src/main/assets/model_licenses/tts-models-license-status.csv +596 -0
- package/android/src/main/cpp/CMakeLists.txt +28 -10
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +2 -2
- package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +268 -2
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +6 -2
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +4 -2
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +40 -10
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +99 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxOnlineSttHelper.kt +4 -1
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +112 -97
- package/ios/Resources/model_licenses/asr-models-license-status.csv +409 -0
- package/ios/Resources/model_licenses/qnn-asr-models-license-status.csv +695 -0
- package/ios/Resources/model_licenses/tts-models-license-status.csv +596 -0
- package/ios/SherpaOnnx+OnlineSTT.mm +2 -0
- package/ios/SherpaOnnx+PcmLiveStream.mm +2 -29
- package/ios/SherpaOnnx+TTS.mm +178 -20
- package/ios/SherpaOnnx.mm +54 -0
- package/ios/SherpaOnnxAudioConvert.h +10 -0
- package/ios/SherpaOnnxAudioConvert.mm +257 -1
- package/ios/archive/sherpa-onnx-archive-helper.h +3 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +39 -6
- package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +13 -2
- package/ios/model_detect/sherpa-onnx-validate-tts.mm +4 -2
- package/ios/online_stt/sherpa-onnx-online-stt-wrapper.h +1 -0
- package/ios/online_stt/sherpa-onnx-online-stt-wrapper.mm +4 -0
- package/ios/tts/sherpa-onnx-tts-wrapper.h +37 -0
- package/ios/tts/sherpa-onnx-tts-wrapper.mm +149 -3
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/audio/index.js +8 -0
- package/lib/module/audio/index.js.map +1 -1
- package/lib/module/download/ModelDownloadManager.js +10 -929
- package/lib/module/download/ModelDownloadManager.js.map +1 -1
- package/lib/module/download/activeModelOperations.js +26 -0
- package/lib/module/download/activeModelOperations.js.map +1 -0
- package/lib/module/download/background-downloader.d.js +2 -0
- package/lib/module/download/background-downloader.d.js.map +1 -0
- package/lib/module/download/bulkPurge.js +72 -0
- package/lib/module/download/bulkPurge.js.map +1 -0
- package/lib/module/download/checksumPrompt.js +19 -0
- package/lib/module/download/checksumPrompt.js.map +1 -0
- package/lib/module/download/constants.js +7 -0
- package/lib/module/download/constants.js.map +1 -0
- package/lib/module/download/downloadEvents.js +35 -0
- package/lib/module/download/downloadEvents.js.map +1 -0
- package/lib/module/download/downloadTask.js +385 -0
- package/lib/module/download/downloadTask.js.map +1 -0
- package/lib/module/download/ensureModel.js +89 -0
- package/lib/module/download/ensureModel.js.map +1 -0
- package/lib/module/download/index.js +4 -4
- package/lib/module/download/index.js.map +1 -1
- package/lib/module/download/localModels.js +151 -0
- package/lib/module/download/localModels.js.map +1 -0
- package/lib/module/download/modelExtraction.js +174 -0
- package/lib/module/download/modelExtraction.js.map +1 -0
- package/lib/module/download/paths.js +98 -0
- package/lib/module/download/paths.js.map +1 -0
- package/lib/module/download/postDownloadProcessing.js +206 -0
- package/lib/module/download/postDownloadProcessing.js.map +1 -0
- package/lib/module/download/protectedModelKeys.js +31 -0
- package/lib/module/download/protectedModelKeys.js.map +1 -0
- package/lib/module/download/registry.js +267 -0
- package/lib/module/download/registry.js.map +1 -0
- package/lib/module/download/retry.js +59 -0
- package/lib/module/download/retry.js.map +1 -0
- package/lib/module/download/types.js +17 -0
- package/lib/module/download/types.js.map +1 -0
- package/lib/module/download/validation.js +101 -5
- package/lib/module/download/validation.js.map +1 -1
- package/lib/module/{download → extraction}/extractTarBz2.js +3 -1
- package/lib/module/extraction/extractTarBz2.js.map +1 -0
- package/lib/module/{download → extraction}/extractTarZst.js +3 -1
- package/lib/module/extraction/extractTarZst.js.map +1 -0
- package/lib/module/extraction/index.js +3 -4
- package/lib/module/extraction/index.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/licenses.js +63 -0
- package/lib/module/licenses.js.map +1 -0
- package/lib/module/stt/index.js +16 -2
- package/lib/module/stt/index.js.map +1 -1
- package/lib/module/stt/streaming.js +2 -0
- package/lib/module/stt/streaming.js.map +1 -1
- package/lib/module/stt/streamingTypes.js.map +1 -1
- package/lib/module/stt/types.js.map +1 -1
- package/lib/module/tts/index.js +20 -2
- package/lib/module/tts/index.js.map +1 -1
- package/lib/module/tts/streaming.js +4 -0
- package/lib/module/tts/streaming.js.map +1 -1
- package/lib/module/tts/types.js.map +1 -1
- package/lib/module/utils.js +16 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +33 -5
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/audio/index.d.ts +10 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -1
- package/lib/typescript/src/download/ModelDownloadManager.d.ts +10 -108
- package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
- package/lib/typescript/src/download/activeModelOperations.d.ts +6 -0
- package/lib/typescript/src/download/activeModelOperations.d.ts.map +1 -0
- package/lib/typescript/src/download/bulkPurge.d.ts +14 -0
- package/lib/typescript/src/download/bulkPurge.d.ts.map +1 -0
- package/lib/typescript/src/download/checksumPrompt.d.ts +3 -0
- package/lib/typescript/src/download/checksumPrompt.d.ts.map +1 -0
- package/lib/typescript/src/download/constants.d.ts +5 -0
- package/lib/typescript/src/download/constants.d.ts.map +1 -0
- package/lib/typescript/src/download/downloadEvents.d.ts +6 -0
- package/lib/typescript/src/download/downloadEvents.d.ts.map +1 -0
- package/lib/typescript/src/download/downloadTask.d.ts +20 -0
- package/lib/typescript/src/download/downloadTask.d.ts.map +1 -0
- package/lib/typescript/src/download/ensureModel.d.ts +26 -0
- package/lib/typescript/src/download/ensureModel.d.ts.map +1 -0
- package/lib/typescript/src/download/index.d.ts +7 -7
- package/lib/typescript/src/download/index.d.ts.map +1 -1
- package/lib/typescript/src/download/localModels.d.ts +15 -0
- package/lib/typescript/src/download/localModels.d.ts.map +1 -0
- package/lib/typescript/src/download/modelExtraction.d.ts +36 -0
- package/lib/typescript/src/download/modelExtraction.d.ts.map +1 -0
- package/lib/typescript/src/download/paths.d.ts +28 -0
- package/lib/typescript/src/download/paths.d.ts.map +1 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts +19 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts.map +1 -0
- package/lib/typescript/src/download/protectedModelKeys.d.ts +6 -0
- package/lib/typescript/src/download/protectedModelKeys.d.ts.map +1 -0
- package/lib/typescript/src/download/registry.d.ts +14 -0
- package/lib/typescript/src/download/registry.d.ts.map +1 -0
- package/lib/typescript/src/download/retry.d.ts +15 -0
- package/lib/typescript/src/download/retry.d.ts.map +1 -0
- package/lib/typescript/src/download/types.d.ts +96 -0
- package/lib/typescript/src/download/types.d.ts.map +1 -0
- package/lib/typescript/src/download/validation.d.ts +19 -0
- package/lib/typescript/src/download/validation.d.ts.map +1 -1
- package/lib/typescript/src/extraction/extractTarBz2.d.ts.map +1 -0
- package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/licenses.d.ts +10 -0
- package/lib/typescript/src/licenses.d.ts.map +1 -0
- package/lib/typescript/src/stt/index.d.ts +4 -1
- package/lib/typescript/src/stt/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/streaming.d.ts.map +1 -1
- package/lib/typescript/src/stt/streamingTypes.d.ts +5 -0
- package/lib/typescript/src/stt/streamingTypes.d.ts.map +1 -1
- package/lib/typescript/src/stt/types.d.ts +3 -1
- package/lib/typescript/src/stt/types.d.ts.map +1 -1
- package/lib/typescript/src/tts/index.d.ts +3 -1
- package/lib/typescript/src/tts/index.d.ts.map +1 -1
- package/lib/typescript/src/tts/streaming.d.ts.map +1 -1
- package/lib/typescript/src/tts/types.d.ts +6 -5
- package/lib/typescript/src/tts/types.d.ts.map +1 -1
- package/lib/typescript/src/utils.d.ts +5 -0
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/package.json +6 -1
- package/scripts/{check-model-csvs.sh → ci/check-model-csvs.sh} +9 -2
- package/scripts/ci/collect_all_sherpa_model_streams.sh +101 -0
- package/scripts/ci/collect_one_sherpa_release_stream.sh +189 -0
- package/scripts/ci/sherpa_asr_model_release_streams.json +21 -0
- package/scripts/ci/sherpa_tts_model_release_streams.json +13 -0
- package/scripts/ci/update_model_license_csv.sh +765 -0
- package/scripts/setup-ios-framework.sh +14 -11
- package/scripts/update_commercial_use.js +73 -0
- package/src/NativeSherpaOnnx.ts +36 -5
- package/src/audio/index.ts +20 -0
- package/src/download/ModelDownloadManager.ts +55 -1343
- package/src/download/activeModelOperations.ts +38 -0
- package/src/download/background-downloader.d.ts +43 -0
- package/src/download/bulkPurge.ts +102 -0
- package/src/download/checksumPrompt.ts +25 -0
- package/src/download/constants.ts +5 -0
- package/src/download/downloadEvents.ts +55 -0
- package/src/download/downloadTask.ts +497 -0
- package/src/download/ensureModel.ts +124 -0
- package/src/download/index.ts +19 -4
- package/src/download/localModels.ts +234 -0
- package/src/download/modelExtraction.ts +244 -0
- package/src/download/paths.ts +134 -0
- package/src/download/postDownloadProcessing.ts +292 -0
- package/src/download/protectedModelKeys.ts +30 -0
- package/src/download/registry.ts +404 -0
- package/src/download/retry.ts +76 -0
- package/src/download/types.ts +120 -0
- package/src/download/validation.ts +114 -8
- package/src/{download → extraction}/extractTarBz2.ts +3 -1
- package/src/{download → extraction}/extractTarZst.ts +3 -1
- package/src/extraction/index.ts +3 -7
- package/src/index.tsx +1 -0
- package/src/licenses.ts +100 -0
- package/src/stt/index.ts +20 -2
- package/src/stt/streaming.ts +3 -0
- package/src/stt/streamingTypes.ts +5 -0
- package/src/stt/types.ts +3 -1
- package/src/tts/index.ts +30 -2
- package/src/tts/streaming.ts +10 -0
- package/src/tts/types.ts +6 -5
- package/src/utils.ts +22 -1
- package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
- package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +0 -301
- package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +0 -187
- package/lib/module/download/extractTarBz2.js.map +0 -1
- package/lib/module/download/extractTarZst.js.map +0 -1
- package/lib/typescript/src/download/extractTarBz2.d.ts.map +0 -1
- package/lib/typescript/src/download/extractTarZst.d.ts.map +0 -1
- package/scripts/check-qnn-support.sh +0 -78
- /package/lib/typescript/src/{download → extraction}/extractTarBz2.d.ts +0 -0
- /package/lib/typescript/src/{download → extraction}/extractTarZst.d.ts +0 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
exists,
|
|
3
|
+
mkdir,
|
|
4
|
+
writeFile,
|
|
5
|
+
stat,
|
|
6
|
+
unlink,
|
|
7
|
+
} from '@dr.pogodin/react-native-fs';
|
|
8
|
+
import type {
|
|
9
|
+
ModelCategory,
|
|
10
|
+
ModelMetaBase,
|
|
11
|
+
ModelManifest,
|
|
12
|
+
ChecksumIssue,
|
|
13
|
+
DownloadProgress,
|
|
14
|
+
} from './types';
|
|
15
|
+
import {
|
|
16
|
+
getReadyMarkerPath,
|
|
17
|
+
getManifestPath,
|
|
18
|
+
getExtractionStatePath,
|
|
19
|
+
} from './paths';
|
|
20
|
+
import {
|
|
21
|
+
validateChecksum,
|
|
22
|
+
validateExtractedFiles,
|
|
23
|
+
resolveActualModelDir,
|
|
24
|
+
} from './validation';
|
|
25
|
+
import { extractTarBz2 } from '../extraction/extractTarBz2';
|
|
26
|
+
import { promptChecksumFallback } from './checksumPrompt';
|
|
27
|
+
import { emitDownloadProgress, emitModelsListUpdated } from './downloadEvents';
|
|
28
|
+
import type { DownloadResult } from './types';
|
|
29
|
+
import {
|
|
30
|
+
registerActivePostProcess,
|
|
31
|
+
unregisterActivePostProcess,
|
|
32
|
+
} from './activeModelOperations';
|
|
33
|
+
|
|
34
|
+
export type RunPostDownloadProcessingOptions = {
|
|
35
|
+
category: ModelCategory;
|
|
36
|
+
id: string;
|
|
37
|
+
model: ModelMetaBase;
|
|
38
|
+
downloadPath: string;
|
|
39
|
+
modelDir: string;
|
|
40
|
+
isArchive: boolean;
|
|
41
|
+
statePath: string;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
onChecksumIssue?: (issue: ChecksumIssue) => Promise<boolean>;
|
|
44
|
+
deleteArchiveAfterExtract?: boolean;
|
|
45
|
+
onProgress?: (progress: DownloadProgress) => void;
|
|
46
|
+
/** Called to get current list of downloaded models for emitModelsListUpdated. */
|
|
47
|
+
getDownloadedList: () => Promise<ModelMetaBase[]>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export async function runPostDownloadProcessing(
|
|
51
|
+
options: RunPostDownloadProcessingOptions
|
|
52
|
+
): Promise<DownloadResult> {
|
|
53
|
+
const {
|
|
54
|
+
category,
|
|
55
|
+
id,
|
|
56
|
+
model,
|
|
57
|
+
downloadPath,
|
|
58
|
+
modelDir,
|
|
59
|
+
isArchive,
|
|
60
|
+
statePath,
|
|
61
|
+
signal,
|
|
62
|
+
onChecksumIssue,
|
|
63
|
+
deleteArchiveAfterExtract,
|
|
64
|
+
onProgress,
|
|
65
|
+
getDownloadedList,
|
|
66
|
+
} = options;
|
|
67
|
+
|
|
68
|
+
registerActivePostProcess(category, id);
|
|
69
|
+
try {
|
|
70
|
+
return await runPostDownloadProcessingBody({
|
|
71
|
+
category,
|
|
72
|
+
id,
|
|
73
|
+
model,
|
|
74
|
+
downloadPath,
|
|
75
|
+
modelDir,
|
|
76
|
+
isArchive,
|
|
77
|
+
statePath,
|
|
78
|
+
signal,
|
|
79
|
+
onChecksumIssue,
|
|
80
|
+
deleteArchiveAfterExtract,
|
|
81
|
+
onProgress,
|
|
82
|
+
getDownloadedList,
|
|
83
|
+
});
|
|
84
|
+
} finally {
|
|
85
|
+
unregisterActivePostProcess(category, id);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function runPostDownloadProcessingBody(
|
|
90
|
+
options: RunPostDownloadProcessingOptions
|
|
91
|
+
): Promise<DownloadResult> {
|
|
92
|
+
const {
|
|
93
|
+
category,
|
|
94
|
+
id,
|
|
95
|
+
model,
|
|
96
|
+
downloadPath,
|
|
97
|
+
modelDir,
|
|
98
|
+
isArchive,
|
|
99
|
+
statePath,
|
|
100
|
+
signal,
|
|
101
|
+
onChecksumIssue,
|
|
102
|
+
deleteArchiveAfterExtract,
|
|
103
|
+
onProgress,
|
|
104
|
+
getDownloadedList,
|
|
105
|
+
} = options;
|
|
106
|
+
|
|
107
|
+
const isAborted = () => Boolean(signal?.aborted);
|
|
108
|
+
const abortError = new Error('Download aborted');
|
|
109
|
+
abortError.name = 'AbortError';
|
|
110
|
+
|
|
111
|
+
if (signal?.aborted) throw abortError;
|
|
112
|
+
|
|
113
|
+
let extractResult: { sha256?: string } | null = null;
|
|
114
|
+
let extractedTotalBytes = 0;
|
|
115
|
+
|
|
116
|
+
if (isArchive) {
|
|
117
|
+
try {
|
|
118
|
+
const archiveStat = await stat(downloadPath);
|
|
119
|
+
if (model.bytes > 0 && archiveStat.size < model.bytes) {
|
|
120
|
+
console.warn(
|
|
121
|
+
`[Download] Archive truncated for ${category}:${id}: ${archiveStat.size}/${model.bytes} bytes. Deleting for re-download.`
|
|
122
|
+
);
|
|
123
|
+
await unlink(downloadPath);
|
|
124
|
+
throw new Error(
|
|
125
|
+
`Archive file is truncated (${archiveStat.size}/${model.bytes} bytes). Please retry the download.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
} catch (statErr) {
|
|
129
|
+
if (statErr instanceof Error && statErr.message.includes('truncated'))
|
|
130
|
+
throw statErr;
|
|
131
|
+
}
|
|
132
|
+
await mkdir(modelDir);
|
|
133
|
+
const extractionStatePath = getExtractionStatePath(category, id);
|
|
134
|
+
try {
|
|
135
|
+
await writeFile(
|
|
136
|
+
extractionStatePath,
|
|
137
|
+
JSON.stringify({
|
|
138
|
+
modelId: id,
|
|
139
|
+
category,
|
|
140
|
+
phase: 'extracting' as const,
|
|
141
|
+
startedAt: new Date().toISOString(),
|
|
142
|
+
archivePath: downloadPath,
|
|
143
|
+
modelDir,
|
|
144
|
+
model,
|
|
145
|
+
}),
|
|
146
|
+
'utf8'
|
|
147
|
+
);
|
|
148
|
+
} catch {
|
|
149
|
+
// non-fatal; resume after crash may not be possible for this run
|
|
150
|
+
}
|
|
151
|
+
extractResult = await extractTarBz2(
|
|
152
|
+
downloadPath,
|
|
153
|
+
modelDir,
|
|
154
|
+
true,
|
|
155
|
+
(evt) => {
|
|
156
|
+
if (isAborted()) return;
|
|
157
|
+
if (evt.totalBytes > 0) extractedTotalBytes = evt.totalBytes;
|
|
158
|
+
const progress: DownloadProgress = {
|
|
159
|
+
bytesDownloaded: evt.bytes,
|
|
160
|
+
totalBytes: evt.totalBytes,
|
|
161
|
+
percent: evt.percent,
|
|
162
|
+
phase: 'extracting',
|
|
163
|
+
};
|
|
164
|
+
onProgress?.(progress);
|
|
165
|
+
emitDownloadProgress(category, id, progress);
|
|
166
|
+
},
|
|
167
|
+
signal
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (model.sha256) {
|
|
172
|
+
const expectedSha = model.sha256.toLowerCase();
|
|
173
|
+
let issue: ChecksumIssue | null = null;
|
|
174
|
+
if (isArchive) {
|
|
175
|
+
const nativeSha = extractResult?.sha256?.toLowerCase();
|
|
176
|
+
if (!nativeSha) {
|
|
177
|
+
issue = {
|
|
178
|
+
category,
|
|
179
|
+
id,
|
|
180
|
+
archivePath: downloadPath,
|
|
181
|
+
expected: model.sha256,
|
|
182
|
+
message: 'Native SHA-256 not available after extraction.',
|
|
183
|
+
reason: 'CHECKSUM_FAILED',
|
|
184
|
+
};
|
|
185
|
+
} else if (nativeSha !== expectedSha) {
|
|
186
|
+
issue = {
|
|
187
|
+
category,
|
|
188
|
+
id,
|
|
189
|
+
archivePath: downloadPath,
|
|
190
|
+
expected: model.sha256,
|
|
191
|
+
message: `Checksum mismatch: expected ${model.sha256}, got ${extractResult?.sha256}`,
|
|
192
|
+
reason: 'CHECKSUM_MISMATCH',
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
const checksumResult = await validateChecksum(downloadPath, expectedSha);
|
|
197
|
+
if (!checksumResult.success) {
|
|
198
|
+
issue = {
|
|
199
|
+
category,
|
|
200
|
+
id,
|
|
201
|
+
archivePath: downloadPath,
|
|
202
|
+
expected: model.sha256,
|
|
203
|
+
message: checksumResult.message ?? 'Checksum validation failed.',
|
|
204
|
+
reason:
|
|
205
|
+
checksumResult.error === 'CHECKSUM_MISMATCH'
|
|
206
|
+
? 'CHECKSUM_MISMATCH'
|
|
207
|
+
: 'CHECKSUM_FAILED',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (issue) {
|
|
212
|
+
const keepFile = onChecksumIssue
|
|
213
|
+
? await onChecksumIssue(issue)
|
|
214
|
+
: await promptChecksumFallback(issue);
|
|
215
|
+
if (!keepFile) {
|
|
216
|
+
if (await exists(modelDir)) await unlink(modelDir);
|
|
217
|
+
if (await exists(downloadPath)) await unlink(downloadPath);
|
|
218
|
+
throw new Error(`Checksum validation failed: ${issue.message}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (signal?.aborted) throw abortError;
|
|
224
|
+
|
|
225
|
+
const filesValidation = await validateExtractedFiles(modelDir, category);
|
|
226
|
+
if (!filesValidation.success) {
|
|
227
|
+
await unlink(modelDir);
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Extracted files validation failed: ${filesValidation.message}`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
await writeFile(getReadyMarkerPath(category, id), 'ready', 'utf8');
|
|
234
|
+
const now = new Date().toISOString();
|
|
235
|
+
let sizeOnDisk: number | undefined;
|
|
236
|
+
if (isArchive && extractedTotalBytes > 0) {
|
|
237
|
+
sizeOnDisk = extractedTotalBytes;
|
|
238
|
+
} else if (!isArchive) {
|
|
239
|
+
try {
|
|
240
|
+
const s = await stat(downloadPath);
|
|
241
|
+
sizeOnDisk = s.size;
|
|
242
|
+
} catch {
|
|
243
|
+
// ignore
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
await writeFile(
|
|
247
|
+
getManifestPath(category, id),
|
|
248
|
+
JSON.stringify({
|
|
249
|
+
downloadedAt: now,
|
|
250
|
+
lastUsed: now,
|
|
251
|
+
model,
|
|
252
|
+
sizeOnDisk,
|
|
253
|
+
} as ModelManifest),
|
|
254
|
+
'utf8'
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
if (await exists(statePath)) await unlink(statePath);
|
|
259
|
+
} catch {
|
|
260
|
+
// non-fatal
|
|
261
|
+
}
|
|
262
|
+
if (isArchive) {
|
|
263
|
+
try {
|
|
264
|
+
const extractionStatePath = getExtractionStatePath(category, id);
|
|
265
|
+
if (
|
|
266
|
+
extractionStatePath !== statePath &&
|
|
267
|
+
(await exists(extractionStatePath))
|
|
268
|
+
) {
|
|
269
|
+
await unlink(extractionStatePath);
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
// non-fatal
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (isArchive && deleteArchiveAfterExtract !== false) {
|
|
277
|
+
try {
|
|
278
|
+
if (await exists(downloadPath)) await unlink(downloadPath);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
console.warn(
|
|
281
|
+
`[Download] Failed to delete archive after extraction for ${category}:${id}:`,
|
|
282
|
+
err instanceof Error ? err.message : String(err)
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const list = await getDownloadedList();
|
|
288
|
+
emitModelsListUpdated(category, list);
|
|
289
|
+
|
|
290
|
+
const resolvedPath = await resolveActualModelDir(modelDir);
|
|
291
|
+
return { modelId: id, localPath: resolvedPath };
|
|
292
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getExistingDownloadTasks } from '@kesha-antonov/react-native-background-downloader';
|
|
2
|
+
import { getActivePostProcessKeys } from './activeModelOperations';
|
|
3
|
+
import { getActiveDownloadTaskKeys } from './downloadTask';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Model keys (`category:modelId`) that must not be removed by bulk delete: active JS download tasks,
|
|
7
|
+
* native background-downloader tasks, and models in post-download processing (extraction / validation).
|
|
8
|
+
*/
|
|
9
|
+
export async function getProtectedModelKeysForBulkDelete(): Promise<
|
|
10
|
+
ReadonlySet<string>
|
|
11
|
+
> {
|
|
12
|
+
const set = new Set<string>();
|
|
13
|
+
for (const k of getActiveDownloadTaskKeys()) {
|
|
14
|
+
set.add(k);
|
|
15
|
+
}
|
|
16
|
+
for (const k of getActivePostProcessKeys()) {
|
|
17
|
+
set.add(k);
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const existing = await getExistingDownloadTasks();
|
|
21
|
+
for (const t of existing) {
|
|
22
|
+
if (t.id && typeof t.id === 'string') {
|
|
23
|
+
set.add(t.id);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// ignore — still return JS/post-process protection
|
|
28
|
+
}
|
|
29
|
+
return set;
|
|
30
|
+
}
|