pinokiod 7.4.0 → 7.4.1
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 +9 -791
- package/kernel/procs.js +1 -1
- package/package.json +2 -3
- package/server/views/app.ejs +11 -8
- package/test/procs.test.js +49 -0
- package/script/verify-ffmpeg.js +0 -459
package/kernel/procs.js
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinokiod",
|
|
3
|
-
"version": "7.4.
|
|
3
|
+
"version": "7.4.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"download_readme": "wget -O kernel/proto/PINOKIO.md https://raw.githubusercontent.com/pinokiocomputer/home/refs/heads/main/docs/README.md",
|
|
8
|
-
"start": "node script/index"
|
|
9
|
-
"verify:ffmpeg": "node script/verify-ffmpeg.js"
|
|
8
|
+
"start": "node script/index"
|
|
10
9
|
},
|
|
11
10
|
"author": "",
|
|
12
11
|
"license": "MIT",
|
package/server/views/app.ejs
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
<% if (agent === "electron") { %>
|
|
20
20
|
<link href="/electron.css" rel="stylesheet"/>
|
|
21
21
|
<% } %>
|
|
22
|
+
<% const appMobileBreakpointPx = 980 %>
|
|
22
23
|
<style>
|
|
23
24
|
:root {
|
|
24
25
|
--assist-surface-light: var(--pinokio-chrome-accent-bg-light);
|
|
@@ -6169,7 +6170,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
6169
6170
|
}
|
|
6170
6171
|
}
|
|
6171
6172
|
*/
|
|
6172
|
-
@media only screen and (max-width:
|
|
6173
|
+
@media only screen and (max-width: <%= appMobileBreakpointPx %>px) {
|
|
6173
6174
|
body {
|
|
6174
6175
|
display: flex !important;
|
|
6175
6176
|
flex-direction: row !important;
|
|
@@ -6410,7 +6411,7 @@ header.navheader h1 {
|
|
|
6410
6411
|
margin: 0 10px;
|
|
6411
6412
|
}
|
|
6412
6413
|
}
|
|
6413
|
-
@media only screen and (max-width:
|
|
6414
|
+
@media only screen and (max-width: <%= appMobileBreakpointPx %>px) {
|
|
6414
6415
|
:root {
|
|
6415
6416
|
--mobile-bottom-bar-height: calc(46px + env(safe-area-inset-bottom));
|
|
6416
6417
|
}
|
|
@@ -8361,6 +8362,10 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
8361
8362
|
let pendingHomeSelectionRetry = null
|
|
8362
8363
|
let initialWorkspaceDiskUsageRequested = false
|
|
8363
8364
|
const openWithoutLaunching = <%- JSON.stringify(type === "run" && !autoselect) %>
|
|
8365
|
+
const appMobileBreakpoint = <%= appMobileBreakpointPx %>
|
|
8366
|
+
const appMobileBreakpointQuery = `(max-width: ${appMobileBreakpoint}px)`
|
|
8367
|
+
window.PinokioAppMobileBreakpoint = appMobileBreakpoint
|
|
8368
|
+
window.PinokioAppMobileBreakpointQuery = appMobileBreakpointQuery
|
|
8364
8369
|
const scheduleSelectionRetry = (delay = 100) => {
|
|
8365
8370
|
if (pendingSelectionRetry !== null) {
|
|
8366
8371
|
return
|
|
@@ -11097,14 +11102,12 @@ const rerenderMenuSection = (container, html) => {
|
|
|
11097
11102
|
}
|
|
11098
11103
|
|
|
11099
11104
|
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
const mobileMenuQuery = window.matchMedia ? window.matchMedia("(max-width: 768px)") : null
|
|
11105
|
+
const mobileMenuQuery = window.matchMedia ? window.matchMedia(appMobileBreakpointQuery) : null
|
|
11103
11106
|
const isMobileMenuOpen = () => document.body.classList.contains("mobile-menu-open")
|
|
11104
11107
|
const appcanvas = document.querySelector(".appcanvas")
|
|
11105
11108
|
const closeWindowButton = document.querySelector("#close-window")
|
|
11106
11109
|
const mobileMenuBackdrop = document.querySelector("[data-mobile-menu-backdrop]")
|
|
11107
|
-
const isMobilePanelLayout = () => mobileMenuQuery ? mobileMenuQuery.matches : window.innerWidth <=
|
|
11110
|
+
const isMobilePanelLayout = () => mobileMenuQuery ? mobileMenuQuery.matches : window.innerWidth <= appMobileBreakpoint
|
|
11108
11111
|
const normalizeMobilePanelName = (value) => {
|
|
11109
11112
|
return value === "logs" || value === "ask-ai" || value === "feed" ? value : ""
|
|
11110
11113
|
}
|
|
@@ -11844,7 +11847,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
11844
11847
|
if (appcanvas && sidebarResizer && sidebarContainer) {
|
|
11845
11848
|
const SIDEBAR_MIN_WIDTH = 140
|
|
11846
11849
|
const SIDEBAR_MAX_WIDTH = 560
|
|
11847
|
-
const sidebarMobileQuery = window.matchMedia ? window.matchMedia(
|
|
11850
|
+
const sidebarMobileQuery = window.matchMedia ? window.matchMedia(appMobileBreakpointQuery) : null
|
|
11848
11851
|
const workspaceName = "<%= typeof name === 'string' ? name : '' %>"
|
|
11849
11852
|
const sidebarWidthStorageKey = workspaceName
|
|
11850
11853
|
? `pinokio-app-sidebar-width:${workspaceName}`
|
|
@@ -17862,7 +17865,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
17862
17865
|
enabled = false
|
|
17863
17866
|
}
|
|
17864
17867
|
|
|
17865
|
-
const communityModeQuery = window.matchMedia ? window.matchMedia("(max-width:
|
|
17868
|
+
const communityModeQuery = window.matchMedia ? window.matchMedia(window.PinokioAppMobileBreakpointQuery || "(max-width: <%= appMobileBreakpointPx %>px)") : null
|
|
17866
17869
|
let communityMode = false
|
|
17867
17870
|
|
|
17868
17871
|
const setCommunityMode = (next, opts) => {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const assert = require("node:assert/strict")
|
|
2
|
+
const os = require("node:os")
|
|
3
|
+
const test = require("node:test")
|
|
4
|
+
|
|
5
|
+
const procsPath = require.resolve("../kernel/procs")
|
|
6
|
+
|
|
7
|
+
function loadProcsForPlatform(platform) {
|
|
8
|
+
const originalPlatform = os.platform
|
|
9
|
+
delete require.cache[procsPath]
|
|
10
|
+
os.platform = () => platform
|
|
11
|
+
try {
|
|
12
|
+
return require("../kernel/procs")
|
|
13
|
+
} finally {
|
|
14
|
+
os.platform = originalPlatform
|
|
15
|
+
delete require.cache[procsPath]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
test("Windows process parser only probes listening TCP rows", async () => {
|
|
20
|
+
const Procs = loadProcsForPlatform("win32")
|
|
21
|
+
const procs = new Procs({})
|
|
22
|
+
const probed = []
|
|
23
|
+
|
|
24
|
+
procs.isHttp = async (host, port) => {
|
|
25
|
+
probed.push(`${host}:${port}`)
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const stdout = [
|
|
30
|
+
" Proto Local Address Foreign Address State PID",
|
|
31
|
+
" TCP 127.0.0.1:5173 0.0.0.0:0 LISTENING 1111",
|
|
32
|
+
" TCP 127.0.0.1:49153 127.0.0.1:5173 ESTABLISHED 2222",
|
|
33
|
+
" TCP 0.0.0.0:7860 0.0.0.0:0 LISTENING 3333",
|
|
34
|
+
" TCP [::1]:11434 [::]:0 LISTENING 4444"
|
|
35
|
+
].join("\n")
|
|
36
|
+
|
|
37
|
+
const results = await procs.get_pids(stdout)
|
|
38
|
+
|
|
39
|
+
assert.deepEqual(probed, [
|
|
40
|
+
"127.0.0.1:5173",
|
|
41
|
+
"0.0.0.0:7860",
|
|
42
|
+
"::1:11434"
|
|
43
|
+
])
|
|
44
|
+
assert.deepEqual(results.map((item) => `${item.pid}:${item.ip}`), [
|
|
45
|
+
"1111:127.0.0.1:5173",
|
|
46
|
+
"3333:0.0.0.0:7860",
|
|
47
|
+
"4444:[::1]:11434"
|
|
48
|
+
])
|
|
49
|
+
})
|
package/script/verify-ffmpeg.js
DELETED
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const crypto = require("crypto")
|
|
4
|
-
const fs = require("fs")
|
|
5
|
-
const os = require("os")
|
|
6
|
-
const path = require("path")
|
|
7
|
-
const { spawn } = require("child_process")
|
|
8
|
-
const Kernel = require("../kernel")
|
|
9
|
-
|
|
10
|
-
function parseArgs(argv) {
|
|
11
|
-
const options = {
|
|
12
|
-
home: process.env.PINOKIO_HOME || path.resolve(process.cwd(), ".pinokio"),
|
|
13
|
-
reinstall: false,
|
|
14
|
-
skipInstall: false,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
18
|
-
const arg = argv[i]
|
|
19
|
-
if (arg === "--home" && argv[i + 1]) {
|
|
20
|
-
options.home = path.resolve(argv[i + 1])
|
|
21
|
-
i += 1
|
|
22
|
-
} else if (arg === "--reinstall") {
|
|
23
|
-
options.reinstall = true
|
|
24
|
-
} else if (arg === "--skip-install") {
|
|
25
|
-
options.skipInstall = true
|
|
26
|
-
} else if (arg === "--help" || arg === "-h") {
|
|
27
|
-
options.help = true
|
|
28
|
-
} else {
|
|
29
|
-
throw new Error(`Unknown argument: ${arg}`)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return options
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function usage() {
|
|
37
|
-
return [
|
|
38
|
-
"Usage: node script/verify-ffmpeg.js [--home <PINOKIO_HOME>] [--reinstall] [--skip-install]",
|
|
39
|
-
"",
|
|
40
|
-
"--reinstall remove and reinstall FFmpeg before verification",
|
|
41
|
-
"--skip-install only verify the current install state",
|
|
42
|
-
].join("\n")
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function logOnData(event) {
|
|
46
|
-
if (!event) {
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
if (typeof event.raw === "string") {
|
|
50
|
-
process.stdout.write(event.raw)
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
if (typeof event.html === "string") {
|
|
54
|
-
process.stdout.write(`${event.html.replace(/<[^>]+>/g, "")}\n`)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function mergeEnv(baseEnv, overlay) {
|
|
59
|
-
const env = { ...baseEnv }
|
|
60
|
-
for (const [key, value] of Object.entries(overlay || {})) {
|
|
61
|
-
if (Array.isArray(value)) {
|
|
62
|
-
const prefix = value.filter(Boolean).join(path.delimiter)
|
|
63
|
-
if (prefix.length === 0) {
|
|
64
|
-
continue
|
|
65
|
-
}
|
|
66
|
-
env[key] = env[key] ? `${prefix}${path.delimiter}${env[key]}` : prefix
|
|
67
|
-
} else if (value === undefined || value === null) {
|
|
68
|
-
delete env[key]
|
|
69
|
-
} else {
|
|
70
|
-
env[key] = String(value)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return env
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function normalizePathForCompare(value) {
|
|
77
|
-
return String(value || "")
|
|
78
|
-
.replace(/\\/g, "/")
|
|
79
|
-
.replace(/\/+$/, "")
|
|
80
|
-
.toLowerCase()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function assert(condition, message) {
|
|
84
|
-
if (!condition) {
|
|
85
|
-
throw new Error(message)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function exists(target) {
|
|
90
|
-
try {
|
|
91
|
-
await fs.promises.access(target)
|
|
92
|
-
return true
|
|
93
|
-
} catch (error) {
|
|
94
|
-
return false
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function runCommand(command, args, options = {}) {
|
|
99
|
-
return await new Promise((resolve, reject) => {
|
|
100
|
-
const child = spawn(command, args, {
|
|
101
|
-
cwd: options.cwd,
|
|
102
|
-
env: options.env,
|
|
103
|
-
windowsHide: true,
|
|
104
|
-
shell: false,
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
let stdout = ""
|
|
108
|
-
let stderr = ""
|
|
109
|
-
child.stdout.on("data", (chunk) => {
|
|
110
|
-
const text = chunk.toString()
|
|
111
|
-
stdout += text
|
|
112
|
-
if (options.stream) {
|
|
113
|
-
process.stdout.write(text)
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
child.stderr.on("data", (chunk) => {
|
|
117
|
-
const text = chunk.toString()
|
|
118
|
-
stderr += text
|
|
119
|
-
if (options.stream) {
|
|
120
|
-
process.stderr.write(text)
|
|
121
|
-
}
|
|
122
|
-
})
|
|
123
|
-
child.on("error", reject)
|
|
124
|
-
child.on("close", (code) => {
|
|
125
|
-
if (code === 0) {
|
|
126
|
-
resolve({ stdout, stderr, code })
|
|
127
|
-
} else {
|
|
128
|
-
reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}\n${stdout}${stderr}`))
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function prefixedValue(output, prefix) {
|
|
135
|
-
const line = String(output || "").split(/\r?\n/).find((entry) => entry.startsWith(prefix))
|
|
136
|
-
if (!line) {
|
|
137
|
-
return ""
|
|
138
|
-
}
|
|
139
|
-
return line.slice(prefix.length)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function sectionValues(output, beginMarker, endMarker) {
|
|
143
|
-
const lines = String(output || "").split(/\r?\n/)
|
|
144
|
-
const begin = lines.findIndex((line) => line.trim() === beginMarker)
|
|
145
|
-
const end = lines.findIndex((line, index) => index > begin && line.trim() === endMarker)
|
|
146
|
-
if (begin === -1 || end === -1 || end <= begin) {
|
|
147
|
-
return []
|
|
148
|
-
}
|
|
149
|
-
return lines.slice(begin + 1, end).map((line) => line.trim()).filter(Boolean)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async function verifyHookFiles(ffmpeg) {
|
|
153
|
-
const hookFiles = ffmpeg.activationHookFiles()
|
|
154
|
-
for (const file of hookFiles) {
|
|
155
|
-
assert(await exists(file.path), `Missing activation hook: ${file.path}`)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async function verifyWindowsPatchedCache(ffmpeg) {
|
|
160
|
-
if (ffmpeg.kernel.platform !== "win32") {
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const pkgsDir = ffmpeg.ffmpegPkgsDir()
|
|
165
|
-
const entries = await fs.promises.readdir(pkgsDir, { withFileTypes: true })
|
|
166
|
-
const packageDirs = entries
|
|
167
|
-
.filter((entry) => entry.isDirectory() && /^gdk-pixbuf-/.test(entry.name))
|
|
168
|
-
.map((entry) => path.resolve(pkgsDir, entry.name))
|
|
169
|
-
|
|
170
|
-
assert(packageDirs.length > 0, `No gdk-pixbuf package found under ${pkgsDir}`)
|
|
171
|
-
|
|
172
|
-
for (const packageDir of packageDirs) {
|
|
173
|
-
const scriptPath = path.resolve(packageDir, "Scripts", ".gdk-pixbuf-post-link.bat")
|
|
174
|
-
assert(await exists(scriptPath), `Missing patched gdk-pixbuf script: ${scriptPath}`)
|
|
175
|
-
|
|
176
|
-
const contents = await fs.promises.readFile(scriptPath)
|
|
177
|
-
assert(
|
|
178
|
-
contents.toString("utf8").includes("Pinokio intentionally skips gdk-pixbuf loader cache generation"),
|
|
179
|
-
`Unexpected gdk-pixbuf post-link contents in ${scriptPath}`
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
const pathsJsonPath = path.resolve(packageDir, "info", "paths.json")
|
|
183
|
-
const pathsJson = JSON.parse(await fs.promises.readFile(pathsJsonPath, "utf8"))
|
|
184
|
-
const entry = Array.isArray(pathsJson.paths)
|
|
185
|
-
? pathsJson.paths.find((item) => item && item._path === "Scripts/.gdk-pixbuf-post-link.bat")
|
|
186
|
-
: null
|
|
187
|
-
|
|
188
|
-
assert(entry, `Missing paths.json entry for patched gdk-pixbuf script in ${pathsJsonPath}`)
|
|
189
|
-
assert(entry.size_in_bytes === contents.length, `paths.json size mismatch for ${scriptPath}`)
|
|
190
|
-
|
|
191
|
-
const sha256 = crypto.createHash("sha256").update(contents).digest("hex")
|
|
192
|
-
assert(entry.sha256 === sha256, `paths.json sha256 mismatch for ${scriptPath}`)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
async function verifyPosixRuntime(ffmpeg, condaEnv) {
|
|
197
|
-
const shell = "/bin/bash"
|
|
198
|
-
const env = mergeEnv(process.env, condaEnv)
|
|
199
|
-
const expectedFfmpeg = ffmpeg.binaryPath("ffmpeg")
|
|
200
|
-
const expectedFfprobe = ffmpeg.binaryPath("ffprobe")
|
|
201
|
-
const expectedBinDir = path.dirname(expectedFfmpeg)
|
|
202
|
-
const expectedLibDir = ffmpeg.libraryDir()
|
|
203
|
-
|
|
204
|
-
const command = [
|
|
205
|
-
"set -e",
|
|
206
|
-
'eval "$(conda shell.bash hook)"',
|
|
207
|
-
"conda deactivate || true",
|
|
208
|
-
"conda deactivate || true",
|
|
209
|
-
"conda deactivate || true",
|
|
210
|
-
"conda activate base",
|
|
211
|
-
'printf "__FFMPEG__%s\\n" "$(command -v ffmpeg)"',
|
|
212
|
-
'printf "__FFPROBE__%s\\n" "$(command -v ffprobe)"',
|
|
213
|
-
'printf "__FFMPEG_PATH__%s\\n" "${FFMPEG_PATH-}"',
|
|
214
|
-
'printf "__FFPROBE_PATH__%s\\n" "${FFPROBE_PATH-}"',
|
|
215
|
-
'printf "__PATH__%s\\n" "$PATH"',
|
|
216
|
-
ffmpeg.kernel.platform === "linux"
|
|
217
|
-
? 'printf "__LD_LIBRARY_PATH__%s\\n" "${LD_LIBRARY_PATH-}"'
|
|
218
|
-
: 'printf "__LD_LIBRARY_PATH__%s\\n" "${LD_LIBRARY_PATH-}"',
|
|
219
|
-
"ffmpeg -hide_banner -version | head -n 1",
|
|
220
|
-
"ffprobe -hide_banner -version | head -n 1",
|
|
221
|
-
"ffmpeg -hide_banner -encoders | grep -q libmp3lame",
|
|
222
|
-
].join(" && ")
|
|
223
|
-
|
|
224
|
-
const { stdout } = await runCommand(shell, ["-lc", command], { env, stream: true })
|
|
225
|
-
const ffmpegResolved = prefixedValue(stdout, "__FFMPEG__")
|
|
226
|
-
const ffprobeResolved = prefixedValue(stdout, "__FFPROBE__")
|
|
227
|
-
const ffmpegPathEnv = prefixedValue(stdout, "__FFMPEG_PATH__")
|
|
228
|
-
const ffprobePathEnv = prefixedValue(stdout, "__FFPROBE_PATH__")
|
|
229
|
-
const shellPath = prefixedValue(stdout, "__PATH__")
|
|
230
|
-
const ldLibraryPath = prefixedValue(stdout, "__LD_LIBRARY_PATH__")
|
|
231
|
-
|
|
232
|
-
assert(
|
|
233
|
-
normalizePathForCompare(ffmpegResolved) === normalizePathForCompare(expectedFfmpeg),
|
|
234
|
-
`bash resolved ffmpeg to ${ffmpegResolved}, expected ${expectedFfmpeg}`
|
|
235
|
-
)
|
|
236
|
-
assert(
|
|
237
|
-
normalizePathForCompare(ffprobeResolved) === normalizePathForCompare(expectedFfprobe),
|
|
238
|
-
`bash resolved ffprobe to ${ffprobeResolved}, expected ${expectedFfprobe}`
|
|
239
|
-
)
|
|
240
|
-
assert(
|
|
241
|
-
normalizePathForCompare(ffmpegPathEnv) === normalizePathForCompare(expectedFfmpeg),
|
|
242
|
-
`FFMPEG_PATH was ${ffmpegPathEnv}, expected ${expectedFfmpeg}`
|
|
243
|
-
)
|
|
244
|
-
assert(
|
|
245
|
-
normalizePathForCompare(ffprobePathEnv) === normalizePathForCompare(expectedFfprobe),
|
|
246
|
-
`FFPROBE_PATH was ${ffprobePathEnv}, expected ${expectedFfprobe}`
|
|
247
|
-
)
|
|
248
|
-
assert(
|
|
249
|
-
shellPath.split(":").map((entry) => normalizePathForCompare(entry))[0] === normalizePathForCompare(expectedBinDir),
|
|
250
|
-
`PATH does not start with FFmpeg bin dir: ${expectedBinDir}`
|
|
251
|
-
)
|
|
252
|
-
if (ffmpeg.kernel.platform === "linux") {
|
|
253
|
-
assert(
|
|
254
|
-
ldLibraryPath.split(":").map((entry) => normalizePathForCompare(entry))[0] === normalizePathForCompare(expectedLibDir),
|
|
255
|
-
`LD_LIBRARY_PATH does not start with FFmpeg lib dir: ${expectedLibDir}`
|
|
256
|
-
)
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
async function verifyWindowsCmdRuntime(ffmpeg, condaEnv) {
|
|
261
|
-
const env = mergeEnv(process.env, condaEnv)
|
|
262
|
-
const expectedFfmpeg = ffmpeg.binaryPath("ffmpeg")
|
|
263
|
-
const expectedFfprobe = ffmpeg.binaryPath("ffprobe")
|
|
264
|
-
const expectedRuntimeDir = ffmpeg.libraryDir()
|
|
265
|
-
|
|
266
|
-
const command = [
|
|
267
|
-
"conda_hook",
|
|
268
|
-
"conda deactivate",
|
|
269
|
-
"conda deactivate",
|
|
270
|
-
"conda deactivate",
|
|
271
|
-
[
|
|
272
|
-
"conda activate base",
|
|
273
|
-
"echo __FFMPEG_PATH__%FFMPEG_PATH%",
|
|
274
|
-
"echo __FFPROBE_PATH__%FFPROBE_PATH%",
|
|
275
|
-
"echo __PATH__%PATH%",
|
|
276
|
-
"echo __FFMPEG_BEGIN__",
|
|
277
|
-
"where ffmpeg",
|
|
278
|
-
"echo __FFMPEG_END__",
|
|
279
|
-
"echo __FFPROBE_BEGIN__",
|
|
280
|
-
"where ffprobe",
|
|
281
|
-
"echo __FFPROBE_END__",
|
|
282
|
-
"ffmpeg -hide_banner -version",
|
|
283
|
-
"ffprobe -hide_banner -version",
|
|
284
|
-
'ffmpeg -hide_banner -encoders | findstr /C:"libmp3lame"',
|
|
285
|
-
].join(" && "),
|
|
286
|
-
].join(" & ")
|
|
287
|
-
|
|
288
|
-
const shell = process.env.ComSpec || "cmd.exe"
|
|
289
|
-
const { stdout } = await runCommand(shell, ["/d", "/s", "/c", command], { env, stream: true })
|
|
290
|
-
|
|
291
|
-
const ffmpegPathEnv = prefixedValue(stdout, "__FFMPEG_PATH__")
|
|
292
|
-
const ffprobePathEnv = prefixedValue(stdout, "__FFPROBE_PATH__")
|
|
293
|
-
const shellPath = prefixedValue(stdout, "__PATH__")
|
|
294
|
-
const ffmpegResolved = sectionValues(stdout, "__FFMPEG_BEGIN__", "__FFMPEG_END__")[0]
|
|
295
|
-
const ffprobeResolved = sectionValues(stdout, "__FFPROBE_BEGIN__", "__FFPROBE_END__")[0]
|
|
296
|
-
|
|
297
|
-
assert(
|
|
298
|
-
normalizePathForCompare(ffmpegResolved) === normalizePathForCompare(expectedFfmpeg),
|
|
299
|
-
`cmd resolved ffmpeg to ${ffmpegResolved}, expected ${expectedFfmpeg}`
|
|
300
|
-
)
|
|
301
|
-
assert(
|
|
302
|
-
normalizePathForCompare(ffprobeResolved) === normalizePathForCompare(expectedFfprobe),
|
|
303
|
-
`cmd resolved ffprobe to ${ffprobeResolved}, expected ${expectedFfprobe}`
|
|
304
|
-
)
|
|
305
|
-
assert(
|
|
306
|
-
normalizePathForCompare(ffmpegPathEnv) === normalizePathForCompare(expectedFfmpeg),
|
|
307
|
-
`FFMPEG_PATH was ${ffmpegPathEnv}, expected ${expectedFfmpeg}`
|
|
308
|
-
)
|
|
309
|
-
assert(
|
|
310
|
-
normalizePathForCompare(ffprobePathEnv) === normalizePathForCompare(expectedFfprobe),
|
|
311
|
-
`FFPROBE_PATH was ${ffprobePathEnv}, expected ${expectedFfprobe}`
|
|
312
|
-
)
|
|
313
|
-
assert(
|
|
314
|
-
shellPath.split(";").map((entry) => normalizePathForCompare(entry))[0] === normalizePathForCompare(expectedRuntimeDir),
|
|
315
|
-
`PATH does not start with FFmpeg runtime dir: ${expectedRuntimeDir}`
|
|
316
|
-
)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
async function verifyWindowsPowerShellRuntime(ffmpeg, condaEnv) {
|
|
320
|
-
const env = mergeEnv(process.env, condaEnv)
|
|
321
|
-
const expectedFfmpeg = ffmpeg.binaryPath("ffmpeg")
|
|
322
|
-
const expectedFfprobe = ffmpeg.binaryPath("ffprobe")
|
|
323
|
-
const expectedRuntimeDir = ffmpeg.libraryDir()
|
|
324
|
-
|
|
325
|
-
const script = [
|
|
326
|
-
"$ErrorActionPreference = 'Stop'",
|
|
327
|
-
"conda_hook",
|
|
328
|
-
"conda deactivate",
|
|
329
|
-
"conda deactivate",
|
|
330
|
-
"conda deactivate",
|
|
331
|
-
"conda activate base",
|
|
332
|
-
'Write-Output ("__FFMPEG_PATH__" + $Env:FFMPEG_PATH)',
|
|
333
|
-
'Write-Output ("__FFPROBE_PATH__" + $Env:FFPROBE_PATH)',
|
|
334
|
-
'Write-Output ("__PATH__" + $Env:Path)',
|
|
335
|
-
'Write-Output ("__FFMPEG__" + (Get-Command ffmpeg).Source)',
|
|
336
|
-
'Write-Output ("__FFPROBE__" + (Get-Command ffprobe).Source)',
|
|
337
|
-
"ffmpeg -hide_banner -version | Select-Object -First 1",
|
|
338
|
-
"ffprobe -hide_banner -version | Select-Object -First 1",
|
|
339
|
-
"if (-not (ffmpeg -hide_banner -encoders | Select-String -SimpleMatch 'libmp3lame')) { exit 1 }",
|
|
340
|
-
].join("; ")
|
|
341
|
-
|
|
342
|
-
const shell = process.env.SystemRoot
|
|
343
|
-
? path.resolve(process.env.SystemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
344
|
-
: "powershell.exe"
|
|
345
|
-
const { stdout } = await runCommand(shell, ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", script], { env, stream: true })
|
|
346
|
-
|
|
347
|
-
const ffmpegResolved = prefixedValue(stdout, "__FFMPEG__")
|
|
348
|
-
const ffprobeResolved = prefixedValue(stdout, "__FFPROBE__")
|
|
349
|
-
const ffmpegPathEnv = prefixedValue(stdout, "__FFMPEG_PATH__")
|
|
350
|
-
const ffprobePathEnv = prefixedValue(stdout, "__FFPROBE_PATH__")
|
|
351
|
-
const shellPath = prefixedValue(stdout, "__PATH__")
|
|
352
|
-
|
|
353
|
-
assert(
|
|
354
|
-
normalizePathForCompare(ffmpegResolved) === normalizePathForCompare(expectedFfmpeg),
|
|
355
|
-
`PowerShell resolved ffmpeg to ${ffmpegResolved}, expected ${expectedFfmpeg}`
|
|
356
|
-
)
|
|
357
|
-
assert(
|
|
358
|
-
normalizePathForCompare(ffprobeResolved) === normalizePathForCompare(expectedFfprobe),
|
|
359
|
-
`PowerShell resolved ffprobe to ${ffprobeResolved}, expected ${expectedFfprobe}`
|
|
360
|
-
)
|
|
361
|
-
assert(
|
|
362
|
-
normalizePathForCompare(ffmpegPathEnv) === normalizePathForCompare(expectedFfmpeg),
|
|
363
|
-
`PowerShell FFMPEG_PATH was ${ffmpegPathEnv}, expected ${expectedFfmpeg}`
|
|
364
|
-
)
|
|
365
|
-
assert(
|
|
366
|
-
normalizePathForCompare(ffprobePathEnv) === normalizePathForCompare(expectedFfprobe),
|
|
367
|
-
`PowerShell FFPROBE_PATH was ${ffprobePathEnv}, expected ${expectedFfprobe}`
|
|
368
|
-
)
|
|
369
|
-
assert(
|
|
370
|
-
shellPath.split(";").map((entry) => normalizePathForCompare(entry))[0] === normalizePathForCompare(expectedRuntimeDir),
|
|
371
|
-
`PowerShell PATH does not start with FFmpeg runtime dir: ${expectedRuntimeDir}`
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
async function main() {
|
|
376
|
-
const options = parseArgs(process.argv.slice(2))
|
|
377
|
-
if (options.help) {
|
|
378
|
-
console.log(usage())
|
|
379
|
-
return
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
process.env.PINOKIO_HOME = options.home
|
|
383
|
-
console.log(`[verify-ffmpeg] home=${options.home}`)
|
|
384
|
-
console.log(`[verify-ffmpeg] platform=${os.platform()} arch=${os.arch()}`)
|
|
385
|
-
|
|
386
|
-
const kernel = new Kernel({ store: {} })
|
|
387
|
-
await kernel.init({})
|
|
388
|
-
await kernel.shell.init()
|
|
389
|
-
await kernel.bin.init()
|
|
390
|
-
await kernel.bin.refreshInstalled()
|
|
391
|
-
|
|
392
|
-
if (kernel.refresh_interval) {
|
|
393
|
-
clearInterval(kernel.refresh_interval)
|
|
394
|
-
}
|
|
395
|
-
kernel.server_running = true
|
|
396
|
-
|
|
397
|
-
const conda = kernel.bin.mod("conda")
|
|
398
|
-
const ffmpeg = kernel.bin.mod("ffmpeg")
|
|
399
|
-
|
|
400
|
-
assert(conda, "Conda module was not initialized")
|
|
401
|
-
assert(ffmpeg, "FFmpeg module was not initialized")
|
|
402
|
-
|
|
403
|
-
if (!kernel.bin.installed.conda || !(await conda.installed())) {
|
|
404
|
-
console.log("[verify-ffmpeg] installing conda")
|
|
405
|
-
await kernel.bin.install({
|
|
406
|
-
params: [
|
|
407
|
-
{
|
|
408
|
-
name: "conda",
|
|
409
|
-
dependencies: [],
|
|
410
|
-
}
|
|
411
|
-
]
|
|
412
|
-
}, logOnData)
|
|
413
|
-
await kernel.bin.refreshInstalled()
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (!options.skipInstall) {
|
|
417
|
-
const ffmpegInstalled = await ffmpeg.installed()
|
|
418
|
-
if (options.reinstall && ffmpegInstalled) {
|
|
419
|
-
console.log("[verify-ffmpeg] reinstall requested, removing existing ffmpeg")
|
|
420
|
-
await ffmpeg.uninstall({}, logOnData)
|
|
421
|
-
await kernel.bin.refreshInstalled()
|
|
422
|
-
}
|
|
423
|
-
if (options.reinstall || !(await ffmpeg.installed())) {
|
|
424
|
-
console.log("[verify-ffmpeg] installing ffmpeg")
|
|
425
|
-
await kernel.bin.install({
|
|
426
|
-
params: [
|
|
427
|
-
{
|
|
428
|
-
name: "ffmpeg",
|
|
429
|
-
}
|
|
430
|
-
]
|
|
431
|
-
}, logOnData)
|
|
432
|
-
await kernel.bin.refreshInstalled()
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
assert(await ffmpeg.installed(), "FFmpeg module did not report installed after setup")
|
|
437
|
-
await ffmpeg.selfTest(logOnData)
|
|
438
|
-
await verifyHookFiles(ffmpeg)
|
|
439
|
-
await verifyWindowsPatchedCache(ffmpeg)
|
|
440
|
-
|
|
441
|
-
const condaEnv = conda.env()
|
|
442
|
-
if (kernel.platform === "win32") {
|
|
443
|
-
console.log("[verify-ffmpeg] verifying cmd.exe runtime")
|
|
444
|
-
await verifyWindowsCmdRuntime(ffmpeg, condaEnv)
|
|
445
|
-
console.log("[verify-ffmpeg] verifying PowerShell runtime")
|
|
446
|
-
await verifyWindowsPowerShellRuntime(ffmpeg, condaEnv)
|
|
447
|
-
} else {
|
|
448
|
-
console.log("[verify-ffmpeg] verifying bash runtime")
|
|
449
|
-
await verifyPosixRuntime(ffmpeg, condaEnv)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
console.log("[verify-ffmpeg] all checks passed")
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
main().catch((error) => {
|
|
456
|
-
console.error("[verify-ffmpeg] failed")
|
|
457
|
-
console.error(error && error.stack ? error.stack : error)
|
|
458
|
-
process.exit(1)
|
|
459
|
-
})
|