mirror of https://github.com/mifi/lossless-cut
Adds support for more formats by detecting format and using same format for output file (don't always use mp4)
Also: Improve ffmpeg error handling React enable production Improve react rendering a bitpull/13/head
parent
3851cb264f
commit
cce542af41
@ -1,25 +1,74 @@
|
|||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const bluebird = require('bluebird');
|
const bluebird = require('bluebird');
|
||||||
const which = bluebird.promisify(require('which'));
|
const which = bluebird.promisify(require('which'));
|
||||||
|
const path = require('path');
|
||||||
|
const util = require('./util');
|
||||||
|
|
||||||
const Configstore = require('configstore');
|
const Configstore = require('configstore');
|
||||||
|
|
||||||
const configstore = new Configstore('lossless-cut', { ffmpegPath: '' });
|
const configstore = new Configstore('lossless-cut', { ffmpegPath: '' });
|
||||||
|
|
||||||
|
|
||||||
module.exports.cut = (filePath, cutFrom, cutTo, outFile) => {
|
function showFfmpegFail(err) {
|
||||||
console.log('Cutting from', cutFrom, 'to', cutTo);
|
alert('Failed to run ffmpeg, make sure you have it installed and in available in your PATH or set its path (from the file menu)');
|
||||||
|
console.error(err.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFfmpegPath() {
|
||||||
return which('ffmpeg')
|
return which('ffmpeg')
|
||||||
.catch(() => configstore.get('ffmpegPath'))
|
.catch(() => configstore.get('ffmpegPath'));
|
||||||
.then(ffmpegPath => execa(ffmpegPath, [
|
}
|
||||||
'-i', filePath, '-y', '-vcodec', 'copy', '-acodec', 'copy', '-ss', cutFrom, '-t', cutTo - cutFrom, outFile,
|
|
||||||
]))
|
function cut(filePath, format, cutFrom, cutTo) {
|
||||||
|
const ext = path.extname(filePath) || format;
|
||||||
|
const outFileAppend = `${util.formatDuration(cutFrom)}-${util.formatDuration(cutTo)}`;
|
||||||
|
const outFile = `${filePath}-${outFileAppend}.${ext}`;
|
||||||
|
|
||||||
|
console.log('Cutting from', cutFrom, 'to', cutTo);
|
||||||
|
|
||||||
|
const ffmpegArgs = [
|
||||||
|
'-i', filePath, '-y', '-vcodec', 'copy', '-acodec', 'copy',
|
||||||
|
'-ss', cutFrom, '-t', cutTo - cutFrom,
|
||||||
|
'-f', format,
|
||||||
|
outFile,
|
||||||
|
];
|
||||||
|
|
||||||
|
console.log('ffmpeg', ffmpegArgs.join(' '));
|
||||||
|
|
||||||
|
return getFfmpegPath()
|
||||||
|
.then(ffmpegPath => execa(ffmpegPath, ffmpegArgs))
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
console.log(result.stdout);
|
console.log(result.stdout);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err.stack);
|
if (err.code === 1) {
|
||||||
alert(`Failed to run ffmpeg, make sure you have it installed and in available in your PATH or its path configured in ${configstore.path}`);
|
alert('Whoops! ffmpeg was unable to cut this video. It may be of an unknown format or codec combination');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showFfmpegFail(err);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFormats(filePath) {
|
||||||
|
console.log('getFormat', filePath);
|
||||||
|
|
||||||
|
return getFfmpegPath()
|
||||||
|
.then(ffmpegPath => path.join(path.dirname(ffmpegPath), 'ffprobe'))
|
||||||
|
.then(ffprobePath => execa(ffprobePath, [
|
||||||
|
'-of', 'json', '-show_format', '-i', filePath,
|
||||||
|
]))
|
||||||
|
.then((result) => {
|
||||||
|
const formatsStr = JSON.parse(result.stdout).format.format_name;
|
||||||
|
console.log('formats', formatsStr);
|
||||||
|
const formats = formatsStr.split(',');
|
||||||
|
return formats;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// '-of', 'json', '-select_streams', 'v', '-show_frames', filePath,
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
cut,
|
||||||
|
getFormats,
|
||||||
|
showFfmpegFail,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
function formatDuration(_seconds) {
|
||||||
|
const seconds = _seconds || 0;
|
||||||
|
const minutes = seconds / 60;
|
||||||
|
const hours = minutes / 60;
|
||||||
|
|
||||||
|
const hoursPadded = _.padStart(Math.floor(hours), 2, '0');
|
||||||
|
const minutesPadded = _.padStart(Math.floor(minutes % 60), 2, '0');
|
||||||
|
const secondsPadded = _.padStart(Math.floor(seconds) % 60, 2, '0');
|
||||||
|
const msPadded = _.padStart(Math.floor((seconds - Math.floor(seconds)) * 1000), 3, '0');
|
||||||
|
|
||||||
|
// Be nice to filenames and use .
|
||||||
|
return `${hoursPadded}.${minutesPadded}.${secondsPadded}.${msPadded}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
formatDuration,
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue