This commit is contained in:
AniDL 2020-03-10 16:30:32 +03:00
parent 0d8ef58d98
commit ef1635192a
6 changed files with 163 additions and 57 deletions

5
.gitignore vendored
View file

@ -1,4 +1,8 @@
/bin/ff*
/bin/mkv*
/_builds/*
/node_modules/
/videos/*.json
.DS_Store
ffmpeg
mkvmerge
@ -10,3 +14,4 @@ package-lock.json
*.mkv
*.mp4
*.srt
*.resume

View file

@ -1,2 +1,2 @@
ffmpeg: ./bin/ffmpeg
mkvmerge: ./bin/mkvmerge
ffmpeg: "./bin/ffmpeg"
mkvmerge: "./bin/mkvmerge"

View file

@ -1,5 +1,10 @@
## Change Log
### 4.5.1 (2020/03/10)
- Better binary files handling
- Binary build for windows
- Known bug: Proxy not working
### 4.5.0 (2020/01/21)
- Resume downloading
- Known bug: Proxy not working

102
funi.js
View file

@ -6,7 +6,7 @@ const path = require('path');
const url = require('url');
// package json
const packageJson = require(path.join(__dirname,'package.json'));
const packageJson = require('./package.json');
// program name
console.log(`\n=== Funimation Downloader NX ${packageJson.version} ===\n`);
@ -165,9 +165,6 @@ catch (e) {
process.exit();
}
// go to content folder (remove it in future version!)
process.chdir(cfg.dir.content);
// select mode
if(argv.auth){
auth();
@ -546,7 +543,7 @@ async function downloadStreams(){
console.log('[INFO] Stream URL:',videoUrl);
fnSuffix = argv.suffix.replace('SIZEp',plLayersRes[argv.q]);
fnOutput = shlp.cleanupFilename(`[${argv.a}] ${fnTitle} - ${fnEpNum} [${fnSuffix}]`);
console.log(`[INFO] Output filename: ${fnOutput}`);
console.log(`[INFO] Output filename: ${fnOutput}.ts`);
}
else if(argv.x > plServerList.length){
console.log('[ERROR] Server not selected!\n');
@ -557,6 +554,8 @@ async function downloadStreams(){
return;
}
let dlFailed = false;
if (!argv.novids) {
// download video
let reqVideo = await getData({
@ -581,37 +580,24 @@ async function downloadStreams(){
}
}
let tsFile = `${fnOutput}.ts`;
let resumeFile = `${tsFile}.resume`;
let streamOffset = 0;
if(fs.existsSync(tsFile) && fs.existsSync(resumeFile)){
try{
let resume = JSON.parse(fs.readFileSync(resumeFile, 'utf-8'));
if(resume.total == chunkList.segments.length && resume.completed != resume.total){
streamOffset = resume.completed;
}
}
catch(e){
console.log(e);
}
}
let tsFile = path.join(cfg.dir.content, fnOutput);
let streamdlParams = {
fn: tsFile,
fn: tsFile + '.ts',
m3u8json: chunkList,
baseurl: chunkList.baseUrl,
pcount: 10,
partsOffset: streamOffset,
proxy: (proxyHLS ? proxyHLS : false)
};
let dldata = await new streamdl(streamdlParams).download();
if (!dldata.ok) {
fs.writeFileSync(resumeFile, JSON.stringify(dldata.parts));
console.log(`[ERROR] ${dldata.error}\n`);
return;
if(!dldata.ok){
fs.writeFileSync(`${tsFile}.ts.resume`, JSON.stringify(dldata.parts));
console.log(`[ERROR] DL Stats: ${JSON.stringify(dldata.parts)}\n`);
dlFailed = true;
}
else {
console.log('[INFO] Video downloaded!\n');
else if(fs.existsSync(`${tsFile}.ts.resume`) && dldata.ok){
fs.unlinkSync(`${tsFile}.ts.resume`);
}
}
else{
@ -628,7 +614,8 @@ async function downloadStreams(){
});
if(subsSrc.ok){
let srtData = ttml2srt(subsSrc.res.body);
fs.writeFileSync(`${fnOutput}.srt`,srtData);
let srtFile = path.join(cfg.dir.content, fnOutput) + '.srt';
fs.writeFileSync(srtFile, srtData);
console.log('[INFO] Subtitles downloaded!');
}
else{
@ -637,7 +624,12 @@ async function downloadStreams(){
}
}
if(!fs.statSync(`${fnOutput}.ts`).isFile()){
if(dlFailed){
console.log('\n[INFO] TS file not fully downloaded, skip muxing video...\n');
return;
}
if(!fs.statSync(`${path.join(cfg.dir.content, fnOutput)}.ts`).isFile()){
console.log('\n[INFO] TS file not found, skip muxing video...\n');
return;
}
@ -645,46 +637,55 @@ async function downloadStreams(){
// add subs
let addSubs = argv.mks && stDlPath ? true : false;
// usage
let usableMKVmerge = true;
let usableFFmpeg = true;
console.log(await lookpath(path.join(cfg.bin.ffmpeg + '.exe')));
// 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...');
cfg.bin.mkvmerge = false;
usableMKVmerge = false;
}
if( !mkvmergebinfile && !ffmpegbinfile || argv.mp4 && !ffmpegbinfile ){
if( !usableMKVmerge && !ffmpegbinfile || argv.mp4 && !ffmpegbinfile ){
console.log('[WARN] FFmpeg not found, skip using this...');
cfg.bin.ffmpeg = false;
usableFFmpeg = false;
}
// ftag
argv.ftag = argv.ftag ? argv.ftag : argv.a;
argv.ftag = shlp.cleanupFilename(argv.ftag);
let muxTrg = path.join(cfg.dir.content, fnOutput);
let tshTrg = path.join(cfg.dir.trash, fnOutput);
// select muxer
if(!argv.mp4 && cfg.bin.mkvmerge){
if(!argv.mp4 && usableMKVmerge){
// mux to mkv
let mkvmux = [];
mkvmux.push('-o',`${fnOutput}.mkv`);
mkvmux.push('-o',`${muxTrg}.mkv`);
mkvmux.push('--no-date','--disable-track-statistics-tags','--engage','no_variable_data');
mkvmux.push('--track-name',`0:[${argv.ftag}]`);
mkvmux.push('--language',`1:${argv.sub?'jpn':'eng'}`);
mkvmux.push('--video-tracks','0','--audio-tracks','1');
mkvmux.push('--no-subtitles','--no-attachments');
mkvmux.push(`${fnOutput}.ts`);
mkvmux.push(`${muxTrg}.ts`);
if(addSubs){
mkvmux.push('--language','0:eng');
mkvmux.push(`${fnOutput}.srt`);
mkvmux.push(`${muxTrg}.srt`);
}
fs.writeFileSync(`${fnOutput}.json`,JSON.stringify(mkvmux,null,' '));
shlp.exec('mkvmerge',`"${cfg.bin.mkvmerge}"`,`@"${fnOutput}.json"`);
fs.unlinkSync(`${fnOutput}.json`);
fs.writeFileSync(`${muxTrg}.json`,JSON.stringify(mkvmux,null,' '));
shlp.exec('mkvmerge',`"${mkvmergebinfile}"`,`@"${muxTrg}.json"`);
fs.unlinkSync(`${muxTrg}.json`);
}
else if(cfg.bin.ffmpeg){
else if(usableFFmpeg){
let ffext = !argv.mp4 ? 'mkv' : 'mp4';
let ffmux = `-i "${fnOutput}.ts" `;
ffmux += addSubs ? `-i "${fnOutput}.srt" ` : '';
let ffmux = `-i "${muxTrg}.ts" `;
ffmux += addSubs ? `-i "${muxTrg}.srt" ` : '';
ffmux += '-map 0 -c:v copy -c:a copy ';
ffmux += addSubs ? '-map 1 ' : '';
ffmux += addSubs && !argv.mp4 ? '-c:s srt ' : '';
@ -692,24 +693,27 @@ async function downloadStreams(){
ffmux += '-metadata encoding_tool="no_variable_data" ';
ffmux += `-metadata:s:v:0 title="[${argv.a}]" -metadata:s:a:0 language=${argv.sub?'jpn':'eng'} `;
ffmux += addSubs ? '-metadata:s:s:0 language=eng ' : '';
ffmux += `"${fnOutput}.${ffext}"`;
ffmux += `"${muxTrg}.${ffext}"`;
// mux to mkv
shlp.exec('ffmpeg',`"${cfg.bin.ffmpeg}"`,ffmux);
shlp.exec('ffmpeg',`"${ffmpegbinfile}"`,ffmux);
}
else{
console.log('\n[INFO] Done!\n');
return;
}
if(argv.nocleanup){
fs.renameSync(fnOutput+'.ts', path.join(cfg.dir.trash,`/${fnOutput}.ts`));
if(argv.notrashfolder && argv.nocleanup){
// don't move or delete temp files
}
else if(argv.nocleanup){
fs.renameSync(muxTrg+'.ts', tshTrg + '.ts');
if(stDlPath && argv.mks){
fs.renameSync(fnOutput+'.srt', path.join(cfg.dir.trash,`/${fnOutput}.srt`));
fs.renameSync(muxTrg+'.srt', tshTrg + '.srt');
}
}
else{
fs.unlinkSync(fnOutput+'.ts', path.join(cfg.dir.trash,`/${fnOutput}.ts`));
fs.unlinkSync(muxTrg+'.ts');
if(stDlPath && argv.mks){
fs.unlinkSync(fnOutput+'.srt', path.join(cfg.dir.trash,`/${fnOutput}.srt`));
fs.unlinkSync(muxTrg+'.srt');
}
}
console.log('\n[INFO] Done!\n');

80
modules/build.js Normal file
View file

@ -0,0 +1,80 @@
#!/usr/bin/env node
// build requirements
const pkg = require('../package.json');
const fs = require('fs-extra');
const modulesCleanup = require('removeNPMAbsolutePaths');
const { compile } = require('nexe');
const buildsDir = './_builds';
const nodeVer = '-12.15.0';
// main
(async function(){
const buildStr = `${pkg.name}-${pkg.version}`;
const acceptableBuilds = ['win64','linux64','macos64'];
const buildType = process.argv[2];
if(!acceptableBuilds.includes(buildType)){
console.error('[ERROR] unknown build type!');
process.exit();
}
await modulesCleanup('.');
if(!fs.existsSync(buildsDir)){
fs.mkdirSync(buildsDir);
}
const buildFull = `${buildStr}-${buildType}`;
const buildDir = `${buildsDir}/${buildFull}`;
if(fs.existsSync(buildDir)){
fs.removeSync(buildDir);
}
fs.mkdirSync(buildDir);
fs.mkdirSync(`${buildDir}/bin`);
fs.mkdirSync(`${buildDir}/config`);
fs.mkdirSync(`${buildDir}/videos`);
fs.mkdirSync(`${buildDir}/videos/_trash`);
const buildConfig = {
input: './crunchy.js',
output: `${buildDir}/${pkg.short_name}`,
target: getTarget(buildType) + nodeVer,
resources: [
'./modules/module.*',
],
};
console.log(`[Build] Build configuration: ${buildFull}`);
await compile(buildConfig);
if(fs.existsSync('./bin/ffmpeg')){
// fs.copySync('./bin/ffmpeg', `${buildDir}/bin/ffmpeg`);
}
if(fs.existsSync('./bin/ffmpeg.exe')){
// fs.copySync('./bin/ffmpeg.exe', `${buildDir}/bin/ffmpeg.exe`);
}
if(fs.existsSync('./bin/mkvmerge')){
// fs.copySync('./bin/mkvmerge', `${buildDir}/bin/mkvmerge`);
}
if(fs.existsSync('./bin/mkvmerge.exe')){
// fs.copySync('./bin/mkvmerge.exe', `${buildDir}/bin/mkvmerge.exe`);
}
fs.copySync('./config/bin-path.yml', `${buildDir}/config/bin-path.yml`);
fs.copySync('./config/cli-defaults.yml', `${buildDir}/config/cli-defaults.yml`);
fs.copySync('./config/dir-path.yml', `${buildDir}/config/dir-path.yml`);
fs.copySync('./cmd-here.bat', `${buildDir}/cmd-here.bat`);
fs.copySync('./docs/', `${buildDir}/docs/`);
fs.copySync('./LICENSE.md', `${buildDir}/docs/LICENSE.md`);
if(fs.existsSync(`${buildsDir}/${buildFull}.7z`)){
fs.removeSync(`${buildsDir}/${buildFull}.7z`);
}
require('child_process').execSync(`7z a -t7z "${buildsDir}/${buildFull}.7z" "${buildDir}"`,{stdio:[0,1,2]});
}());
function getTarget(bt){
switch(bt){
case 'win64':
return 'windows-x64';
case 'linux64':
return 'linux-x64';
case 'macos64':
return 'macos-x64';
default:
return 'windows-x64';
}
}

View file

@ -1,6 +1,7 @@
{
"name": "funimation-downloader-nx",
"version": "4.5.0",
"short_name": "funi",
"version": "4.5.1",
"description": "Download videos from Funimation via cli.",
"keywords": [
"download",
@ -24,14 +25,25 @@
"main": "funi.js",
"dependencies": {
"form-data": "^3.0.0",
"got": "^10.2.2",
"hls-download": "^2.3.1",
"lookpath": "^1.0.4",
"got": "^10.6.0",
"hls-download": "^2.3.2",
"lookpath": "^1.0.5",
"m3u8-parsed": "^1.2.0",
"proxy-agent": "^3.1.1",
"sei-helper": "^3.3.0",
"ttml2srt": "^1.1.0",
"yaml": "^1.7.2",
"yargs": "^15.1.0"
"yaml": "^1.8.0",
"yargs": "^15.3.0"
},
"devDependencies": {
"fs-extra": "^8.1.0",
"nexe": "^3.3.2",
"removeNPMAbsolutePaths": "^2.0.0"
},
"scripts": {
"build-win64": "node modules/build win64",
"build-linux64": "node modules/build linux64",
"build-macos64": "node modules/build macos64",
"test": "echo \"Error: no test specified\" && exit 1"
}
}