refactor(merger): move from ffprobe to mediainfo

Removes the necessity of ffprobe completely.
Also removed the mention of ffprobe requirement from the readme.
This commit is contained in:
stratumadev 2025-11-30 03:10:28 +01:00
parent e4afedfc9c
commit 1ff93f2fbd
8 changed files with 118 additions and 50 deletions

View file

@ -1,5 +1,4 @@
ffmpeg: 'ffmpeg.exe'
mkvmerge: 'mkvmerge.exe'
ffprobe: 'ffprobe.exe'
mp4decrypt: 'mp4decrypt.exe'
shaka: 'shaka-packager.exe'

View file

@ -126,7 +126,6 @@ C:.
12. Great! Now we have all dependencies installed and available in our PATH. To confirm that everything is working, open a new Command Prompt window and run the following commands:
```
ffmpeg
ffprobe
mkvmerge
mp4decrypt (or shaka-packager's .exe name, if you chose that instead)
```

View file

@ -18,7 +18,6 @@ This application is not endorsed by or affiliated with *Crunchyroll*, *Hidive* o
By default this application uses the following paths to programs (main executables):
* `ffmpeg.exe` (Windows) or `ffmpeg` (other) (From PATH)
* `ffprobe.exe` (Windows) or `ffprobe` (other) (From PATH)
* `mkvmerge.exe` (Windows) or `mkvmerge` (other) (From PATH)
* `mp4decrypt.exe` (Windows) or `mp4decrypt` (other) (From PATH) (or shaka-packager)
* `shaka-packager.exe` (Windows) or `shaka-packager` (other) (From PATH) (or mp4decrypt)

View file

