pwebm 0.0.1 → 0.1.0-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/README.md +1 -1
- package/TODO.md +11 -25
- package/package.json +1 -1
- package/src/args.ts +281 -283
- package/src/config.ts +3 -6
- package/src/ipc/client.ts +66 -0
- package/src/ipc/constants.ts +9 -0
- package/src/{ipc.ts → ipc/server.ts} +11 -80
- package/src/logger.ts +5 -0
- package/src/main.ts +10 -11
- package/src/schema/args.ts +1 -0
- package/src/schema/config.ts +1 -0
- package/src/utils.ts +5 -3
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ bun i -g git+https://github.com/4ndrs/pwebm.git
|
|
|
27
27
|
|
|
28
28
|
## Historical Background & Purpose
|
|
29
29
|
|
|
30
|
-
In 2022, I wrote a script for the mpv media player called [PureMPV](https://github.com/4ndrs/PureMPV) that would help extracting the currently watched video's information, like the timestamps at certain points, and the
|
|
30
|
+
In 2022, I wrote a script for the mpv media player called [PureMPV](https://github.com/4ndrs/PureMPV) that would help extracting the currently watched video's information, like the timestamps at certain points, and the cropping coordinates, which would then later be used for encoding videos with ffmpeg with specific parameters.
|
|
31
31
|
|
|
32
32
|
Up to that point, I mostly spent the time encoding short webm files to keep and share on some imageboards, as well as encoding some mkv files with streams and attachments copied, so I wanted to integrate this functionality in some way with PureMPV. I didn't like the idea of having PureMPV to do the encoding itself, I wanted a seperate process to handle this independently, so I could stop or start another mpv window without affecting the encoding process. I wrote down some of the initial requirements at the time, which were the following:
|
|
33
33
|
|
package/TODO.md
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
##
|
|
2
|
-
|
|
3
|
-
- [x]
|
|
4
|
-
- [
|
|
5
|
-
- [
|
|
6
|
-
- [
|
|
7
|
-
- [
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [x] ffmpeg progress
|
|
12
|
-
- [x] status implementation
|
|
13
|
-
- [x] handle signals
|
|
14
|
-
- [x] name the process
|
|
15
|
-
- [x] version implementation
|
|
16
|
-
- [x] help implementation
|
|
17
|
-
- [x] args.ts help is missing dynamic default for crf
|
|
18
|
-
- [x] if input is missing after some other arg, the default parse error is shown
|
|
19
|
-
- [x] warn color is messed up for the message shown when the file limit is reached because of default warn color
|
|
20
|
-
- [x] implement better cleaning process before exit
|
|
21
|
-
- [x] release tagged versions in npm
|
|
22
|
-
- [x] 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
|
|
23
|
-
- [x] update readme
|
|
24
|
-
- [x] add subs flag warning to the readme (how it works, output seeking needed, etc)
|
|
1
|
+
## 0.1.0
|
|
2
|
+
- [x] (pwebm-helper) add a keybinding to show the status of the encoding on the mpv window
|
|
3
|
+
- [x] no log file flag
|
|
4
|
+
- [ ] add no log file flag to the docs
|
|
5
|
+
- [ ] when erroring out encoding an item, just log the error and move on to the next item (save the exit code)
|
|
6
|
+
- [ ] update the status on the terminal right away when adding a new item to the queue
|
|
7
|
+
- [ ] rename tries prop in status to try
|
|
8
|
+
- [ ] document status in the readme
|
|
9
|
+
- [ ] pass file to select in the -subs option
|
|
10
|
+
- [ ] pass false to -subs to disable subtitles (if enabled in the config)
|
|
25
11
|
|
|
26
12
|
### Might be nice to have
|
|
27
13
|
- [ ] add limit for the amount of tries to redo a conversion
|
|
28
14
|
- [ ] percentage bitrate offset when retrying a conversion with new calcs
|
|
29
15
|
- [ ] handle no duration case, maybe adding an additional crf mode instead of bitrate calcs
|
|
30
|
-
- [ ]
|
|
16
|
+
- [ ] multiple encodings at the same time
|
package/package.json
CHANGED
package/src/args.ts
CHANGED
|
@@ -8,9 +8,8 @@ import {
|
|
|
8
8
|
COPYRIGHT_YEAR,
|
|
9
9
|
} from "./constants";
|
|
10
10
|
|
|
11
|
-
import { ipc } from "./ipc";
|
|
12
11
|
import { config } from "./config";
|
|
13
|
-
import {
|
|
12
|
+
import { ipcClient } from "./ipc/client";
|
|
14
13
|
import { ArgsSchema } from "./schema/args";
|
|
15
14
|
|
|
16
15
|
const RECOGNIZED_ARGS = [
|
|
@@ -34,412 +33,411 @@ const RECOGNIZED_ARGS = [
|
|
|
34
33
|
"-ep",
|
|
35
34
|
"--extra-params",
|
|
36
35
|
"--video-path",
|
|
36
|
+
"--no-log-file",
|
|
37
37
|
];
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
const
|
|
39
|
+
const printUsage = () => {
|
|
40
|
+
const usage = `Usage: ${CLI_NAME} [options] [[infile options] -i infile]... [outfile options] [outfile] [extra params]
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
let isExtraParam = false;
|
|
44
|
-
let seeking: { startTime?: string; stopTime?: string } | undefined;
|
|
42
|
+
${DESCRIPTION}
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
Positional arguments:
|
|
45
|
+
[outfile] The output file. If not specified, a generated unix timestamp as filename will be used
|
|
46
|
+
and saved to the directory set in the --video-path option
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
Options:
|
|
49
|
+
-h, --help Show this help message
|
|
50
|
+
-v, --version Show version information
|
|
51
|
+
-kill Terminate the running ${CLI_NAME} instance, if there is any
|
|
52
|
+
-status Show the current status
|
|
53
|
+
-i <input> The input file to encode
|
|
54
|
+
-ss <start_time> The start time (same as ffmpeg's -ss)
|
|
55
|
+
-to <stop_time> The stop time (same as ffmpeg's -to)
|
|
56
|
+
-lavfi <filters> The set of filters to pass to ffmpeg
|
|
57
|
+
-c:v <encoder> The video encoder to use (default is ${config.encoder})
|
|
58
|
+
-deadline {good,best} The deadline for libvpx-vp9; good is the recommended one, best has the best
|
|
59
|
+
compression efficiency but takes the most time (default is ${config.deadline})
|
|
60
|
+
-crf <value> The crf to use (default is ${config.crf})
|
|
61
|
+
-cpu-used {0,1,2,3,4,5} The cpu-used for libvpx-vp9; a number between 0 and 5 inclusive, the higher
|
|
62
|
+
the number the faster the encoding will be with a quality trade-off (default is ${config.cpuUsed})
|
|
63
|
+
-subs Burn the subtitles onto the output file; this flag will automatically use
|
|
64
|
+
the subtitles found in the first input file, to use a different file use
|
|
65
|
+
the -lavfi flag with the subtitles filter directly
|
|
66
|
+
-sl, --size-limit <limit> The size limit of the output file in MiB, use 0 for no limit (default is ${config.sizeLimit})
|
|
67
|
+
--video-path <path> The video path where the video files are stored (default is ${config.videoPath})
|
|
68
|
+
this is overridden if the output file is specified
|
|
69
|
+
--no-log-file Don't log to the log file
|
|
70
|
+
-ep, --extra-params <params>
|
|
71
|
+
The extra parameters to pass to ffmpeg, these will be appended making it
|
|
72
|
+
possible to override some defaults. This option has to be the last one, everything
|
|
73
|
+
will be passed as is to ffmpeg
|
|
50
74
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
75
|
+
Examples:
|
|
76
|
+
${CLI_NAME} -i "/tmp/Videos/nijinosaki.mkv" -ss 00:00:02.268 -to 00:00:10.310
|
|
77
|
+
${CLI_NAME} -i "/tmp/Videos/nijinosaki.mkv" --size-limit 6 -subs --extra-params -map 0:a -c:a libopus -b:a 128k`;
|
|
55
78
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
79
|
+
console.info(usage);
|
|
80
|
+
};
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
const logMissingArg = (arg: string) =>
|
|
83
|
+
console.error(`The ${arg} flag requires an argument`);
|
|
63
84
|
|
|
64
|
-
|
|
85
|
+
const logInvalidNumber = (arg: string, value: number) =>
|
|
86
|
+
console.error(
|
|
87
|
+
`The ${arg} flag requires a number. "${value}" is not a valid number`,
|
|
88
|
+
);
|
|
65
89
|
|
|
66
|
-
|
|
67
|
-
}
|
|
90
|
+
const argv = Bun.argv.slice(2);
|
|
68
91
|
|
|
69
|
-
|
|
70
|
-
printUsage();
|
|
92
|
+
const rawArgs: Partial<ArgsSchema> = {};
|
|
71
93
|
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
let skip = false;
|
|
95
|
+
let isExtraParam = false;
|
|
96
|
+
let seeking: { startTime?: string; stopTime?: string } | undefined;
|
|
74
97
|
|
|
75
|
-
|
|
76
|
-
logger.info(
|
|
77
|
-
`${CLI_NAME} version ${VERSION}\nCopyright (c) ${COPYRIGHT_YEAR} ${AUTHOR}\nLicensed under the ${LICENSE} License\n${HOMEPAGE}`,
|
|
78
|
-
{ onlyConsole: true },
|
|
79
|
-
);
|
|
80
|
-
process.exit();
|
|
81
|
-
}
|
|
98
|
+
const skipNext = () => (skip = true);
|
|
82
99
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
await ipc.sendMessage({ type: "kill" });
|
|
86
|
-
|
|
87
|
-
logger.info("Main instance successfully killed", {
|
|
88
|
-
logToConsole: true,
|
|
89
|
-
});
|
|
90
|
-
} catch (error) {
|
|
91
|
-
if (
|
|
92
|
-
error instanceof Error &&
|
|
93
|
-
"code" in error &&
|
|
94
|
-
error.code !== "ENOENT"
|
|
95
|
-
) {
|
|
96
|
-
logger.error("Couldn't kill the main instance");
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
100
|
+
for (let index = 0; index < argv.length; index++) {
|
|
101
|
+
const arg = argv[index];
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const status = await ipc.sendMessage({ type: "status" });
|
|
103
|
+
if (skip) {
|
|
104
|
+
skip = false;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
if (isExtraParam) {
|
|
109
|
+
rawArgs.extraParams?.push(arg);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
110
112
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
error instanceof Error &&
|
|
115
|
-
"code" in error &&
|
|
116
|
-
error.code !== "ENOENT"
|
|
117
|
-
) {
|
|
118
|
-
logger.error("Couldn't get the status of the main instance");
|
|
119
|
-
}
|
|
113
|
+
if (arg.startsWith("-") && !RECOGNIZED_ARGS.includes(arg)) {
|
|
114
|
+
printUsage();
|
|
120
115
|
|
|
121
|
-
|
|
122
|
-
}
|
|
116
|
+
console.error(`Unrecognized argument: ${arg}`);
|
|
123
117
|
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
126
120
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
logger.error("Only one output file is allowed");
|
|
121
|
+
if (["-h", "--help"].includes(arg)) {
|
|
122
|
+
printUsage();
|
|
130
123
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
);
|
|
124
|
+
process.exit();
|
|
125
|
+
}
|
|
134
126
|
|
|
135
|
-
|
|
136
|
-
|
|
127
|
+
if (["-v", "--version"].includes(arg)) {
|
|
128
|
+
console.info(
|
|
129
|
+
`${CLI_NAME} version ${VERSION}\nCopyright (c) ${COPYRIGHT_YEAR} ${AUTHOR}\nLicensed under the ${LICENSE} License\n${HOMEPAGE}`,
|
|
130
|
+
);
|
|
131
|
+
process.exit();
|
|
132
|
+
}
|
|
137
133
|
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
if (arg === "-kill") {
|
|
135
|
+
try {
|
|
136
|
+
await ipcClient.sendMessage({ type: "kill" });
|
|
137
|
+
|
|
138
|
+
console.info("Main instance successfully killed");
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (
|
|
141
|
+
error instanceof Error &&
|
|
142
|
+
"code" in error &&
|
|
143
|
+
error.code !== "ENOENT"
|
|
144
|
+
) {
|
|
145
|
+
console.error("Couldn't kill the main instance");
|
|
140
146
|
}
|
|
141
147
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
continue;
|
|
148
|
+
process.exit(1);
|
|
145
149
|
}
|
|
146
150
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
logMissingArg(arg);
|
|
151
|
+
process.exit();
|
|
152
|
+
}
|
|
150
153
|
|
|
151
|
-
|
|
154
|
+
if (arg === "-status") {
|
|
155
|
+
try {
|
|
156
|
+
const status = await ipcClient.sendMessage({ type: "status" });
|
|
157
|
+
|
|
158
|
+
console.info(JSON.stringify(status, null, 2));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (
|
|
161
|
+
error instanceof Error &&
|
|
162
|
+
"code" in error &&
|
|
163
|
+
error.code !== "ENOENT"
|
|
164
|
+
) {
|
|
165
|
+
console.error("Couldn't get the status of the main instance");
|
|
152
166
|
}
|
|
153
167
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
157
170
|
|
|
158
|
-
|
|
171
|
+
process.exit();
|
|
172
|
+
}
|
|
159
173
|
|
|
160
|
-
|
|
174
|
+
if (!arg.startsWith("-") && !arg.startsWith("--")) {
|
|
175
|
+
if (rawArgs.output?.file) {
|
|
176
|
+
console.error("Only one output file is allowed");
|
|
161
177
|
|
|
162
|
-
|
|
163
|
-
|
|
178
|
+
console.debug(
|
|
179
|
+
`Current output file: ${rawArgs.output.file}, new file: ${arg}`,
|
|
180
|
+
);
|
|
164
181
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
logMissingArg(arg);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
168
184
|
|
|
169
|
-
|
|
170
|
-
}
|
|
185
|
+
if (!rawArgs.output) {
|
|
186
|
+
rawArgs.output = {};
|
|
187
|
+
}
|
|
171
188
|
|
|
172
|
-
|
|
173
|
-
seeking = {};
|
|
174
|
-
}
|
|
189
|
+
rawArgs.output.file = arg;
|
|
175
190
|
|
|
176
|
-
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
177
193
|
|
|
178
|
-
|
|
194
|
+
if (arg === "-ss") {
|
|
195
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
196
|
+
logMissingArg(arg);
|
|
179
197
|
|
|
180
|
-
|
|
198
|
+
process.exit(1);
|
|
181
199
|
}
|
|
182
200
|
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
process.exit(1);
|
|
188
|
-
}
|
|
201
|
+
if (!seeking) {
|
|
202
|
+
seeking = {};
|
|
203
|
+
}
|
|
189
204
|
|
|
190
|
-
|
|
191
|
-
rawArgs.inputs = [];
|
|
192
|
-
}
|
|
205
|
+
seeking.startTime = argv[index + 1];
|
|
193
206
|
|
|
194
|
-
|
|
195
|
-
file: args[index + 1],
|
|
196
|
-
...seeking,
|
|
197
|
-
});
|
|
207
|
+
skipNext();
|
|
198
208
|
|
|
199
|
-
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
200
211
|
|
|
201
|
-
|
|
212
|
+
if (arg === "-to") {
|
|
213
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
214
|
+
logMissingArg(arg);
|
|
202
215
|
|
|
203
|
-
|
|
216
|
+
process.exit(1);
|
|
204
217
|
}
|
|
205
218
|
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
continue;
|
|
219
|
+
if (!seeking) {
|
|
220
|
+
seeking = {};
|
|
210
221
|
}
|
|
211
222
|
|
|
212
|
-
|
|
213
|
-
if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
|
|
214
|
-
logMissingArg(arg);
|
|
223
|
+
seeking.stopTime = argv[index + 1];
|
|
215
224
|
|
|
216
|
-
|
|
217
|
-
}
|
|
225
|
+
skipNext();
|
|
218
226
|
|
|
219
|
-
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
220
229
|
|
|
221
|
-
|
|
222
|
-
|
|
230
|
+
if (arg === "-i") {
|
|
231
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
232
|
+
logMissingArg(arg);
|
|
223
233
|
|
|
224
|
-
|
|
225
|
-
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
226
236
|
|
|
227
|
-
|
|
237
|
+
if (!rawArgs.inputs) {
|
|
238
|
+
rawArgs.inputs = [];
|
|
239
|
+
}
|
|
228
240
|
|
|
229
|
-
|
|
241
|
+
rawArgs.inputs.push({
|
|
242
|
+
file: argv[index + 1],
|
|
243
|
+
...seeking,
|
|
244
|
+
});
|
|
230
245
|
|
|
231
|
-
|
|
232
|
-
}
|
|
246
|
+
seeking = undefined;
|
|
233
247
|
|
|
234
|
-
|
|
235
|
-
if (args[index + 1] === undefined) {
|
|
236
|
-
logMissingArg(arg);
|
|
248
|
+
skipNext();
|
|
237
249
|
|
|
238
|
-
|
|
239
|
-
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
240
252
|
|
|
241
|
-
|
|
253
|
+
if (arg === "-subs") {
|
|
254
|
+
rawArgs.subs = true;
|
|
242
255
|
|
|
243
|
-
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (arg === "-sl" || arg === "--size-limit") {
|
|
260
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
261
|
+
logMissingArg(arg);
|
|
244
262
|
|
|
245
|
-
|
|
263
|
+
process.exit(1);
|
|
246
264
|
}
|
|
247
265
|
|
|
248
|
-
|
|
249
|
-
if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
|
|
250
|
-
logMissingArg(arg);
|
|
266
|
+
const sizeLimit = Number(argv[index + 1]);
|
|
251
267
|
|
|
252
|
-
|
|
253
|
-
|
|
268
|
+
if (isNaN(sizeLimit)) {
|
|
269
|
+
logInvalidNumber(arg, sizeLimit);
|
|
254
270
|
|
|
255
|
-
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
256
273
|
|
|
257
|
-
|
|
274
|
+
rawArgs.sizeLimit = sizeLimit;
|
|
258
275
|
|
|
259
|
-
|
|
260
|
-
}
|
|
276
|
+
skipNext();
|
|
261
277
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
logMissingArg(arg);
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
265
280
|
|
|
266
|
-
|
|
267
|
-
|
|
281
|
+
if (arg === "-ep" || arg === "--extra-params") {
|
|
282
|
+
if (argv[index + 1] === undefined) {
|
|
283
|
+
logMissingArg(arg);
|
|
268
284
|
|
|
269
|
-
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
270
287
|
|
|
271
|
-
|
|
272
|
-
logInvalidNumber(arg, crf);
|
|
288
|
+
isExtraParam = true;
|
|
273
289
|
|
|
274
|
-
|
|
275
|
-
}
|
|
290
|
+
rawArgs.extraParams = [];
|
|
276
291
|
|
|
277
|
-
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
278
294
|
|
|
279
|
-
|
|
295
|
+
if (arg === "--video-path") {
|
|
296
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
297
|
+
logMissingArg(arg);
|
|
280
298
|
|
|
281
|
-
|
|
299
|
+
process.exit(1);
|
|
282
300
|
}
|
|
283
301
|
|
|
284
|
-
|
|
285
|
-
if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
|
|
286
|
-
logMissingArg(arg);
|
|
302
|
+
rawArgs.videoPath = argv[index + 1];
|
|
287
303
|
|
|
288
|
-
|
|
289
|
-
}
|
|
304
|
+
skipNext();
|
|
290
305
|
|
|
291
|
-
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
292
308
|
|
|
293
|
-
|
|
294
|
-
|
|
309
|
+
if (arg === "--no-log-file") {
|
|
310
|
+
rawArgs.noLogFile = true;
|
|
295
311
|
|
|
296
|
-
|
|
297
|
-
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
298
314
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
);
|
|
315
|
+
if (arg === "-crf") {
|
|
316
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
317
|
+
logMissingArg(arg);
|
|
303
318
|
|
|
304
|
-
|
|
305
|
-
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
306
321
|
|
|
307
|
-
|
|
322
|
+
const crf = Number(argv[index + 1]);
|
|
308
323
|
|
|
309
|
-
|
|
324
|
+
if (isNaN(crf)) {
|
|
325
|
+
logInvalidNumber(arg, crf);
|
|
310
326
|
|
|
311
|
-
|
|
327
|
+
process.exit(1);
|
|
312
328
|
}
|
|
313
329
|
|
|
314
|
-
|
|
315
|
-
if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
|
|
316
|
-
logMissingArg(arg);
|
|
330
|
+
rawArgs.crf = crf;
|
|
317
331
|
|
|
318
|
-
|
|
319
|
-
}
|
|
332
|
+
skipNext();
|
|
320
333
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
`The ${arg} flag requires either "good" or "best". "${args[index + 1]}" is not a valid value`,
|
|
324
|
-
);
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
325
336
|
|
|
326
|
-
|
|
327
|
-
|
|
337
|
+
if (arg === "-cpu-used") {
|
|
338
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
339
|
+
logMissingArg(arg);
|
|
340
|
+
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const cpuUsed = Number(argv[index + 1]);
|
|
345
|
+
|
|
346
|
+
if (isNaN(cpuUsed)) {
|
|
347
|
+
logInvalidNumber(arg, cpuUsed);
|
|
328
348
|
|
|
329
|
-
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
330
351
|
|
|
331
|
-
|
|
352
|
+
if (ArgsSchema.shape.cpuUsed.safeParse(cpuUsed).success === false) {
|
|
353
|
+
console.error(
|
|
354
|
+
`The ${arg} flag requires a number between 0 and 5 inclusive. "${cpuUsed}" is out of that range`,
|
|
355
|
+
);
|
|
332
356
|
|
|
333
|
-
|
|
357
|
+
process.exit(1);
|
|
334
358
|
}
|
|
335
359
|
|
|
336
|
-
|
|
337
|
-
if (args[index + 1] === undefined || args[index + 1].startsWith("-")) {
|
|
338
|
-
logMissingArg(arg);
|
|
360
|
+
rawArgs.cpuUsed = cpuUsed as 0 | 1 | 2 | 3 | 4 | 5;
|
|
339
361
|
|
|
340
|
-
|
|
341
|
-
}
|
|
362
|
+
skipNext();
|
|
342
363
|
|
|
343
|
-
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
344
366
|
|
|
345
|
-
|
|
367
|
+
if (arg === "-deadline") {
|
|
368
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
369
|
+
logMissingArg(arg);
|
|
346
370
|
|
|
347
|
-
|
|
371
|
+
process.exit(1);
|
|
348
372
|
}
|
|
349
373
|
|
|
350
|
-
if (
|
|
351
|
-
|
|
352
|
-
|
|
374
|
+
if (!["good", "best"].includes(argv[index + 1])) {
|
|
375
|
+
console.error(
|
|
376
|
+
`The ${arg} flag requires either "good" or "best". "${argv[index + 1]}" is not a valid value`,
|
|
377
|
+
);
|
|
353
378
|
|
|
354
|
-
|
|
355
|
-
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
356
381
|
|
|
357
|
-
|
|
382
|
+
rawArgs.deadline = argv[index + 1] as "good" | "best";
|
|
358
383
|
|
|
359
|
-
|
|
384
|
+
skipNext();
|
|
360
385
|
|
|
361
|
-
|
|
362
|
-
}
|
|
386
|
+
continue;
|
|
363
387
|
}
|
|
364
388
|
|
|
365
|
-
if (
|
|
366
|
-
|
|
389
|
+
if (arg === "-c:v") {
|
|
390
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
391
|
+
logMissingArg(arg);
|
|
367
392
|
|
|
368
|
-
|
|
369
|
-
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
370
395
|
|
|
371
|
-
|
|
372
|
-
printUsage();
|
|
396
|
+
rawArgs.encoder = argv[index + 1];
|
|
373
397
|
|
|
374
|
-
|
|
375
|
-
logger.error("Input file is required");
|
|
398
|
+
skipNext();
|
|
376
399
|
|
|
377
|
-
|
|
400
|
+
continue;
|
|
378
401
|
}
|
|
379
402
|
|
|
380
|
-
|
|
403
|
+
if (arg === "-lavfi") {
|
|
404
|
+
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
405
|
+
logMissingArg(arg);
|
|
406
|
+
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
381
409
|
|
|
382
|
-
|
|
383
|
-
logger.error("Error parsing the arguments");
|
|
410
|
+
rawArgs.lavfi = argv[index + 1];
|
|
384
411
|
|
|
385
|
-
|
|
386
|
-
JSON.stringify(parsedArgs.error.flatten().fieldErrors, null, 2),
|
|
387
|
-
);
|
|
412
|
+
skipNext();
|
|
388
413
|
|
|
389
|
-
|
|
414
|
+
continue;
|
|
390
415
|
}
|
|
416
|
+
}
|
|
391
417
|
|
|
392
|
-
|
|
393
|
-
};
|
|
418
|
+
if (seeking) {
|
|
419
|
+
rawArgs.output = { ...rawArgs.output, ...seeking };
|
|
394
420
|
|
|
395
|
-
|
|
396
|
-
|
|
421
|
+
seeking = undefined;
|
|
422
|
+
}
|
|
397
423
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
`The ${arg} flag requires a number. "${value}" is not a valid number`,
|
|
401
|
-
);
|
|
424
|
+
if (!rawArgs.inputs) {
|
|
425
|
+
printUsage();
|
|
402
426
|
|
|
403
|
-
|
|
404
|
-
|
|
427
|
+
// if the user isn't using any of the quick actions we require the -i flag
|
|
428
|
+
console.error("Input file is required");
|
|
405
429
|
|
|
406
|
-
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
407
432
|
|
|
408
|
-
|
|
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
|
|
433
|
+
const parsed = ArgsSchema.safeParse(rawArgs);
|
|
411
434
|
|
|
412
|
-
|
|
413
|
-
|
|
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 ${config.crf})
|
|
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
|
|
435
|
+
if (!parsed.success) {
|
|
436
|
+
console.error("Error parsing the arguments");
|
|
437
437
|
|
|
438
|
-
|
|
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`;
|
|
438
|
+
console.error(JSON.stringify(parsed.error.flatten().fieldErrors, null, 2));
|
|
441
439
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export const parsedArgs = parsed.data;
|
package/src/config.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
|
|
3
3
|
import { parse } from "smol-toml";
|
|
4
|
-
import { logger } from "./logger";
|
|
5
4
|
import { CONFIG_PATH } from "./paths";
|
|
6
5
|
import { ConfigSchema } from "./schema/config";
|
|
7
6
|
import { CONFIG_FILE_NAME } from "./constants";
|
|
@@ -12,13 +11,11 @@ const configPath = path.join(CONFIG_PATH, CONFIG_FILE_NAME);
|
|
|
12
11
|
let rawConfig: unknown = {};
|
|
13
12
|
|
|
14
13
|
if (existsSync(configPath)) {
|
|
15
|
-
logger.info("Loading config file " + configPath);
|
|
16
|
-
|
|
17
14
|
try {
|
|
18
15
|
rawConfig = parse(readFileSync(configPath, "utf-8"));
|
|
19
16
|
} catch (error) {
|
|
20
17
|
if (error instanceof Error) {
|
|
21
|
-
|
|
18
|
+
console.error(
|
|
22
19
|
"Error parsing the config file " + configPath + ":\n\n" + error.message,
|
|
23
20
|
);
|
|
24
21
|
|
|
@@ -32,12 +29,12 @@ if (existsSync(configPath)) {
|
|
|
32
29
|
const parsedConfig = ConfigSchema.safeParse(rawConfig);
|
|
33
30
|
|
|
34
31
|
if (!parsedConfig.success) {
|
|
35
|
-
|
|
32
|
+
console.error("Error parsing the config file " + configPath);
|
|
36
33
|
|
|
37
34
|
const errors = parsedConfig.error.flatten().fieldErrors;
|
|
38
35
|
|
|
39
36
|
for (const key in errors) {
|
|
40
|
-
|
|
37
|
+
console.error(
|
|
41
38
|
`Error in option "${key}": ` +
|
|
42
39
|
errors[key as keyof typeof errors]?.join("; "),
|
|
43
40
|
);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { SOCKET_FILE } from "./constants";
|
|
2
|
+
import { ResponseSchema } from "../schema/ipc";
|
|
3
|
+
|
|
4
|
+
import type { IPCSchema } from "../schema/ipc";
|
|
5
|
+
import type { StatusSchema } from "../schema/status";
|
|
6
|
+
|
|
7
|
+
// overloading
|
|
8
|
+
type SendMessage = {
|
|
9
|
+
(message: Exclude<IPCSchema, { type: "status" }>): Promise<void>;
|
|
10
|
+
(message: Extract<IPCSchema, { type: "status" }>): Promise<StatusSchema>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const sendMessage: SendMessage = async (message) =>
|
|
14
|
+
new Promise(async (resolve, reject) => {
|
|
15
|
+
try {
|
|
16
|
+
const socket = await Bun.connect({
|
|
17
|
+
unix: SOCKET_FILE,
|
|
18
|
+
socket: {
|
|
19
|
+
data: (socket, rawData) => {
|
|
20
|
+
socket.end();
|
|
21
|
+
|
|
22
|
+
const parsedData = ResponseSchema.safeParse(
|
|
23
|
+
JSON.parse(rawData.toString()),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (!parsedData.success) {
|
|
27
|
+
// couldn't parse
|
|
28
|
+
console.error("Invalid response received through the socket");
|
|
29
|
+
|
|
30
|
+
return reject();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!parsedData.data.success) {
|
|
34
|
+
// request did not succeed
|
|
35
|
+
return reject();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (parsedData.data.type === "status") {
|
|
39
|
+
const { data } = parsedData.data;
|
|
40
|
+
|
|
41
|
+
return resolve(data);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return resolve(undefined as void & StatusSchema);
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
socket.write(JSON.stringify(message));
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (
|
|
52
|
+
error instanceof Error &&
|
|
53
|
+
"code" in error &&
|
|
54
|
+
error.code === "ENOENT" &&
|
|
55
|
+
message.type !== "enqueue"
|
|
56
|
+
) {
|
|
57
|
+
console.error("No current main instance running");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
reject(error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const ipcClient = {
|
|
65
|
+
sendMessage,
|
|
66
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import { TEMP_PATH } from "../paths";
|
|
5
|
+
import { PIPE_NAME, SOCKET_NAME } from "../constants";
|
|
6
|
+
|
|
7
|
+
// windows doesn't have unix sockets but named pipes
|
|
8
|
+
export const SOCKET_FILE =
|
|
9
|
+
os.platform() === "win32" ? PIPE_NAME : path.join(TEMP_PATH, SOCKET_NAME);
|
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { queue } from "./queue";
|
|
5
|
-
import { status } from "./status";
|
|
6
|
-
import { logger } from "./logger";
|
|
7
|
-
import { TEMP_PATH } from "./paths";
|
|
1
|
+
import { queue } from "../queue";
|
|
2
|
+
import { status } from "../status";
|
|
3
|
+
import { logger } from "../logger";
|
|
8
4
|
import { unlinkSync } from "fs";
|
|
9
|
-
import { assertNever } from "
|
|
10
|
-
import {
|
|
11
|
-
import { IPCSchema, ResponseSchema } from "
|
|
5
|
+
import { assertNever } from "../utils";
|
|
6
|
+
import { SOCKET_FILE } from "./constants";
|
|
7
|
+
import { IPCSchema, ResponseSchema } from "../schema/ipc";
|
|
12
8
|
|
|
13
|
-
import
|
|
14
|
-
import type { UnixSocketListener } from "bun";
|
|
9
|
+
import os from "os";
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
const SOCKET_FILE =
|
|
18
|
-
os.platform() === "win32" ? PIPE_NAME : path.join(TEMP_PATH, SOCKET_NAME);
|
|
11
|
+
import type { UnixSocketListener } from "bun";
|
|
19
12
|
|
|
20
13
|
let listener: UnixSocketListener<undefined> | undefined;
|
|
21
14
|
|
|
@@ -72,8 +65,6 @@ const startListener = () => {
|
|
|
72
65
|
);
|
|
73
66
|
break;
|
|
74
67
|
case "status":
|
|
75
|
-
logger.info("Received status request, sending the current status");
|
|
76
|
-
|
|
77
68
|
socket.end(
|
|
78
69
|
JSON.stringify({
|
|
79
70
|
type: "status",
|
|
@@ -116,67 +107,7 @@ const stopListener = () => {
|
|
|
116
107
|
}
|
|
117
108
|
};
|
|
118
109
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
(message: Extract<IPCSchema, { type: "status" }>): Promise<StatusSchema>;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const sendMessage: SendMessage = async (message) =>
|
|
126
|
-
new Promise(async (resolve, reject) => {
|
|
127
|
-
try {
|
|
128
|
-
const socket = await Bun.connect({
|
|
129
|
-
unix: SOCKET_FILE,
|
|
130
|
-
socket: {
|
|
131
|
-
data: (socket, rawData) => {
|
|
132
|
-
socket.end();
|
|
133
|
-
|
|
134
|
-
const parsedData = ResponseSchema.safeParse(
|
|
135
|
-
JSON.parse(rawData.toString()),
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
if (!parsedData.success) {
|
|
139
|
-
// couldn't parse
|
|
140
|
-
logger.error("Invalid response received through the socket");
|
|
141
|
-
|
|
142
|
-
return reject();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!parsedData.data.success) {
|
|
146
|
-
// request did not succeed
|
|
147
|
-
return reject();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (parsedData.data.type === "status") {
|
|
151
|
-
const { data } = parsedData.data;
|
|
152
|
-
|
|
153
|
-
return resolve(data);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return resolve(undefined as void & StatusSchema);
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
socket.write(JSON.stringify(message));
|
|
162
|
-
} catch (error) {
|
|
163
|
-
if (
|
|
164
|
-
error instanceof Error &&
|
|
165
|
-
"code" in error &&
|
|
166
|
-
error.code === "ENOENT" &&
|
|
167
|
-
message.type !== "enqueue"
|
|
168
|
-
) {
|
|
169
|
-
logger.info("No current main instance running", {
|
|
170
|
-
logToConsole: true,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
reject(error);
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
export const ipc = {
|
|
179
|
-
sendMessage,
|
|
180
|
-
stopListener,
|
|
181
|
-
startListener,
|
|
110
|
+
export const ipcServer = {
|
|
111
|
+
stop: stopListener,
|
|
112
|
+
start: startListener,
|
|
182
113
|
};
|
package/src/logger.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os from "os";
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
|
+
import { parsedArgs } from "./args";
|
|
4
5
|
import { CONFIG_PATH } from "./paths";
|
|
5
6
|
import { CLI_NAME, LOG_FILE_NAME } from "./constants";
|
|
6
7
|
import { existsSync, mkdirSync, appendFileSync } from "fs";
|
|
@@ -113,6 +114,10 @@ const log = (message: Message, level: Level, options?: Options) => {
|
|
|
113
114
|
consoleLog(consoleMessage);
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
if (parsedArgs.noLogFile) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
116
121
|
writeToFile(message, level);
|
|
117
122
|
};
|
|
118
123
|
|
package/src/main.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { ipc } from "./ipc";
|
|
2
1
|
import { queue } from "./queue";
|
|
3
2
|
import { logger } from "./logger";
|
|
4
3
|
import { CLI_NAME } from "./constants";
|
|
5
|
-
import { parseArgs } from "./args";
|
|
6
4
|
import { cleanExit } from "./utils";
|
|
5
|
+
import { ipcServer } from "./ipc/server";
|
|
6
|
+
import { ipcClient } from "./ipc/client";
|
|
7
|
+
import { parsedArgs } from "./args";
|
|
8
|
+
|
|
9
|
+
const argv = Bun.argv.slice(2);
|
|
10
|
+
|
|
11
|
+
logger.info("argv: " + argv.join(" "));
|
|
7
12
|
|
|
8
13
|
process.title = CLI_NAME;
|
|
9
14
|
|
|
@@ -51,12 +56,6 @@ process.on("unhandledRejection", (reason) => {
|
|
|
51
56
|
cleanExit(1);
|
|
52
57
|
});
|
|
53
58
|
|
|
54
|
-
const args = Bun.argv.slice(2);
|
|
55
|
-
|
|
56
|
-
logger.info("argv: " + args.join(" "));
|
|
57
|
-
|
|
58
|
-
const parsedArgs = await parseArgs(args);
|
|
59
|
-
|
|
60
59
|
// let's check if ffmpeg and ffprobe are available before encoding anything
|
|
61
60
|
try {
|
|
62
61
|
const ffmpegProcess = Bun.spawnSync(["ffmpeg", "-hide_banner", "-version"]);
|
|
@@ -90,7 +89,7 @@ try {
|
|
|
90
89
|
|
|
91
90
|
try {
|
|
92
91
|
// try sending the args to the running process if there is one
|
|
93
|
-
await
|
|
92
|
+
await ipcClient.sendMessage({
|
|
94
93
|
type: "enqueue",
|
|
95
94
|
data: parsedArgs,
|
|
96
95
|
});
|
|
@@ -103,9 +102,9 @@ try {
|
|
|
103
102
|
|
|
104
103
|
queue.push(parsedArgs);
|
|
105
104
|
|
|
106
|
-
|
|
105
|
+
ipcServer.start();
|
|
107
106
|
|
|
108
107
|
await queue.processQueue();
|
|
109
108
|
|
|
110
|
-
|
|
109
|
+
ipcServer.stop();
|
|
111
110
|
}
|
package/src/schema/args.ts
CHANGED
|
@@ -28,6 +28,7 @@ export const ArgsSchema = ConfigSchema.merge(
|
|
|
28
28
|
encoder: ConfigSchema.shape.encoder.default(config.encoder),
|
|
29
29
|
cpuUsed: ConfigSchema.shape.cpuUsed.default(config.cpuUsed),
|
|
30
30
|
deadline: ConfigSchema.shape.deadline.default(config.deadline),
|
|
31
|
+
noLogFile: ConfigSchema.shape.noLogFile.default(config.noLogFile),
|
|
31
32
|
sizeLimit: ConfigSchema.shape.sizeLimit.default(config.sizeLimit),
|
|
32
33
|
videoPath: ConfigSchema.shape.videoPath.default(config.videoPath),
|
|
33
34
|
}),
|
package/src/schema/config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { DEFAULT_VIDEO_PATH, expandHome } from "../paths";
|
|
|
3
3
|
|
|
4
4
|
export const ConfigSchema = z.object({
|
|
5
5
|
subs: z.boolean().default(false),
|
|
6
|
+
noLogFile: z.boolean().default(false),
|
|
6
7
|
encoder: z.string().default("libvpx-vp9"),
|
|
7
8
|
sizeLimit: z.number().default(4),
|
|
8
9
|
crf: z.number().default(24),
|
package/src/utils.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ipc } from "./ipc";
|
|
2
1
|
import { queue } from "./queue";
|
|
3
2
|
import { logger } from "./logger";
|
|
3
|
+
import { ipcServer } from "./ipc/server";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type AssertNever = (value: never) => never;
|
|
6
|
+
|
|
7
|
+
export const assertNever: AssertNever = (value) => {
|
|
6
8
|
throw new Error(`Unexpected value: ${value}`);
|
|
7
9
|
};
|
|
8
10
|
|
|
@@ -15,7 +17,7 @@ export const cleanExit: CleanExit = async (code = 0) => {
|
|
|
15
17
|
|
|
16
18
|
await queue.abortProcessing();
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
ipcServer.stop();
|
|
19
21
|
|
|
20
22
|
process.exit(code);
|
|
21
23
|
};
|