mirror of
https://github.com/anidl/multi-downloader-nx.git
synced 2026-01-11 20:10:20 +00:00
Ffmpeg working with multiple subtitle files
Please note that MkvMerge will follow in the next commit
This commit is contained in:
parent
c194a9c6b7
commit
ef28f4e624
3 changed files with 128 additions and 63 deletions
|
|
@ -1,2 +1,2 @@
|
|||
ffmpeg: "./bin/ffmpeg/ffmpeg.exe"
|
||||
ffmpeg: "C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe"
|
||||
mkvmerge: "./bin/mkvtoolnix/mkvmerge.exe"
|
||||
|
|
|
|||
137
funi.js
137
funi.js
|
|
@ -62,6 +62,14 @@ if(!token){
|
|||
|
||||
// cli
|
||||
const argv = appYargs.appArgv(cfg.cli);
|
||||
module.exports = {
|
||||
argv,
|
||||
cfg
|
||||
}
|
||||
|
||||
// Import merger after argv has been exported
|
||||
|
||||
const merger = require('./modules/merger')
|
||||
|
||||
// check page
|
||||
if(!isNaN(parseInt(argv.p, 10)) && parseInt(argv.p, 10) > 0){
|
||||
|
|
@ -349,7 +357,9 @@ async function getEpisode(fnSlug){
|
|||
stDlPath = m.subtitles;
|
||||
selected = true;
|
||||
}
|
||||
console.log(`[#${m.id}] ${dub_type} [${m.version}]`,(selected?'(selected)':''),(m.subtitles.subLangAvailable?'':'(defaulted to English subtitles)'));
|
||||
console.log(`[#${m.id}] ${dub_type} [${m.version}]${(selected?' (selected)':'')}${
|
||||
stDlPath && selected ? ` (using ${stDlPath.map(a => `'${a.langName}'`).join(', ')} for subtitles)` : ''
|
||||
}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -397,7 +407,7 @@ function getSubsUrl(m){
|
|||
return false;
|
||||
}
|
||||
|
||||
let subLang = argv.subLang;
|
||||
let subLangs = argv.subLang;
|
||||
|
||||
const subType = {
|
||||
'enUS': 'English',
|
||||
|
|
@ -405,27 +415,30 @@ function getSubsUrl(m){
|
|||
'ptBR': 'Portuguese (Brazil)'
|
||||
};
|
||||
|
||||
let subLangAvailable = m.some(a => {
|
||||
return a.ext == 'vtt' && a.language === subType[subLang];
|
||||
});
|
||||
let subLangAvailable = m.some(a => subLangs.some(subLang => a.ext == 'vtt' && a.language === subType[subLang]));
|
||||
|
||||
if (!subLangAvailable) {
|
||||
subLang = 'enUS';
|
||||
subLangs = [ 'enUS' ];
|
||||
}
|
||||
|
||||
let found = []
|
||||
|
||||
for(let i in m){
|
||||
let fpp = m[i].filePath.split('.');
|
||||
let fpe = fpp[fpp.length-1];
|
||||
if(fpe == 'vtt' && m[i].language === subType[subLang]) {
|
||||
return {
|
||||
path: m[i].filePath,
|
||||
ext: `.${subLang}`,
|
||||
langName: subType[subLang],
|
||||
subLangAvailable: subLangAvailable
|
||||
};
|
||||
for (let lang of subLangs) {
|
||||
if(fpe == 'vtt' && m[i].language === subType[lang]) {
|
||||
found.push({
|
||||
path: m[i].filePath,
|
||||
ext: `.${lang}`,
|
||||
langName: subType[lang],
|
||||
language: m[i]?.languages[0]?.code ?? lang.slice(0, 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
async function downloadStreams(){
|
||||
|
|
@ -598,35 +611,36 @@ async function downloadStreams(){
|
|||
}
|
||||
|
||||
// add subs
|
||||
let subsUrl = stDlPath ? stDlPath.path : false;
|
||||
let subsExt = !argv.mp4 || argv.mp4 && !argv.mks && argv.ass ? '.ass' : '.srt';
|
||||
let addSubs = argv.mks && subsUrl ? true : false;
|
||||
let subFile;
|
||||
let subTrashFile;
|
||||
let addSubs = argv.mks && tsDlPath ? true : false;
|
||||
|
||||
// download subtitles
|
||||
if(subsUrl){
|
||||
if(stDlPath){
|
||||
console.log('[INFO] Downloading subtitles...');
|
||||
console.log(subsUrl);
|
||||
let subsSrc = await getData({
|
||||
url: subsUrl,
|
||||
useProxy: true,
|
||||
debug: argv.debug,
|
||||
});
|
||||
if(subsSrc.ok){
|
||||
let assData = vttConvert(subsSrc.res.body, (subsExt == '.srt' ? true : false), stDlPath.langName, argv.fontSize);
|
||||
subFile = path.join(cfg.dir.content, fnOutput) + stDlPath.ext + subsExt;
|
||||
subTrashFile = path.join(cfg.dir.trash, fnOutput) + stDlPath.ext + subsExt;
|
||||
fs.writeFileSync(subFile, assData);
|
||||
for (let subObject of stDlPath) {
|
||||
console.log(subObject);
|
||||
let subsSrc = await getData({
|
||||
url: subObject.path,
|
||||
useProxy: true,
|
||||
debug: argv.debug,
|
||||
});
|
||||
if(subsSrc.ok){
|
||||
let assData = vttConvert(subsSrc.res.body, (subsExt == '.srt' ? true : false), subObject.langName, argv.fontSize);
|
||||
subObject.file = path.join(cfg.dir.content, fnOutput) + subObject.ext + subsExt;
|
||||
subObject.trashFile = path.join(cfg.dir.trash, fnOutput) + subObject.ext + subsExt;
|
||||
fs.writeFileSync(subObject.file, assData);
|
||||
}
|
||||
else{
|
||||
console.log('[ERROR] Failed to download subtitles!');
|
||||
addSubs = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (addSubs)
|
||||
console.log('[INFO] Subtitles downloaded!');
|
||||
}
|
||||
else{
|
||||
console.log('[ERROR] Failed to download subtitles!');
|
||||
addSubs = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(dlFailed || dlFailedA){
|
||||
if(false && (dlFailed || dlFailedA)){
|
||||
console.log('\n[INFO] TS file not fully downloaded, skip muxing video...\n');
|
||||
return;
|
||||
}
|
||||
|
|
@ -671,7 +685,7 @@ async function downloadStreams(){
|
|||
// check exec path
|
||||
let mkvmergebinfile = await lookpath(path.join(cfg.bin.mkvmerge));
|
||||
let ffmpegbinfile = await lookpath(path.join(cfg.bin.ffmpeg));
|
||||
|
||||
|
||||
// check exec
|
||||
if( !argv.mp4 && !mkvmergebinfile ){
|
||||
console.log('[WARN] MKVMerge not found, skip using this...');
|
||||
|
|
@ -686,57 +700,53 @@ async function downloadStreams(){
|
|||
}
|
||||
|
||||
// select muxer
|
||||
usableMKVmerge = false
|
||||
/* TODO Remake mkvmerge */
|
||||
if(!argv.mp4 && usableMKVmerge){
|
||||
/*
|
||||
// mux to mkv
|
||||
let mkvmux = [];
|
||||
mkvmux.push('-o',`${muxTrg}.mkv`);
|
||||
mkvmux.push('--no-date','--disable-track-statistics-tags','--engage','no_variable_data');
|
||||
mkvmux.push('--track-name','0:[Funimation]');
|
||||
|
||||
if(plAud.uri){
|
||||
mkvmux.push('--video-tracks','0','--no-audio');
|
||||
mkvmux.push('--no-subtitles','--no-attachments');
|
||||
mkvmux.push(`${muxTrg}.ts`);
|
||||
mkvmux.push('--language',`0:${langCode}`);
|
||||
mkvmux.push('--no-video','--audio-tracks','0');
|
||||
mkvmux.push('--no-subtitles','--no-attachments');
|
||||
mkvmux.push(`${muxTrgA}.ts`);
|
||||
}
|
||||
else{
|
||||
mkvmux.push('--language',`1:${langCode}`);
|
||||
mkvmux.push('--video-tracks','0','--audio-tracks','1');
|
||||
mkvmux.push('--no-subtitles','--no-attachments');
|
||||
mkvmux.push(`${muxTrg}.ts`);
|
||||
}
|
||||
if(addSubs){
|
||||
mkvmux.push('--language','0:eng');
|
||||
mkvmux.push(`${subFile ? subFile : muxTrg + subsExt}`);
|
||||
for (let index in stDlPath) {
|
||||
subObj = stDlPath[index]
|
||||
mkvmux.push('--language',`${parseInt(index) + 2}:${getLanguageCode(subObj.language)}`);
|
||||
mkvmux.push(`${subObj.file ? subObj.file : muxTrg + subsExt}`);
|
||||
}
|
||||
} else {
|
||||
mkvmux.push('--no-subtitles')
|
||||
mkvmux.push('--no-attachments');
|
||||
}
|
||||
fs.writeFileSync(`${muxTrg}.json`,JSON.stringify(mkvmux,null,' '));
|
||||
shlp.exec('mkvmerge',`"${mkvmergebinfile}"`,`@"${muxTrg}.json"`);
|
||||
fs.unlinkSync(`${muxTrg}.json`);
|
||||
// fs.unlinkSync(`${muxTrg}.json`);
|
||||
*/
|
||||
}
|
||||
else if(usableFFmpeg){
|
||||
let ffext = !argv.mp4 ? 'mkv' : 'mp4';
|
||||
let ffmux = `-i "${muxTrg}.ts" `;
|
||||
ffmux += plAud.uri ? `-i "${muxTrgA}.ts" ` : '';
|
||||
ffmux += addSubs ? `-i "${subFile ? subFile : muxTrg + subsExt}" ` : '';
|
||||
ffmux += plAud.uri ? '-map 1:a ' : '';
|
||||
ffmux += '-map 0 -c:v copy -c:a copy ';
|
||||
ffmux += addSubs ? `-map ${plAud.uri ? 2 : 1} ` : '';
|
||||
ffmux += addSubs && !argv.mp4 ? '-c:s ass ' : '';
|
||||
ffmux += addSubs && argv.mp4 ? '-c:s mov_text ' : '';
|
||||
ffmux += '-metadata encoding_tool="no_variable_data" ';
|
||||
ffmux += `-metadata:s:v:0 title="[${argv.a}]" -metadata:s:a:${plAud.uri?1:0} language=${langCode} `;
|
||||
ffmux += addSubs ? '-metadata:s:s:0 language=eng ' : '';
|
||||
ffmux += `"${muxTrg}.${ffext}"`;
|
||||
// mux to mkv
|
||||
shlp.exec('ffmpeg',`"${ffmpegbinfile}"`,ffmux);
|
||||
let command = merger.buildCommandFFmpeg(`${muxTrg}.ts`, plAud, stDlPath, `${muxTrg}.${ffext}`)
|
||||
shlp.exec('ffmpeg',`"${ffmpegbinfile}"`,command)
|
||||
}
|
||||
else{
|
||||
console.log('\n[INFO] Done!\n');
|
||||
return;
|
||||
}
|
||||
if (argv.nocleanup)
|
||||
return;
|
||||
if(argv.notrashfolder && argv.nocleanup){
|
||||
// don't move or delete temp files
|
||||
}
|
||||
|
|
@ -744,16 +754,19 @@ async function downloadStreams(){
|
|||
fs.renameSync(muxTrg+'.ts', tshTrg + '.ts');
|
||||
if (plAud.uri)
|
||||
fs.renameSync(muxTrgA+'.ts', tshTrgA + '.ts');
|
||||
if(subsUrl && addSubs){
|
||||
fs.renameSync(subFile ? subFile : muxTrg+subsExt, subTrashFile ? subTrashFile : tshTrg + subsExt);
|
||||
if(addSubs){
|
||||
for (let subObj of stDlPath) {
|
||||
fs.renameSync(subObj.file ? subObj.file : muxTrg+subsExt, subObj.trashFile ? subObj.trashFile : tshTrg + subsExt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
fs.unlinkSync(muxTrg+'.ts');
|
||||
if (plAud.uri)
|
||||
fs.unlinkSync(muxTrgA+'.ts');
|
||||
if(subsUrl && addSubs){
|
||||
fs.unlinkSync(subFile ? subFile : muxTrg + subsExt);
|
||||
if(addSubs){
|
||||
for (let subObj of stDlPath)
|
||||
fs.unlinkSync(subObj.file ? subObj.file : muxTrg + subsExt);
|
||||
}
|
||||
}
|
||||
console.log('\n[INFO] Done!\n');
|
||||
|
|
|
|||
52
modules/merger.js
Normal file
52
modules/merger.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
const iso639 = require('iso-639');
|
||||
const argv = require('../funi').argv
|
||||
|
||||
/**
|
||||
* @param {string} videoFile
|
||||
* @param {object} audioFile
|
||||
* @param {Array<object>} subtitles
|
||||
* @returns {string}
|
||||
*/
|
||||
const buildCommandFFmpeg = (videoFile, audioSettings, subtitles, output) => {
|
||||
let args = []
|
||||
args.push(`-i "${videoFile}"`)
|
||||
|
||||
if (audioSettings.uri)
|
||||
args.push(`-i "${audioSettings.uri}"`)
|
||||
for (let index in subtitles) {
|
||||
let sub = subtitles[index]
|
||||
args.push(`-i "${sub.file}"`)
|
||||
}
|
||||
|
||||
args.push('-map 0')
|
||||
if (audioSettings.uri)
|
||||
args.push( `-map 1`)
|
||||
|
||||
args.push(...subtitles.map((_, index) => `-map ${index + (audioSettings.uri ? 2 : 1)}`))
|
||||
args.push(
|
||||
'-metadata:s:v:0 title="[Funimation]"',
|
||||
`-metadata:s:a:0 language=${getLanguageCode(audioSettings.language, argv.sub ? 'jpn' : 'eng')}`,
|
||||
`-c:v copy`,
|
||||
`-c:a copy`,
|
||||
`-c:s mov_text`,
|
||||
`-c:s ass`
|
||||
)
|
||||
args.push(...subtitles.map((sub, index) => `-metadata:s:${index + 2} language=${getLanguageCode(sub.language)}`))
|
||||
args.push(`"${output}"`)
|
||||
return args.join(" ")
|
||||
}
|
||||
|
||||
const getLanguageCode = (from, _default = 'eng') => {
|
||||
for (let lang in iso639.iso_639_2) {
|
||||
let langObj = iso639.iso_639_2[lang];
|
||||
if (langObj.hasOwnProperty('639-1') && langObj['639-1'] === from) {
|
||||
return langObj['639-2'];
|
||||
}
|
||||
}
|
||||
return _default
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildCommandFFmpeg,
|
||||
getLanguageCode
|
||||
}
|
||||
Loading…
Reference in a new issue