@ -105,7 +105,6 @@ async function buildBinary(buildType: BuildTypes, gui: boolean) {
const binConf = {
ffmpeg: `ffmpeg${ext}`,
mkvmerge: `mkvmerge${ext}`,
ffprobe: `ffprobe${ext}`,
mp4decrypt: `mp4decrypt${ext}`,
shaka: `shaka-packager${ext}`
};

View file

@ -85,7 +85,6 @@ export type ConfigObject = {
bin: {
ffmpeg?: string;
mkvmerge?: string;
ffprobe?: string;
mp4decrypt?: string;
shaka?: string;
};
@ -150,7 +149,6 @@ const loadBinCfg = async () => {
const defaultBin = {
ffmpeg: 'ffmpeg',
mkvmerge: 'mkvmerge',
ffprobe: 'ffprobe',
mp4decrypt: 'mp4decrypt',
shaka: 'shaka-packager'
};

View file

@ -3,12 +3,13 @@ import * as yamlCfg from './module.cfg-loader';
import { fontFamilies, fontMime } from './module.fontsData';
import path from 'path';
import fs from 'fs';
import fsp from 'fs/promises';
import { LanguageItem } from './module.langsData';
import { AvailableMuxer } from './module.args';
import { console } from './log';
import ffprobe from 'ffprobe';
import Helper from './module.helper';
import { convertChaptersToFFmpegFormat } from './module.ffmpegChapter';
import { mediaInfoFactory } from 'mediainfo.js';
export type MergerInput = {
path: string;
@ -71,9 +72,23 @@ class Merger {
const vnas = this.options.videoAndAudio;
//get and set durations on each videoAndAudio Stream
for (const [vnaIndex, vna] of vnas.entries()) {
const streamInfo = await ffprobe(vna.path, { path: bin.ffprobe as string });
const videoInfo = streamInfo.streams.filter((stream) => stream.codec_type == 'video');
vnas[vnaIndex].duration = parseInt(videoInfo[0].duration as string);
const file = await fsp.open(vna.path);
const { size } = await fsp.stat(vna.path);
// Mediainfo
const mediaInfo = await mediaInfoFactory();
const result = await mediaInfo.analyzeData(
() => size,
async (size, offset) => {
const buf = Buffer.alloc(size);
const { bytesRead } = await file.read(buf, 0, size, offset);
return buf.subarray(0, bytesRead);
}
);
await file.close();
const videoInfo = result?.media?.track?.filter((stream) => stream['@type'] == 'Video');
vnas[vnaIndex].duration = videoInfo?.[0].Duration;
}
//Sort videoAndAudio streams by duration (shortest first)
vnas.sort((a, b) => {

View file

@ -43,12 +43,12 @@
"@bufbuild/protobuf": "^2.10.1",
"commander": "^14.0.2",
"express": "^5.1.0",
"ffprobe": "^1.1.2",
"iso-639": "^0.2.2",
"leven": "^4.1.0",
"log4js": "^6.9.1",
"lookpath": "^1.2.3",
"m3u8-parser": "^7.2.0",
"mediainfo.js": "^0.3.6",
"mpd-parser": "^1.3.1",
"node-playready": "^1.1.1",
"open": "^11.0.0",
@ -62,7 +62,6 @@
"@commitlint/config-conventional": "^20.0.0",
"@eslint/js": "^9.39.1",
"@types/express": "^5.0.5",
"@types/ffprobe": "^1.1.8",
"@types/m3u8-parser": "^7.2.5",
"@types/node": "^24.10.1",
"@types/ws": "^8.18.1",
@ -74,7 +73,7 @@
"eslint-config-prettier": "^10.1.8",
"husky": "^9.1.7",
"jiti": "^2.6.1",
"prettier": "^3.7.1",
"prettier": "^3.7.3",
"removeNPMAbsolutePaths": "^3.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",

View file

@ -17,9 +17,6 @@ importers:
express:
specifier: ^5.1.0
version: 5.1.0
ffprobe:
specifier: ^1.1.2
version: 1.1.2
iso-639:
specifier: ^0.2.2
version: 0.2.2
@ -35,6 +32,9 @@ importers:
m3u8-parser:
specifier: ^7.2.0
version: 7.2.0
mediainfo.js:
specifier: ^0.3.6
version: 0.3.6
mpd-parser:
specifier: ^1.3.1
version: 1.3.1
@ -69,9 +69,6 @@ importers:
'@types/express':
specifier: ^5.0.5
version: 5.0.5
'@types/ffprobe':
specifier: ^1.1.8
version: 1.1.8
'@types/m3u8-parser':
specifier: ^7.2.5
version: 7.2.5
@ -106,8 +103,8 @@ importers:
specifier: ^2.6.1
version: 2.6.1
prettier:
specifier: ^3.7.1
version: 3.7.1
specifier: ^3.7.3
version: 3.7.3
removeNPMAbsolutePaths:
specifier: ^3.0.1
version: 3.0.1
@ -496,9 +493,6 @@ packages:
'@types/express@5.0.5':
resolution: {integrity: sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==}
'@types/ffprobe@1.1.8':
resolution: {integrity: sha512-qPxx8Dy0HyH12hQCESN39NQOmU2Yl2b7tCyUhWy0l11HQv/8Yv7U+vcaveFXmXK8hcAP0oj29DPFuSM7vcC3Tg==}
'@types/http-errors@2.0.5':
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
@ -648,10 +642,18 @@ packages:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-regex@6.2.2:
resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
engines: {node: '>=12'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
@ -774,6 +776,10 @@ packages:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
cliui@9.0.1:
resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==}
engines: {node: '>=20'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@ -883,9 +889,6 @@ packages:
resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==}
engines: {node: '>=18'}
deferential@1.0.0:
resolution: {integrity: sha512-QyFNvptDP8bypD6WK6ZOXFSBHN6CFLZmQ59QyvRGDvN9+DoX01mxw28QrJwSVPrrwnMWqHgTRiXybH6Y0cBbWw==}
define-lazy-prop@3.0.0:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
@ -919,6 +922,9 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@ -1055,9 +1061,6 @@ packages:
picomatch:
optional: true
ffprobe@1.1.2:
resolution: {integrity: sha512-a+oTbhyeM7Z8PRy+mpzmVUAnATZT7z4BO94HSKeqHupdmjiKZ1djzcZkyoyXA21zCOCG7oVRrsBMmvvtmzoz4g==}
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
@ -1110,6 +1113,10 @@ packages:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
get-east-asian-width@1.4.0:
resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==}
engines: {node: '>=18'}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@ -1390,6 +1397,11 @@ packages:
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
engines: {node: '>= 0.8'}
mediainfo.js@0.3.6:
resolution: {integrity: sha512-3xVRlxwlVWIZV3z1q7pb8LzFOO7iKi/DXoRiFRZdOlrUEhPyJDaaRt0uK32yQJabArQicRBeq7cRxmdZlIBTyA==}
engines: {node: '>=18.0.0'}
hasBin: true
meow@12.1.1:
resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==}
engines: {node: '>=16.10'}
@ -1447,9 +1459,6 @@ packages:
napi-build-utils@2.0.0:
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
native-promise-only@0.8.1:
resolution: {integrity: sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==}
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@ -1569,8 +1578,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier@3.7.1:
resolution: {integrity: sha512-RWKXE4qB3u5Z6yz7omJkjWwmTfLdcbv44jUVHC5NpfXwFGzvpQM798FGv/6WNK879tc+Cn0AAyherCl1KjbyZQ==}
prettier@3.7.3:
resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==}
engines: {node: '>=14'}
hasBin: true
@ -1733,6 +1742,10 @@ packages:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string-width@7.2.0:
resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
engines: {node: '>=18'}
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
@ -1743,6 +1756,10 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
strip-ansi@7.1.2:
resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
engines: {node: '>=12'}
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
@ -1911,6 +1928,10 @@ packages:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@9.0.2:
resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
engines: {node: '>=18'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@ -1951,6 +1972,10 @@ packages:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yargs-parser@22.0.0:
resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=23}
yargs@16.2.0:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
engines: {node: '>=10'}
@ -1959,6 +1984,10 @@ packages:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
yargs@18.0.0:
resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==}
engines: {node: ^20.19.0 || ^22.12.0 || >=23}
yn@3.1.1:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
engines: {node: '>=6'}
@ -2318,8 +2347,6 @@ snapshots:
'@types/express-serve-static-core': 5.1.0
'@types/serve-static': 1.15.10
'@types/ffprobe@1.1.8': {}
'@types/http-errors@2.0.5': {}
'@types/json-schema@7.0.15': {}
@ -2542,10 +2569,14 @@ snapshots:
ansi-regex@5.0.1: {}
ansi-regex@6.2.2: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
ansi-styles@6.2.3: {}
arg@4.1.3: {}
argparse@2.0.1: {}
@ -2672,6 +2703,12 @@ snapshots:
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
cliui@9.0.1:
dependencies:
string-width: 7.2.0
strip-ansi: 7.1.2
wrap-ansi: 9.0.2
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@ -2759,10 +2796,6 @@ snapshots:
bundle-name: 4.1.0
default-browser-id: 5.0.1
deferential@1.0.0:
dependencies:
native-promise-only: 0.8.1
define-lazy-prop@3.0.0: {}
depd@2.0.0: {}
@ -2789,6 +2822,8 @@ snapshots:
ee-first@1.1.1: {}
emoji-regex@10.6.0: {}
emoji-regex@8.0.0: {}
encodeurl@2.0.0: {}
@ -2978,12 +3013,6 @@ snapshots:
optionalDependencies:
picomatch: 4.0.3
ffprobe@1.1.2:
dependencies:
JSONStream: 1.3.5
bl: 4.1.0
deferential: 1.0.0
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
@ -3044,6 +3073,8 @@ snapshots:
get-caller-file@2.0.5: {}
get-east-asian-width@1.4.0: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
@ -3283,6 +3314,10 @@ snapshots:
media-typer@1.1.0: {}
mediainfo.js@0.3.6:
dependencies:
yargs: 18.0.0
meow@12.1.1: {}
merge-descriptors@2.0.0: {}
@ -3333,8 +3368,6 @@ snapshots:
napi-build-utils@2.0.0: {}
native-promise-only@0.8.1: {}
natural-compare@1.4.0: {}
negotiator@1.0.0: {}
@ -3448,7 +3481,7 @@ snapshots:
prelude-ls@1.2.1: {}
prettier@3.7.1: {}
prettier@3.7.3: {}
process-nextick-args@2.0.1: {}
@ -3642,6 +3675,12 @@ snapshots:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
string-width@7.2.0:
dependencies:
emoji-regex: 10.6.0
get-east-asian-width: 1.4.0
strip-ansi: 7.1.2
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
@ -3654,6 +3693,10 @@ snapshots:
dependencies:
ansi-regex: 5.0.1
strip-ansi@7.1.2:
dependencies:
ansi-regex: 6.2.2
strip-json-comments@2.0.1: {}
strip-json-comments@3.1.1: {}
@ -3836,6 +3879,12 @@ snapshots:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@9.0.2:
dependencies:
ansi-styles: 6.2.3
string-width: 7.2.0
strip-ansi: 7.1.2
wrappy@1.0.2: {}
ws@8.18.3: {}
@ -3855,6 +3904,8 @@ snapshots:
yargs-parser@21.1.1: {}
yargs-parser@22.0.0: {}
yargs@16.2.0:
dependencies:
cliui: 7.0.4
@ -3875,6 +3926,15 @@ snapshots:
y18n: 5.0.8
yargs-parser: 21.1.1
yargs@18.0.0:
dependencies:
cliui: 9.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
string-width: 7.2.0
y18n: 5.0.8
yargs-parser: 22.0.0
yn@3.1.1: {}
yocto-queue@0.1.0: {}