pwebm 0.0.1-alpha.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-2025 4ndrs <andres.degozaru@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # pwebm
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.0.0. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
package/TODO.md ADDED
@@ -0,0 +1,55 @@
1
+ config, log -> there has to be a way to retrieve the config dir with env variable or some api
2
+ (socket) similar to purewebm; have to be in ~/.config/pwebm/config, ~/.config/pwebm/log
3
+ the socket file (if there is any) goes to /tmp
4
+
5
+ videos dir -> use ~/Videos/pwebm for consistency as default, but make it changeable through
6
+ the config file ASAP, way to many webms in PureWebM to move to another dir
7
+
8
+ filename -> use the unix timestamp with 16 digits (performance.now() + performance.timeOrigin)
9
+ the --name_type flag won't be ported
10
+
11
+ flags -> -v/--version, -h/--help, --status, --kill, -i, -subs, -c:v, -ss, -to, -lavfi,
12
+ --size_limit/-sl, -crf, -cpu-used, -deadline, --extra_params/-ep
13
+
14
+
15
+ some considerations:
16
+ - not being v1.0 permits for some leeway with breaking changes
17
+ - default size limit will be increased from 3 to 4
18
+ - if --status or --kill are used other flags will be ignored, consider maybe direct commands?
19
+ - current purewebm needs the start/end times in the metadata of the file to work no matter what
20
+ need to find a different way to get these, or at least not rely on them when they are set
21
+ manually
22
+ - it has to work with PureMPV (through pwebm-helper), tail log is nice but would be also nice
23
+ to have some kind of keybinding on the helper to show the status of the encoding on the mpv
24
+ window
25
+
26
+ ## Stuff
27
+
28
+ - [x] argument parser
29
+ - [x] expand tilde and $HOME in config video path
30
+ - [x] check for ffmpeg and ffprobe in path
31
+ - [x] convert webm, retry when limit reached
32
+ - [x] convert any other encoder to mkv copied streams just like purewebm
33
+ - [x] socket file for communication
34
+ - [x] handle queue
35
+ - [x] kill implementation
36
+ - [x] ffmpeg progress
37
+ - [x] status implementation
38
+ - [x] handle signals
39
+ - [x] name the process
40
+ - [x] version implementation
41
+ - [x] help implementation
42
+ - [ ] add automatic releases with github actions (edge + tagged)
43
+ - [ ] add bun bundled executable package releases to the automatic releases
44
+ - [ ] update readme
45
+ - [ ] add subs flag warning to the readme (how it works, output seeking needed, etc)
46
+ - [ ] release tagged versions in npm
47
+ - [ ] it's not part of this repo, but don't forget to improve the helper script for PureMPV (pwebm-helper), it has a missing readme
48
+
49
+ ### the following is just extra not implemented on purewebm but was its initial vision (can skip)
50
+ - [ ] implement conversion logger view (save previous conversions to db with last bitrate info)
51
+ - [ ] redo conversions in logger view
52
+ - [ ] add limit for the amount of tries to redo a conversion
53
+ - [ ] percentage bitrate offset when retrying a conversion with new calcs
54
+
55
+ ## 2025-03-03
package/bun.lock ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "pwebm",
6
+ "dependencies": {
7
+ "smol-toml": "^1.3.1",
8
+ "zod": "^3.24.2",
9
+ },
10
+ "devDependencies": {
11
+ "@types/bun": "^1.2.3",
12
+ "typescript": "^5.7.3",
13
+ },
14
+ },
15
+ },
16
+ "packages": {
17
+ "@types/bun": ["@types/bun@1.2.3", "", { "dependencies": { "bun-types": "1.2.3" } }, "sha512-054h79ipETRfjtsCW9qJK8Ipof67Pw9bodFWmkfkaUaRiIQ1dIV2VTlheshlBx3mpKr0KeK8VqnMMCtgN9rQtw=="],
18
+
19
+ "@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
20
+
21
+ "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
22
+
23
+ "bun-types": ["bun-types@1.2.3", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-P7AeyTseLKAvgaZqQrvp3RqFM3yN9PlcLuSTe7SoJOfZkER73mLdT2vEQi8U64S1YvM/ldcNiQjn0Sn7H9lGgg=="],
24
+
25
+ "smol-toml": ["smol-toml@1.3.1", "", {}, "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ=="],
26
+
27
+ "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
28
+
29
+ "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
30
+
31
+ "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
32
+ }
33
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "pwebm",
3
+ "version": "0.0.1-alpha.0",
4
+ "author": "4ndrs <andres.degozaru@gmail.com>",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/4ndrs/pwebm.git"
8
+ },
9
+ "module": "index.ts",
10
+ "devDependencies": {
11
+ "@types/bun": "^1.2.3",
12
+ "typescript": "^5.7.3"
13
+ },
14
+ "$schema": "https://json.schemastore.org/package.json",
15
+ "bin": {
16
+ "pwebm": "pwebm"
17
+ },
18
+ "bugs": {
19
+ "url": "git+https://github.com/4ndrs/pwebm/issues"
20
+ },
21
+ "description": "Utility to encode size restricted webm files with ffmpeg",
22
+ "homepage": "https://github.com/4ndrs/pwebm",
23
+ "license": "MIT",
24
+ "type": "module",
25
+ "dependencies": {
26
+ "smol-toml": "^1.3.1",
27
+ "zod": "^3.24.2"
28
+ }
29
+ }
package/pwebm ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ import "./src/main";
package/src/args.ts ADDED
@@ -0,0 +1,445 @@
1
+ import {
2
+ AUTHOR,
3
+ LICENSE,
4
+ VERSION,
5
+ HOMEPAGE,
6
+ CLI_NAME,
7
+ DESCRIPTION,
8
+ COPYRIGHT_YEAR,
9
+ } from "./constants";
10
+
11
+ import { ipc } from "./ipc";
12
+ import { config } from "./config";
13
+ import { logger } from "./logger";
14
+ import { ArgsSchema } from "./schema/args";
15
+
16
+ const RECOGNIZED_ARGS = [
17
+ "-h",
18
+ "--help",
19
+ "-v",
20
+ "--version",
21
+ "-kill",
22
+ "-status",
23
+ "-i",
24
+ "-ss",
25
+ "-to",
26
+ "-lavfi",
27
+ "-c:v",
28
+ "-deadline",
29
+ "-crf",
30
+ "-cpu-used",
31
+ "-subs",
32
+ "-sl",
33
+ "--size-limit",
34
+ "-ep",
35
+ "--extra-params",
36
+ "--video-path",
37
+ ];
38
+
39
+ export const parseArgs = async (args: string[]): Promise<ArgsSchema> => {
40
+ if (args.length === 0) {
41
+ printUsage();
42
+
43
+ // if the user isn't using any of the quick actions we require the -i flag
44
+ logger.error("Input file is required");
45
+
46
+ process.exit(1);
47
+ }
48
+
49
+ const rawArgs: Partial<ArgsSchema> = {};
50
+
51
+ let skip = false;
52
+ let isExtraParam = false;
53
+ let seeking: { startTime?: string; stopTime?: string } | undefined;
54
+
55
+ const skipNext = () => (skip = true);
56
+
57
+ for (let index = 0; index < args.length; index++) {
58
+ const arg = args[index];
59
+
60
+ if (skip) {
61
+ skip = false;
62
+ continue;
63
+ }
64
+
65
+ if (isExtraParam) {
66
+ rawArgs.extraParams?.push(arg);
67
+ continue;
68
+ }
69
+
70
+ if (arg.startsWith("-") && !RECOGNIZED_ARGS.includes(arg)) {
71
+ printUsage();
72
+
73
+ logger.error(`Unrecognized argument: ${arg}`);
74
+
75
+ process.exit(1);
76
+ }
77
+
78
+ if (["-h", "--help"].includes(arg)) {
79
+ printUsage();
80
+
81
+ process.exit();
82
+ }
83
+
84
+ if (["-v", "--version"].includes(arg)) {
85
+ logger.info(
86
+ `${CLI_NAME} version ${VERSION}\nCopyright (c) ${COPYRIGHT_YEAR} ${AUTHOR}\nLicensed under the ${LICENSE} License\n${HOMEPAGE}`,
87
+ { onlyConsole: true },
88
+ );
89
+ process.exit();
90
+ }
91
+
92
+ if (arg === "-kill") {
93
+ try {
94
+ await ipc.sendMessage({ type: "kill" });
95
+
96
+ logger.info("Main instance successfully killed", {
97
+ logToConsole: true,
98
+ });
99
+ } catch (error) {
100
+ if (
101
+ error instanceof Error &&
102
+ "code" in error &&
103
+ error.code !== "ENOENT"
104
+ ) {
105
+ logger.error("Couldn't kill the main instance");
106
+ }
107
+
108
+ process.exit(1);
109
+ }
110
+
111
+ process.exit();
112
+ }
113
+
114
+ if (arg === "-status") {
115
+ try {
116
+ const status = await ipc.sendMessage({ type: "status" });
117
+
118
+ logger.info(JSON.stringify(status, null, 2), { onlyConsole: true });
119
+
120
+ logger.info("Status printed to the screen");
121
+ } catch (error) {
122
+ if (
123
+ error instanceof Error &&
124
+ "code" in error &&
125
+ error.code !== "ENOENT"
126
+ ) {
127
+ logger.error("Couldn't get the status of the main instance");
128
+ }
129
+
130
+ process.exit(1);
131
+ }
132
+
133
+ process.exit();
134
+ }
135
+
136
+ if (!arg.startsWith("-") && !arg.startsWith("--")) {
137
+ if (rawArgs.output?.file) {
138
+ logger.error("Only one output file is allowed");
139
+
140
+ logger.debug(
141
+ `Current output file: ${rawArgs.output.file}, new file: ${arg}`,
142
+ );
143
+
144
+ process.exit(1);
145
+ }
146
+
147
+ if (!rawArgs.output) {
148
+ rawArgs.output = {};
149
+ }
150
+
151
+ rawArgs.output.file = arg;
152
+
153
+ continue;
154
+ }
155
+
156
+ if (arg === "-ss") {
157
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
158
+ logMissingArg(arg);
159
+
160
+ process.exit(1);
161
+ }
162
+
163
+ if (!seeking) {
164
+ seeking = {};
165
+ }
166
+
167
+ seeking.startTime = args[index + 1];
168
+
169
+ skipNext();
170
+
171
+ continue;
172
+ }
173
+
174
+ if (arg === "-to") {
175
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
176
+ logMissingArg(arg);
177
+
178
+ process.exit(1);
179
+ }
180
+
181
+ if (!seeking) {
182
+ seeking = {};
183
+ }
184
+
185
+ seeking.stopTime = args[index + 1];
186
+
187
+ skipNext();
188
+
189
+ continue;
190
+ }
191
+
192
+ if (arg === "-i") {
193
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
194
+ logMissingArg(arg);
195
+
196
+ process.exit(1);
197
+ }
198
+
199
+ if (!rawArgs.inputs) {
200
+ rawArgs.inputs = [];
201
+ }
202
+
203
+ rawArgs.inputs.push({
204
+ file: args[index + 1],
205
+ ...seeking,
206
+ });
207
+
208
+ seeking = undefined;
209
+
210
+ skipNext();
211
+
212
+ continue;
213
+ }
214
+
215
+ if (arg === "-subs") {
216
+ rawArgs.subs = true;
217
+
218
+ continue;
219
+ }
220
+
221
+ if (arg === "-sl" || arg === "--size-limit") {
222
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
223
+ logMissingArg(arg);
224
+
225
+ process.exit(1);
226
+ }
227
+
228
+ const sizeLimit = Number(args[index + 1]);
229
+
230
+ if (isNaN(sizeLimit)) {
231
+ logInvalidNumber(arg, sizeLimit);
232
+
233
+ process.exit(1);
234
+ }
235
+
236
+ rawArgs.sizeLimit = sizeLimit;
237
+
238
+ skipNext();
239
+
240
+ continue;
241
+ }
242
+
243
+ if (arg === "-ep" || arg === "--extra-params") {
244
+ if (args[index + 1] === undefined) {
245
+ logMissingArg(arg);
246
+
247
+ process.exit(1);
248
+ }
249
+
250
+ isExtraParam = true;
251
+
252
+ rawArgs.extraParams = [];
253
+
254
+ continue;
255
+ }
256
+
257
+ if (arg === "--video-path") {
258
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
259
+ logMissingArg(arg);
260
+
261
+ process.exit(1);
262
+ }
263
+
264
+ rawArgs.videoPath = args[index + 1];
265
+
266
+ skipNext();
267
+
268
+ continue;
269
+ }
270
+
271
+ if (arg === "-crf") {
272
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
273
+ logMissingArg(arg);
274
+
275
+ process.exit(1);
276
+ }
277
+
278
+ const crf = Number(args[index + 1]);
279
+
280
+ if (isNaN(crf)) {
281
+ logInvalidNumber(arg, crf);
282
+
283
+ process.exit(1);
284
+ }
285
+
286
+ rawArgs.crf = crf;
287
+
288
+ skipNext();
289
+
290
+ continue;
291
+ }
292
+
293
+ if (arg === "-cpu-used") {
294
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
295
+ logMissingArg(arg);
296
+
297
+ process.exit(1);
298
+ }
299
+
300
+ const cpuUsed = Number(args[index + 1]);
301
+
302
+ if (isNaN(cpuUsed)) {
303
+ logInvalidNumber(arg, cpuUsed);
304
+
305
+ process.exit(1);
306
+ }
307
+
308
+ if (ArgsSchema.shape.cpuUsed.safeParse(cpuUsed).success === false) {
309
+ logger.error(
310
+ `The ${arg} flag requires a number between 0 and 5 inclusive. "${cpuUsed}" is out of that range`,
311
+ );
312
+
313
+ process.exit(1);
314
+ }
315
+
316
+ rawArgs.cpuUsed = cpuUsed as 0 | 1 | 2 | 3 | 4 | 5;
317
+
318
+ skipNext();
319
+
320
+ continue;
321
+ }
322
+
323
+ if (arg === "-deadline") {
324
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
325
+ logMissingArg(arg);
326
+
327
+ process.exit(1);
328
+ }
329
+
330
+ if (!["good", "best"].includes(args[index + 1])) {
331
+ logger.error(
332
+ `The ${arg} flag requires either "good" or "best". "${args[index + 1]}" is not a valid value`,
333
+ );
334
+
335
+ process.exit(1);
336
+ }
337
+
338
+ rawArgs.deadline = args[index + 1] as "good" | "best";
339
+
340
+ skipNext();
341
+
342
+ continue;
343
+ }
344
+
345
+ if (arg === "-c:v") {
346
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
347
+ logMissingArg(arg);
348
+
349
+ process.exit(1);
350
+ }
351
+
352
+ rawArgs.encoder = args[index + 1];
353
+
354
+ skipNext();
355
+
356
+ continue;
357
+ }
358
+
359
+ if (arg === "-lavfi") {
360
+ if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
361
+ logMissingArg(arg);
362
+
363
+ process.exit(1);
364
+ }
365
+
366
+ rawArgs.lavfi = args[index + 1];
367
+
368
+ skipNext();
369
+
370
+ continue;
371
+ }
372
+ }
373
+
374
+ if (seeking) {
375
+ rawArgs.output = { ...rawArgs.output, ...seeking };
376
+
377
+ seeking = undefined;
378
+ }
379
+
380
+ const parsedArgs = ArgsSchema.safeParse(rawArgs);
381
+
382
+ if (!parsedArgs.success) {
383
+ logger.error("Error parsing the arguments");
384
+
385
+ logger.error(
386
+ JSON.stringify(parsedArgs.error.flatten().fieldErrors, null, 2),
387
+ );
388
+
389
+ process.exit(1);
390
+ }
391
+
392
+ return parsedArgs.data;
393
+ };
394
+
395
+ const logMissingArg = (arg: string) =>
396
+ logger.error(`The ${arg} flag requires an argument`);
397
+
398
+ const logInvalidNumber = (arg: string, value: number) =>
399
+ logger.error(
400
+ `The ${arg} flag requires a number. "${value}" is not a valid number`,
401
+ );
402
+
403
+ const printUsage = () => {
404
+ const usage = `Usage: ${CLI_NAME} [options] [[infile options] -i infile]... [outfile options] [outfile] [extra params]
405
+
406
+ ${DESCRIPTION}
407
+
408
+ Positional arguments:
409
+ [outfile] The output file. If not specified, a generated unix timestamp as filename will be used
410
+ and saved to the directory set in the --video-path option
411
+
412
+ Options:
413
+ -h, --help Show this help message
414
+ -v, --version Show version information
415
+ -kill Terminate the running ${CLI_NAME} instance, if there is any
416
+ -status Show the current status
417
+ -i <input> The input file to encode
418
+ -ss <start_time> The start time (same as ffmpeg's -ss)
419
+ -to <stop_time> The stop time (same as ffmpeg's -to)
420
+ -lavfi <filters> The set of filters to pass to ffmpeg
421
+ -c:v <encoder> The video encoder to use (default is ${config.encoder})
422
+ -deadline {good,best} The deadline for libvpx-vp9; good is the recommended one, best has the best
423
+ compression efficiency but takes the most time (default is ${config.deadline})
424
+ -crf <value> The crf to use (default is 24)
425
+ -cpu-used {0,1,2,3,4,5} The cpu-used for libvpx-vp9; a number between 0 and 5 inclusive, the higher
426
+ the number the faster the encoding will be with a quality trade-off (default is ${config.cpuUsed})
427
+ -subs Burn the subtitles onto the output file; this flag will automatically use
428
+ the subtitles found in the first input file, to use a different file use
429
+ the -lavfi flag with the subtitles filter directly
430
+ -sl, --size-limit <limit> The size limit of the output file in MiB, use 0 for no limit (default is ${config.sizeLimit})
431
+ --video-path <path> The video path where the video files are stored (default is ${config.videoPath})
432
+ this is overridden if the output file is specified
433
+ -ep, --extra-params <params>
434
+ The extra parameters to pass to ffmpeg, these will be appended making it
435
+ possible to override some defaults. This option has to be the last one, everything
436
+ will be passed as is to ffmpeg
437
+
438
+ Examples:
439
+ ${CLI_NAME} -i "/tmp/Videos/nijinosaki.mkv" -ss 00:00:02.268 -to 00:00:10.310
440
+ ${CLI_NAME} -i "/tmp/Videos/nijinosaki.mkv" --size-limit 6 -subs --extra-params -map 0:a -c:a libopus -b:a 128k`;
441
+
442
+ logger.info(usage, {
443
+ onlyConsole: true,
444
+ });
445
+ };
package/src/config.ts ADDED
@@ -0,0 +1,49 @@
1
+ import path from "path";
2
+
3
+ import { parse } from "smol-toml";
4
+ import { logger } from "./logger";
5
+ import { CONFIG_PATH } from "./paths";
6
+ import { ConfigSchema } from "./schema/config";
7
+ import { CONFIG_FILE_NAME } from "./constants";
8
+ import { existsSync, readFileSync } from "fs";
9
+
10
+ const configPath = path.join(CONFIG_PATH, CONFIG_FILE_NAME);
11
+
12
+ let rawConfig: unknown = {};
13
+
14
+ if (existsSync(configPath)) {
15
+ logger.info("Loading config file " + configPath);
16
+
17
+ try {
18
+ rawConfig = parse(readFileSync(configPath, "utf-8"));
19
+ } catch (error) {
20
+ if (error instanceof Error) {
21
+ logger.error(
22
+ "Error parsing the config file " + configPath + ":\n\n" + error.message,
23
+ );
24
+
25
+ process.exit(1);
26
+ }
27
+
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ const parsedConfig = ConfigSchema.safeParse(rawConfig);
33
+
34
+ if (!parsedConfig.success) {
35
+ logger.error("Error parsing the config file " + configPath);
36
+
37
+ const errors = parsedConfig.error.flatten().fieldErrors;
38
+
39
+ for (const key in errors) {
40
+ logger.error(
41
+ `Error in option "${key}": ` +
42
+ errors[key as keyof typeof errors]?.join("; "),
43
+ );
44
+ }
45
+
46
+ process.exit(1);
47
+ }
48
+
49
+ export const config = parsedConfig.data;
@@ -0,0 +1,15 @@
1
+ import packageJson from "../package.json";
2
+
3
+ export const CLI_NAME = packageJson.bin.pwebm;
4
+ export const LOG_FILE_NAME = CLI_NAME + ".log";
5
+ export const CONFIG_FILE_NAME = "config.toml";
6
+
7
+ export const PIPE_NAME = "\\\\.\\pipe\\" + CLI_NAME; // Named pipe for Windows
8
+ export const SOCKET_NAME = CLI_NAME + ".sock";
9
+
10
+ export const AUTHOR = packageJson.author;
11
+ export const VERSION = packageJson.version;
12
+ export const LICENSE = packageJson.license;
13
+ export const HOMEPAGE = packageJson.homepage;
14
+ export const DESCRIPTION = packageJson.description;
15
+ export const COPYRIGHT_YEAR = "2023-2025";