pinokiod 7.2.0 → 7.2.4
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/kernel/bin/ffmpeg.js
CHANGED
|
@@ -1,13 +1,83 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const
|
|
3
|
-
const {
|
|
4
|
-
const
|
|
1
|
+
const fs = require("fs")
|
|
2
|
+
const path = require("path")
|
|
3
|
+
const { execFile } = require("child_process")
|
|
4
|
+
const ParcelWatcher = require("@parcel/watcher")
|
|
5
|
+
const semver = require("semver")
|
|
6
|
+
const { rimraf } = require("rimraf")
|
|
7
|
+
|
|
8
|
+
const RELEASE_VERSION = "8.0.1"
|
|
9
|
+
const RELEASE_RANGE = ">=8.0.1 <8.1.0"
|
|
10
|
+
const CONDA_SPEC = `ffmpeg=${RELEASE_VERSION}`
|
|
11
|
+
|
|
12
|
+
const WINDOWS_GDK_PIXBUF_POST_LINK_NOOP = `@echo off
|
|
13
|
+
rem Pinokio intentionally skips gdk-pixbuf loader cache generation for FFmpeg installs.
|
|
14
|
+
exit /b 0
|
|
15
|
+
`
|
|
16
|
+
|
|
5
17
|
class Ffmpeg {
|
|
6
18
|
description = "Installs FFmpeg for audio and video processing."
|
|
19
|
+
|
|
7
20
|
cmd() {
|
|
8
|
-
return
|
|
21
|
+
return CONDA_SPEC
|
|
9
22
|
}
|
|
23
|
+
|
|
24
|
+
env(kernel) {
|
|
25
|
+
const activeKernel = kernel || this.kernel
|
|
26
|
+
const env = {
|
|
27
|
+
FFMPEG_PATH: this.binaryPath("ffmpeg", activeKernel),
|
|
28
|
+
FFPROBE_PATH: this.binaryPath("ffprobe", activeKernel)
|
|
29
|
+
}
|
|
30
|
+
if (activeKernel.platform === "linux") {
|
|
31
|
+
env.LD_LIBRARY_PATH = [this.libraryDir(activeKernel)]
|
|
32
|
+
}
|
|
33
|
+
return env
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
binaryPath(tool, kernel = this.kernel) {
|
|
37
|
+
const filename = kernel.platform === "win32" ? `${tool}.exe` : tool
|
|
38
|
+
if (kernel.platform === "win32") {
|
|
39
|
+
return kernel.bin.path("miniconda", "Library", "bin", filename)
|
|
40
|
+
}
|
|
41
|
+
return kernel.bin.path("miniconda", "bin", filename)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
libraryDir(kernel = this.kernel) {
|
|
45
|
+
if (kernel.platform === "win32") {
|
|
46
|
+
return kernel.bin.path("miniconda", "Library", "bin")
|
|
47
|
+
}
|
|
48
|
+
return kernel.bin.path("miniconda", "lib")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
legacyStandalonePaths() {
|
|
52
|
+
return [
|
|
53
|
+
this.kernel.bin.path("ffmpeg"),
|
|
54
|
+
this.kernel.bin.path("ffmpeg-tmp")
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async start() {
|
|
59
|
+
if (this.kernel.platform !== "darwin") {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
if (!this.isInstalledVersion()) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
await this.syncMacUvLibraryShims()
|
|
66
|
+
await this.startMacUvLibraryWatcher()
|
|
67
|
+
}
|
|
68
|
+
|
|
10
69
|
async install(req, ondata) {
|
|
70
|
+
await this.cleanupLegacyStandalone(ondata)
|
|
71
|
+
if (this.kernel.platform === "win32") {
|
|
72
|
+
await this.installWindows(ondata)
|
|
73
|
+
} else {
|
|
74
|
+
await this.installStandard(ondata)
|
|
75
|
+
}
|
|
76
|
+
await this.syncMacUvLibraryShims(ondata)
|
|
77
|
+
await this.selfTest(ondata)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async installStandard(ondata) {
|
|
11
81
|
await this.kernel.bin.exec({
|
|
12
82
|
message: [
|
|
13
83
|
"conda clean -y --all",
|
|
@@ -15,20 +85,391 @@ class Ffmpeg {
|
|
|
15
85
|
]
|
|
16
86
|
}, ondata)
|
|
17
87
|
}
|
|
88
|
+
|
|
89
|
+
async installWindows(ondata) {
|
|
90
|
+
await this.kernel.bin.exec({
|
|
91
|
+
message: [
|
|
92
|
+
"conda clean -y --all",
|
|
93
|
+
`conda install -y --download-only -c conda-forge ${this.cmd()}`
|
|
94
|
+
]
|
|
95
|
+
}, ondata)
|
|
96
|
+
|
|
97
|
+
await this.patchWindowsGdkPixbufPostLink(ondata)
|
|
98
|
+
|
|
99
|
+
await this.kernel.bin.exec({
|
|
100
|
+
message: `conda install -y --offline -c conda-forge ${this.cmd()}`
|
|
101
|
+
}, ondata)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async patchWindowsGdkPixbufPostLink(ondata) {
|
|
105
|
+
const pkgsDir = this.kernel.bin.path("miniconda", "pkgs")
|
|
106
|
+
const entries = await fs.promises.readdir(pkgsDir, { withFileTypes: true })
|
|
107
|
+
const packageDirs = entries
|
|
108
|
+
.filter((entry) => entry.isDirectory() && /^gdk-pixbuf-/.test(entry.name))
|
|
109
|
+
.map((entry) => path.resolve(pkgsDir, entry.name))
|
|
110
|
+
|
|
111
|
+
if (packageDirs.length === 0) {
|
|
112
|
+
throw new Error("Could not find downloaded gdk-pixbuf package in the Conda cache after --download-only")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let patchedCount = 0
|
|
116
|
+
for (const packageDir of packageDirs) {
|
|
117
|
+
const scripts = [
|
|
118
|
+
path.resolve(packageDir, "Scripts", ".gdk-pixbuf-post-link.bat"),
|
|
119
|
+
path.resolve(packageDir, "info", "recipe", "post-link.bat")
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
for (const script of scripts) {
|
|
123
|
+
try {
|
|
124
|
+
await fs.promises.access(script)
|
|
125
|
+
await fs.promises.writeFile(script, WINDOWS_GDK_PIXBUF_POST_LINK_NOOP)
|
|
126
|
+
patchedCount += 1
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error && error.code !== "ENOENT") {
|
|
129
|
+
throw error
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (patchedCount === 0) {
|
|
136
|
+
throw new Error("Found gdk-pixbuf in the Conda cache, but did not find any post-link scripts to patch")
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
ondata({ raw: `patched ${patchedCount} gdk-pixbuf post-link script(s) in the Conda cache...\r\n` })
|
|
140
|
+
}
|
|
141
|
+
|
|
18
142
|
async installed() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let version = this.kernel.bin.installed.conda_versions.ffmpeg
|
|
22
|
-
if (version !== "7.0.2") {
|
|
143
|
+
try {
|
|
144
|
+
if (!this.isInstalledVersion()) {
|
|
23
145
|
return false
|
|
24
146
|
}
|
|
147
|
+
|
|
148
|
+
await fs.promises.access(this.binaryPath("ffmpeg"))
|
|
149
|
+
await fs.promises.access(this.binaryPath("ffprobe"))
|
|
150
|
+
await this.syncMacUvLibraryShims()
|
|
151
|
+
await this.startMacUvLibraryWatcher()
|
|
152
|
+
await this.selfTest()
|
|
153
|
+
return true
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.log("conda ffmpeg installed check failed", error && error.message ? error.message : error)
|
|
156
|
+
return false
|
|
25
157
|
}
|
|
26
|
-
return this.kernel.bin.installed.conda.has("ffmpeg")
|
|
27
158
|
}
|
|
159
|
+
|
|
28
160
|
async uninstall(req, ondata) {
|
|
161
|
+
await this.stopMacUvLibraryWatcher()
|
|
162
|
+
await this.removeMacUvLibraryShims(ondata)
|
|
29
163
|
await this.kernel.bin.exec({
|
|
30
|
-
message: "conda remove ffmpeg"
|
|
164
|
+
message: "conda remove -y ffmpeg"
|
|
31
165
|
}, ondata)
|
|
166
|
+
await this.cleanupLegacyStandalone(ondata)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
isInstalledVersion() {
|
|
170
|
+
if (!this.kernel.bin.installed?.conda?.has("ffmpeg")) {
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
return this.kernel.bin.installed?.conda_versions?.ffmpeg === RELEASE_VERSION
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async cleanupLegacyStandalone(ondata) {
|
|
177
|
+
for (const target of this.legacyStandalonePaths()) {
|
|
178
|
+
const exists = await fs.promises.access(target).then(() => true).catch(() => false)
|
|
179
|
+
if (exists) {
|
|
180
|
+
if (ondata) {
|
|
181
|
+
ondata({ raw: `removing legacy standalone ffmpeg files from ${target}...\r\n` })
|
|
182
|
+
}
|
|
183
|
+
await rimraf(target)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
uvPythonRoot(kernel = this.kernel) {
|
|
189
|
+
return kernel.path("cache", "XDG_DATA_HOME", "uv", "python")
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async startMacUvLibraryWatcher() {
|
|
193
|
+
if (this.kernel.platform !== "darwin" || this.macUvLibraryWatcher) {
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const root = this.uvPythonRoot()
|
|
198
|
+
await fs.promises.mkdir(root, { recursive: true })
|
|
199
|
+
this.macUvLibraryWatcher = await ParcelWatcher.subscribe(root, (error, events) => {
|
|
200
|
+
if (error) {
|
|
201
|
+
console.warn("ffmpeg uv library watcher error", error && error.message ? error.message : error)
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
if (!events || events.length === 0) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
this.scheduleMacUvLibraryShimSync()
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async stopMacUvLibraryWatcher() {
|
|
212
|
+
if (this.macUvLibraryShimSyncTimer) {
|
|
213
|
+
clearTimeout(this.macUvLibraryShimSyncTimer)
|
|
214
|
+
this.macUvLibraryShimSyncTimer = null
|
|
215
|
+
}
|
|
216
|
+
if (this.macUvLibraryWatcher) {
|
|
217
|
+
await this.macUvLibraryWatcher.unsubscribe()
|
|
218
|
+
this.macUvLibraryWatcher = null
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
scheduleMacUvLibraryShimSync() {
|
|
223
|
+
if (this.macUvLibraryShimSyncTimer) {
|
|
224
|
+
clearTimeout(this.macUvLibraryShimSyncTimer)
|
|
225
|
+
}
|
|
226
|
+
this.macUvLibraryShimSyncTimer = setTimeout(async () => {
|
|
227
|
+
this.macUvLibraryShimSyncTimer = null
|
|
228
|
+
try {
|
|
229
|
+
await this.syncMacUvLibraryShims()
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.warn("ffmpeg uv library shim sync error", error && error.message ? error.message : error)
|
|
232
|
+
}
|
|
233
|
+
}, 250)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async uvLibraryDirs(kernel = this.kernel) {
|
|
237
|
+
if (kernel.platform !== "darwin") {
|
|
238
|
+
return []
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const root = this.uvPythonRoot(kernel)
|
|
242
|
+
const entries = await fs.promises.readdir(root, { withFileTypes: true }).catch(() => [])
|
|
243
|
+
const dirs = []
|
|
244
|
+
|
|
245
|
+
for (const entry of entries) {
|
|
246
|
+
if (!entry.isDirectory()) {
|
|
247
|
+
continue
|
|
248
|
+
}
|
|
249
|
+
const libDir = path.resolve(root, entry.name, "lib")
|
|
250
|
+
const exists = await fs.promises.access(libDir).then(() => true).catch(() => false)
|
|
251
|
+
if (exists) {
|
|
252
|
+
dirs.push(libDir)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return dirs
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async ffmpegLibraryFiles(kernel = this.kernel) {
|
|
260
|
+
if (kernel.platform !== "darwin") {
|
|
261
|
+
return []
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const dir = this.libraryDir(kernel)
|
|
265
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true }).catch(() => [])
|
|
266
|
+
return entries
|
|
267
|
+
.filter((entry) => entry.isFile() || entry.isSymbolicLink())
|
|
268
|
+
.map((entry) => entry.name)
|
|
269
|
+
.filter((name) => /^lib(?:av|sw)[^.]+(?:\.\d+)*\.dylib$/i.test(name))
|
|
270
|
+
.sort()
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async syncMacUvLibraryShims(ondata) {
|
|
274
|
+
if (this.kernel.platform !== "darwin") {
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const [libraryDirs, libraryFiles] = await Promise.all([
|
|
279
|
+
this.uvLibraryDirs(),
|
|
280
|
+
this.ffmpegLibraryFiles()
|
|
281
|
+
])
|
|
282
|
+
|
|
283
|
+
if (libraryDirs.length === 0 || libraryFiles.length === 0) {
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let createdCount = 0
|
|
288
|
+
let refreshedCount = 0
|
|
289
|
+
const sourceDir = this.libraryDir()
|
|
290
|
+
|
|
291
|
+
for (const libDir of libraryDirs) {
|
|
292
|
+
for (const filename of libraryFiles) {
|
|
293
|
+
const source = path.resolve(sourceDir, filename)
|
|
294
|
+
const target = path.resolve(libDir, filename)
|
|
295
|
+
const desiredLink = path.relative(libDir, source)
|
|
296
|
+
|
|
297
|
+
let stat
|
|
298
|
+
try {
|
|
299
|
+
stat = await fs.promises.lstat(target)
|
|
300
|
+
} catch (error) {
|
|
301
|
+
if (!error || error.code !== "ENOENT") {
|
|
302
|
+
throw error
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!stat) {
|
|
307
|
+
await fs.promises.symlink(desiredLink, target)
|
|
308
|
+
createdCount += 1
|
|
309
|
+
continue
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!stat.isSymbolicLink()) {
|
|
313
|
+
continue
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const currentLink = await fs.promises.readlink(target)
|
|
317
|
+
if (currentLink === desiredLink) {
|
|
318
|
+
continue
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
await fs.promises.unlink(target)
|
|
322
|
+
await fs.promises.symlink(desiredLink, target)
|
|
323
|
+
refreshedCount += 1
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (ondata && (createdCount > 0 || refreshedCount > 0)) {
|
|
328
|
+
ondata({
|
|
329
|
+
raw: `synced ${createdCount + refreshedCount} FFmpeg dylib shim(s) into uv Python runtime libraries...\r\n`
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async removeMacUvLibraryShims(ondata) {
|
|
335
|
+
if (this.kernel.platform !== "darwin") {
|
|
336
|
+
return
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const [libraryDirs, libraryFiles] = await Promise.all([
|
|
340
|
+
this.uvLibraryDirs(),
|
|
341
|
+
this.ffmpegLibraryFiles()
|
|
342
|
+
])
|
|
343
|
+
|
|
344
|
+
if (libraryDirs.length === 0 || libraryFiles.length === 0) {
|
|
345
|
+
return
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const sourceDir = this.libraryDir()
|
|
349
|
+
let removedCount = 0
|
|
350
|
+
|
|
351
|
+
for (const libDir of libraryDirs) {
|
|
352
|
+
for (const filename of libraryFiles) {
|
|
353
|
+
const target = path.resolve(libDir, filename)
|
|
354
|
+
|
|
355
|
+
let stat
|
|
356
|
+
try {
|
|
357
|
+
stat = await fs.promises.lstat(target)
|
|
358
|
+
} catch (error) {
|
|
359
|
+
if (!error || error.code !== "ENOENT") {
|
|
360
|
+
throw error
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!stat || !stat.isSymbolicLink()) {
|
|
365
|
+
continue
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const currentLink = await fs.promises.readlink(target)
|
|
369
|
+
const resolved = path.resolve(libDir, currentLink)
|
|
370
|
+
if (path.dirname(resolved) !== sourceDir) {
|
|
371
|
+
continue
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
await fs.promises.unlink(target)
|
|
375
|
+
removedCount += 1
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (ondata && removedCount > 0) {
|
|
380
|
+
ondata({ raw: `removed ${removedCount} FFmpeg dylib shim(s) from uv Python runtime libraries...\r\n` })
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async selfTest(ondata) {
|
|
385
|
+
if (ondata) {
|
|
386
|
+
ondata({ raw: "verifying ffmpeg installation...\r\n" })
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const ffmpegVersionOutput = await this.execBinary(this.binaryPath("ffmpeg"), ["-version"])
|
|
390
|
+
const ffmpegVersion = semver.coerce(ffmpegVersionOutput)
|
|
391
|
+
if (!ffmpegVersion || !semver.satisfies(ffmpegVersion, RELEASE_RANGE)) {
|
|
392
|
+
throw new Error(`Unexpected ffmpeg version: ${this.firstLine(ffmpegVersionOutput)}`)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const encoderOutput = await this.execBinary(this.binaryPath("ffmpeg"), ["-hide_banner", "-encoders"])
|
|
396
|
+
if (!/\blibmp3lame\b/i.test(encoderOutput)) {
|
|
397
|
+
throw new Error("FFmpeg was installed without libmp3lame support")
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const ffprobeVersionOutput = await this.execBinary(this.binaryPath("ffprobe"), ["-version"])
|
|
401
|
+
const ffprobeVersion = semver.coerce(ffprobeVersionOutput)
|
|
402
|
+
if (!ffprobeVersion || !semver.satisfies(ffprobeVersion, RELEASE_RANGE)) {
|
|
403
|
+
throw new Error(`Unexpected ffprobe version: ${this.firstLine(ffprobeVersionOutput)}`)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
await this.assertSharedLibraries()
|
|
407
|
+
return true
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async assertSharedLibraries() {
|
|
411
|
+
const dir = this.libraryDir()
|
|
412
|
+
const entries = await fs.promises.readdir(dir).catch(() => {
|
|
413
|
+
throw new Error(`Missing FFmpeg library directory: ${dir}`)
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
const patterns = this.sharedLibraryPatterns()
|
|
417
|
+
for (const pattern of patterns) {
|
|
418
|
+
if (!entries.some((name) => pattern.test(name))) {
|
|
419
|
+
throw new Error(`Missing FFmpeg shared library matching ${pattern}`)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
sharedLibraryPatterns() {
|
|
425
|
+
if (this.kernel.platform === "win32") {
|
|
426
|
+
return [
|
|
427
|
+
/^avcodec-\d+\.dll$/i,
|
|
428
|
+
/^avformat-\d+\.dll$/i,
|
|
429
|
+
/^avutil-\d+\.dll$/i,
|
|
430
|
+
/^swresample-\d+\.dll$/i,
|
|
431
|
+
/^swscale-\d+\.dll$/i
|
|
432
|
+
]
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (this.kernel.platform === "darwin") {
|
|
436
|
+
return [
|
|
437
|
+
/^libavcodec(\.\d+)*\.dylib$/i,
|
|
438
|
+
/^libavformat(\.\d+)*\.dylib$/i,
|
|
439
|
+
/^libavutil(\.\d+)*\.dylib$/i,
|
|
440
|
+
/^libswresample(\.\d+)*\.dylib$/i,
|
|
441
|
+
/^libswscale(\.\d+)*\.dylib$/i
|
|
442
|
+
]
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return [
|
|
446
|
+
/^libavcodec\.so(\.\d+)*$/i,
|
|
447
|
+
/^libavformat\.so(\.\d+)*$/i,
|
|
448
|
+
/^libavutil\.so(\.\d+)*$/i,
|
|
449
|
+
/^libswresample\.so(\.\d+)*$/i,
|
|
450
|
+
/^libswscale\.so(\.\d+)*$/i
|
|
451
|
+
]
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
execBinary(file, args) {
|
|
455
|
+
return new Promise((resolve, reject) => {
|
|
456
|
+
execFile(file, args, {
|
|
457
|
+
windowsHide: true,
|
|
458
|
+
maxBuffer: 32 * 1024 * 1024
|
|
459
|
+
}, (error, stdout, stderr) => {
|
|
460
|
+
const output = `${stdout || ""}${stderr || ""}`
|
|
461
|
+
if (error) {
|
|
462
|
+
reject(new Error(output || error.message))
|
|
463
|
+
return
|
|
464
|
+
}
|
|
465
|
+
resolve(output)
|
|
466
|
+
})
|
|
467
|
+
})
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
firstLine(output) {
|
|
471
|
+
return String(output || "").split(/\r?\n/).find(Boolean) || ""
|
|
32
472
|
}
|
|
33
473
|
}
|
|
474
|
+
|
|
34
475
|
module.exports = Ffmpeg
|
package/kernel/bin/setup.js
CHANGED
|
@@ -14,7 +14,6 @@ module.exports = {
|
|
|
14
14
|
"node",
|
|
15
15
|
"huggingface",
|
|
16
16
|
"git",
|
|
17
|
-
"ffmpeg",
|
|
18
17
|
// "caddy"
|
|
19
18
|
]
|
|
20
19
|
if (platform !== "win32") {
|
|
@@ -184,7 +183,6 @@ module.exports = {
|
|
|
184
183
|
"node",
|
|
185
184
|
"huggingface",
|
|
186
185
|
"git",
|
|
187
|
-
"ffmpeg",
|
|
188
186
|
]
|
|
189
187
|
if (platform !== "win32") {
|
|
190
188
|
conda_requirements.push("tmux")
|
|
@@ -223,7 +221,6 @@ module.exports = {
|
|
|
223
221
|
"node",
|
|
224
222
|
"huggingface",
|
|
225
223
|
"git",
|
|
226
|
-
"ffmpeg",
|
|
227
224
|
"caddy",
|
|
228
225
|
]
|
|
229
226
|
if (platform === "win32") {
|
package/package.json
CHANGED
|
@@ -69,13 +69,13 @@ function escapeRegExp(value) {
|
|
|
69
69
|
function applyTemplateValues(template, values) {
|
|
70
70
|
let result = typeof template === "string" ? template : "";
|
|
71
71
|
if (!values || typeof values !== "object") {
|
|
72
|
-
return result;
|
|
72
|
+
return result.replace(/\r\n?/g, "\n");
|
|
73
73
|
}
|
|
74
74
|
Object.entries(values).forEach(([name, value]) => {
|
|
75
75
|
const pattern = new RegExp(`{{\\s*${escapeRegExp(name)}\\s*}}`, "g");
|
|
76
76
|
result = result.replace(pattern, value == null ? "" : String(value));
|
|
77
77
|
});
|
|
78
|
-
return result;
|
|
78
|
+
return result.replace(/\r\n?/g, "\n");
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function extractInputValues(source) {
|