@codearcade/subtitle-generator 1.0.1 → 1.0.3
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/init/index.js +86 -60
- package/package.json +1 -1
package/init/index.js
CHANGED
|
@@ -47,27 +47,35 @@ const init = async () => {
|
|
|
47
47
|
|
|
48
48
|
const file = fs.createWriteStream(dest);
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
50
|
+
// Wait for both the pipeTo AND the file stream to fully close
|
|
51
|
+
// so the file handle is released before we try to use the file.
|
|
52
|
+
await new Promise((resolve, reject) => {
|
|
53
|
+
file.on("close", resolve);
|
|
54
|
+
file.on("error", reject);
|
|
55
|
+
|
|
56
|
+
res.body.pipeTo(
|
|
57
|
+
new WritableStream({
|
|
58
|
+
write(chunk) {
|
|
59
|
+
downloaded += chunk.length;
|
|
60
|
+
if (total) {
|
|
61
|
+
const percent = ((downloaded / total) * 100).toFixed(2);
|
|
62
|
+
process.stdout.write(`Downloading ${label}... ${percent}%\r`);
|
|
63
|
+
} else {
|
|
64
|
+
process.stdout.write(`Downloaded ${downloaded} bytes\r`);
|
|
65
|
+
}
|
|
66
|
+
file.write(chunk);
|
|
67
|
+
},
|
|
68
|
+
close() {
|
|
69
|
+
file.end(); // triggers 'close' event on the file stream once flushed
|
|
70
|
+
console.log(`\n${label} download complete.`);
|
|
71
|
+
},
|
|
72
|
+
abort(err) {
|
|
73
|
+
file.destroy(err);
|
|
74
|
+
reject(err);
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
77
|
+
).catch(reject);
|
|
78
|
+
});
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
// 1. Download the AI Model
|
|
@@ -113,9 +121,6 @@ const init = async () => {
|
|
|
113
121
|
);
|
|
114
122
|
}
|
|
115
123
|
|
|
116
|
-
// https://github.com/ggml-org/whisper.cpp/releases/download/v1.8.4/whisper-bin-Win32.zip
|
|
117
|
-
// https://github.com/ggml-org/whisper.cpp/releases/v1.8.4/download/whisper-bin-Win32.zip
|
|
118
|
-
|
|
119
124
|
const zipUrl = `https://github.com/ggml-org/whisper.cpp/releases/download/v1.8.4/${zipName}`;
|
|
120
125
|
const zipPath = path.join(whisperDir, "whisper.zip");
|
|
121
126
|
|
|
@@ -123,48 +128,69 @@ const init = async () => {
|
|
|
123
128
|
|
|
124
129
|
console.log("Extracting binary...");
|
|
125
130
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
131
|
+
let extractionSuccess = false;
|
|
132
|
+
let maxRetries = 5;
|
|
133
|
+
let retryDelay = 1000; // 1 second
|
|
134
|
+
|
|
135
|
+
// 1. The Retry Loop for safe extraction
|
|
136
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
137
|
+
try {
|
|
138
|
+
execSync(
|
|
139
|
+
`powershell -command "Expand-Archive -Force -LiteralPath '${zipPath}' -DestinationPath '${whisperDir}'"`,
|
|
140
|
+
{ stdio: "inherit" },
|
|
141
|
+
);
|
|
142
|
+
extractionSuccess = true;
|
|
143
|
+
break; // It worked! Break out of the loop.
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (attempt === maxRetries) {
|
|
146
|
+
console.error(
|
|
147
|
+
`\nExtraction failed after ${maxRetries} attempts. File might be permanently locked or corrupted.`,
|
|
143
148
|
);
|
|
149
|
+
throw error;
|
|
144
150
|
}
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
console.log(
|
|
152
|
+
`\nFile locked by Windows (likely Antivirus). Retrying in 1 second... (Attempt ${attempt} of ${maxRetries})`,
|
|
153
|
+
);
|
|
154
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
147
155
|
}
|
|
156
|
+
}
|
|
148
157
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
// 2. The Cleanup Phase (Only runs if extraction worked)
|
|
159
|
+
if (extractionSuccess) {
|
|
160
|
+
try {
|
|
161
|
+
// Move everything out of the "Release" folder
|
|
162
|
+
const possibleReleaseDir = path.join(whisperDir, "Release");
|
|
163
|
+
|
|
164
|
+
if (fs.existsSync(possibleReleaseDir)) {
|
|
165
|
+
const files = fs.readdirSync(possibleReleaseDir);
|
|
166
|
+
|
|
167
|
+
for (const file of files) {
|
|
168
|
+
fs.renameSync(
|
|
169
|
+
path.join(possibleReleaseDir, file),
|
|
170
|
+
path.join(whisperDir, file),
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
// Delete the now-empty Release folder
|
|
174
|
+
fs.rmdirSync(possibleReleaseDir);
|
|
175
|
+
}
|
|
156
176
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
fs.
|
|
160
|
-
|
|
177
|
+
// Rename extracted main.exe to match our wrapper expectations
|
|
178
|
+
const extractedMain = path.join(whisperDir, "main.exe");
|
|
179
|
+
if (fs.existsSync(extractedMain)) {
|
|
180
|
+
fs.renameSync(extractedMain, binaryDest);
|
|
181
|
+
} else {
|
|
182
|
+
console.error("Warning: Could not find main.exe after extraction.");
|
|
183
|
+
}
|
|
161
184
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
// Clean up the zip file
|
|
186
|
+
if (fs.existsSync(zipPath)) {
|
|
187
|
+
fs.unlinkSync(zipPath);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log(`Whisper binary setup complete for Windows (${arch}).`);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error("Error during binary cleanup/renaming:", error.message);
|
|
193
|
+
}
|
|
168
194
|
}
|
|
169
195
|
} else {
|
|
170
196
|
console.log("Whisper binary already exists for Windows.");
|