Skip to content

Instantly share code, notes, and snippets.

@jixunmoe
Last active June 21, 2018 01:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jixunmoe/11126485 to your computer and use it in GitHub Desktop.
Save jixunmoe/11126485 to your computer and use it in GitHub Desktop.
渣浪后黑脚本

前言

移植自 Dant 的 FlvPatcher [http://danknest.org]
> https://github.com/dantmnf/FlvPatcher/blob/master/blacker.sh

兼容说明

于 Linux Mint 16 下测试通过。

需要的依赖项安装 (完整):

sudo apt-get install libav-tools ffmsindex mkvtoolnix mediainfo nodejs && npm install sequence
※ 如果提示找不到 libav-tools 请改成 ffmpeg

使用方法:

nodejs sinaFlvBlacker.js [参数] --input "输入文件" [--output "输出路径"]

参数列表

--overwrite
  覆盖输出路径。

--avconv <1/0>
  是否使用 avconv, 1 启用 0 改用 ffmpeg; 非 Win 下该选项默认启用 (Linux Mint 必须)。

--verbose
  输出详细日志, 包括各个指令的输出

--mediainfo
  后黑完毕后调用 mediainfo 指令查询比特率; 如果制定了 verbose 则输出完整数据。

用法演示

最精简用法 (生成的文件将写出到同级目录的 Gintama.S01E01.xxx.buggy.flv 下):
nodejs sinaFlvBlacker.js --input Gintama.S01E01.xxx.mp4

var fs = require ('fs'),
cp = require ('child_process'),
u = require ('util'),
sq = require ('sequence').Sequence;
(function (undefined) {
'use strict';
if (typeof window != 'undefined' || typeof require != 'function')
// Not node js :<
throw new TypeError('You should run this script under NodeJS: http://nodejs.org/');
process.stdout.write ('Parse command line... ');
// Parse command line
for (var i=2, curFlag, __FLAG__ = {}; i<process.argv.length; i++) {
if (!process.argv[i].indexOf ('--')) {
// Begin with --
// Which sets the current flag value.
curFlag = process.argv[i].slice(2);
__FLAG__[curFlag] = [];
} else if (curFlag && __FLAG__[curFlag]) {
__FLAG__[curFlag].push (process.argv[i]);
}
}
for (var x in __FLAG__) __FLAG__[x] = __FLAG__[x].join(' ');
var hasFlag = function (flag) { return __FLAG__[flag] !== undefined; },
_ = function (fooo) { return fooo.toString().match(/\/\*\s?([\s\S]+)\s*\*\//)[1]; };
process.stdout.write ('Checking flags... ');
// If is not windows and avconv flag not specified, set avconv to true.
if (process.platform.indexOf('win') && !hasFlag('avconv'))
__FLAG__.avconv = 1;
var ffmpeg = __FLAG__.avconv ? 'avconv' : 'ffmpeg',
isDebug = hasFlag ('verbose');
var sprintf = function () {
var ret = u.format.apply(this, arguments);
if (isDebug) console.log ('> %s', ret);
return ret;
};
if (hasFlag('help')) {
process.stdout.write('\r');
console.log(_(function () {/*
# Sina FLV Blacker for node ver 1.0 By Jixun #
Should work under windows, not tested.
Ported from FlvPatcher by Dant[http://danknest.org]
> https://github.com/dantmnf/FlvPatcher/blob/master/blacker.sh
## Usage:
> nodejs [script] [--options] --input <Source file> --output [Output path]
## Extra:
--overwrite
Overwrite exist file contents.
--avconv <1/0>
Uses avconv instead of ffmpeg to encode video, default true for linux
--verbose
Print console output after each command.
--mediainfo
Execute mediainfo after finish.
## FAQ:
Command not found errors
> Ubuntu based: sudo apt-get install ffmpeg ffmsindex mkvtoolnix mediainfo
> Windows: Just place the exe here.
> Other: Install its binarys.
*/}).replace('[script]', process.argv[1].replace(/.+(\/|\\)/, '')));
process.exit (0);
}
if (!__FLAG__.input || !fs.existsSync(__FLAG__.input)) {
console.error ("Input argument missing or the file doesn\'t exist, exit (1).");
process.exit (1);
}
var inputPath = __FLAG__.input;
// Measure file size
var inputFileSize = fs.statSync(inputPath).size;
if (!inputFileSize) {
console.error ("Input file size is 0, exit (3)");
process.exit (3);
}
if (!__FLAG__.output) __FLAG__.output = inputPath.replace(/\.[^.]+$/, '') + '.buggy.flv';
if (fs.existsSync(__FLAG__.output) && !hasFlag('overwrite')) {
console.error ("Output exists without --overwrite flag specified, exit (2).");
process.exit (2);
}
var outputPath = __FLAG__.output;
var targetBitrate = parseInt (__FLAG__.bitrate);
if (targetBitrate <= 0 || targetBitrate > 1000 || !targetBitrate) {
targetBitrate = 740;
console.log ('Invalid target bitrate, changed to %s.', targetBitrate);
}
console.log ('Ready.');
// Generate temp file name.
var tmpFile = (__FLAG__.tmp || '.') + '/.tmp-' + (+new Date()) + '-' + Math.random(),
tmpPatch = tmpFile + 'patch.mkv',
tmpJoin = tmpFile + 'joined.mkv',
tmpTC = tmpFile + '_track00.tc.txt';
console.log ('Exporting tc file to %s ...', tmpTC);
sq.create().then(function (next) {
console.log ('Generate time code ...');
cp.exec (sprintf('ffmsindex -c "%s" "%s"', inputPath, tmpFile), next);
}).then(function (next, error, stdout, stderr) {
if (isDebug) console.log (stderr || stdout || '> Nothing coming out');
console.log ('Generate black patch ...');
cp.exec (sprintf('%s -i "%s" -c copy -frames:v 3 -- "%s"', ffmpeg, inputPath, tmpPatch), next);
}).then(function (next, error, stdout, stderr) {
if (isDebug) console.log (stderr || stdout || '> Nothing coming out');
var hFile = fs.openSync (tmpTC, 'a');
var appendBlackTime = function (strToWrite) {
var buf = new Buffer(strToWrite + '\n');
fs.writeSync (hFile, buf, 0, buf.length);
};
// 这里的计算和原版有少许不同的样子… 不过大致还是正确的。
var blackTime = (( (inputFileSize + fs.statSync(tmpPatch).size) / targetBitrate ) * 8000).toFixed(8);
console.log ('Black time: %s', blackTime);
for (var i=0; i<3; i++)
appendBlackTime (blackTime + i * 60);
fs.close(hFile, next);
}).then(function (next, error, stdout, stderr) {
if (isDebug) console.log (stderr || stdout || '> Nothing coming out');
console.log ('Join the old video and new one ...');
cp.exec (sprintf('mkvmerge -o "%s" --timecodes "0:%s" \\( "%s" \\) + \\( "%s" \\) --track-order "0:0,0:1"',
tmpJoin, tmpTC, inputPath, tmpPatch
), next);
}).then(function (next, error, stdout, stderr) {
if (isDebug) console.log (stderr || stdout || '> Nothing coming out');
console.log ('Convert to flv ...');
cp.exec (sprintf('%s -f matroska -i "%s" -c copy -f flv -y -- "%s"', ffmpeg, tmpJoin, outputPath), next);
}).then(function (next, error, stdout, stderr) {
if (isDebug) console.log (stderr || stdout || '> Nothing coming out');
process.stdout.write ('Clean up... ');
[tmpFile, tmpJoin, tmpPatch, tmpTC].forEach(fs.unlinkSync);
console.log ('done.');
if (hasFlag('mediainfo')) {
console.log ();
cp.exec(sprintf('mediainfo %s', outputPath), function (error, stdout, stderr) {
var mediainfo = stderr || stdout || '> Nothing coming out';
if (isDebug) {
console.log (mediainfo);
} else {
console.log (mediainfo.match(/.+bit\s*rate.*/)[0]);
}
process.exit (0);
});
} else {
process.exit (0);
}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment