1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-25 03:33:14 +01:00

modernize code and use sweetalert2

This commit is contained in:
Mikael Finstad 2019-01-28 00:21:53 +01:00
parent 328a2cd6f8
commit 8817c2c80b
5 changed files with 113 additions and 43 deletions

View File

@ -6,9 +6,9 @@
"browser": true,
},
"rules": {
"no-alert": 0,
"no-console": 0,
"react/destructuring-assignment": 0,
"react/forbid-prop-types": [1, { "forbid": ["any"] }],
},
"plugins": [
"react"

View File

@ -2,7 +2,6 @@ const execa = require('execa');
const bluebird = require('bluebird');
const which = bluebird.promisify(require('which'));
const path = require('path');
const fs = require('fs');
const fileType = require('file-type');
const readChunk = require('read-chunk');
const _ = require('lodash');
@ -11,14 +10,6 @@ const moment = require('moment');
const util = require('./util');
bluebird.promisifyAll(fs);
function showFfmpegFail(err) {
alert(`Failed to run ffmpeg:\n${err.stack}`);
console.error(err.stack);
}
function getWithExt(name) {
return process.platform === 'win32' ? `${name}.exe` : name;
}
@ -187,6 +178,5 @@ function getFormat(filePath) {
module.exports = {
cut,
getFormat,
showFfmpegFail,
html5ify,
};

View File

@ -15,7 +15,10 @@ const classnames = require('classnames');
const captureFrame = require('./capture-frame');
const ffmpeg = require('./ffmpeg');
const util = require('./util');
const {
getOutPath, parseDuration, formatDuration, toast, errorToast, showFfmpegFail,
} = require('./util');
const { dialog } = electron.remote;
@ -122,30 +125,36 @@ class App extends React.Component {
...globalState,
};
const load = (filePath, html5FriendlyPath) => {
const load = async (filePath, html5FriendlyPath) => {
const { working } = this.state;
console.log('Load', { filePath, html5FriendlyPath });
if (working) return alert('I\'m busy');
if (working) {
errorToast('I\'m busy');
return;
}
this.resetState();
this.setState({ working: true });
return ffmpeg.getFormat(filePath)
.then((fileFormat) => {
if (!fileFormat) return alert('Unsupported file');
setFileNameTitle(filePath);
return this.setState({ filePath, html5FriendlyPath, fileFormat });
})
.catch((err) => {
if (err.code === 1 || err.code === 'ENOENT') {
alert('Unsupported file');
try {
const fileFormat = await ffmpeg.getFormat(filePath);
if (!fileFormat) {
errorToast('Unsupported file');
return;
}
ffmpeg.showFfmpegFail(err);
})
.finally(() => this.setState({ working: false }));
setFileNameTitle(filePath);
this.setState({ filePath, html5FriendlyPath, fileFormat });
} catch (err) {
if (err.code === 1 || err.code === 'ENOENT') {
errorToast('Unsupported file');
return;
}
showFfmpegFail(err);
} finally {
this.setState({ working: false });
}
};
electron.ipcRenderer.on('file-opened', (event, filePaths) => {
@ -159,12 +168,12 @@ class App extends React.Component {
try {
this.setState({ working: true });
const html5ifiedPath = util.getOutPath(customOutDir, filePath, 'html5ified.mp4');
const html5ifiedPath = getOutPath(customOutDir, filePath, 'html5ified.mp4');
await ffmpeg.html5ify(filePath, html5ifiedPath, encodeVideo);
this.setState({ working: false });
load(filePath, html5ifiedPath);
} catch (err) {
alert('Failed to html5ify file');
errorToast('Failed to html5ify file');
console.error('Failed to html5ify file', err);
this.setState({ working: false });
}
@ -184,7 +193,7 @@ class App extends React.Component {
return undefined;
}
const duration = util.parseDuration(value);
const duration = parseDuration(value);
// Invalid, try again
if (duration === undefined) return promptTimeOffset(value);
@ -194,7 +203,7 @@ class App extends React.Component {
electron.ipcRenderer.on('set-start-offset', async () => {
const { startTimeOffset: startTimeOffsetOld } = this.state;
const startTimeOffset = await promptTimeOffset(
startTimeOffsetOld !== undefined ? util.formatDuration(startTimeOffsetOld) : undefined,
startTimeOffsetOld !== undefined ? formatDuration(startTimeOffsetOld) : undefined,
);
if (startTimeOffset === undefined) {
@ -210,7 +219,10 @@ class App extends React.Component {
document.body.ondrop = (ev) => {
ev.preventDefault();
if (ev.dataTransfer.files.length !== 1) return;
if (ev.dataTransfer.files.length !== 1) {
errorToast('Please drop only one file');
return;
}
load(ev.dataTransfer.files[0].path);
};
@ -337,12 +349,13 @@ class App extends React.Component {
return video.play().catch((err) => {
console.log(err);
if (err.name === 'NotSupportedError') {
alert('This video format or codec is not supported. Try to convert it to a friendly format/codec in the player from the "File" menu. Note that this will only create a temporary, low quality encoded file used for previewing your cuts, and will not affect the final cut. The final cut will still be lossless. Audio is also removed to make it faster, but only in the preview.');
toast({ type: 'error', title: 'This format/codec is not supported. Try to convert it to a friendly format/codec in the player from the "File" menu. Note that this will only create a temporary, low quality encoded file used for previewing your cuts, and will not affect the final cut. The final cut will still be lossless. Audio is also removed to make it faster, but only in the preview.', timer: 10000 });
}
});
}
deleteSourceClick = async () => {
// eslint-disable-next-line no-alert
if (this.state.working || !window.confirm('Are you sure you want to move the source file to trash?')) return;
const { filePath } = this.state;
@ -352,7 +365,10 @@ class App extends React.Component {
}
cutClick = async () => {
if (this.state.working) return alert('I\'m busy');
if (this.state.working) {
errorToast('I\'m busy');
return;
}
const {
cutStartTime, cutEndTime, filePath, customOutDir, fileFormat, duration, includeAllStreams,
@ -362,12 +378,13 @@ class App extends React.Component {
const rotation = this.isRotationSet() ? this.getRotation() : undefined;
if (!this.isCutRangeValid()) {
return alert('Start time must be before end time');
errorToast('Start time must be before end time');
return;
}
this.setState({ working: true });
try {
return await ffmpeg.cut({
await ffmpeg.cut({
customOutDir,
filePath,
format: fileFormat,
@ -386,21 +403,26 @@ class App extends React.Component {
console.error('stderr:', err.stderr);
if (err.code === 1 || err.code === 'ENOENT') {
return alert('Whoops! ffmpeg was unable to cut this video. It may be of an unknown format or codec combination');
errorToast('Whoops! ffmpeg was unable to cut this video. It may be of an unknown format or codec combination');
return;
}
return ffmpeg.showFfmpegFail(err);
showFfmpegFail(err);
} finally {
this.setState({ working: false });
}
}
capture = () => {
capture = async () => {
const {
filePath, customOutDir: outputDir, currentTime, captureFormat,
} = this.state;
if (!filePath) return;
captureFrame(outputDir, filePath, getVideo(), currentTime, captureFormat)
.catch(err => alert(err));
try {
await captureFrame(outputDir, filePath, getVideo(), currentTime, captureFormat);
} catch (err) {
console.error(err);
errorToast('Failed to capture frame');
}
}
changePlaybackRate(dir) {
@ -448,7 +470,7 @@ class App extends React.Component {
return;
}
const time = util.parseDuration(text);
const time = parseDuration(text);
if (time === undefined) {
this.setState({ [cutTimeManualKey]: text });
return;
@ -470,7 +492,7 @@ class App extends React.Component {
onChange={e => handleCutTimeInput(e.target.value)}
value={isCutTimeManualSet()
? this.state[cutTimeManualKey]
: util.formatDuration(cutTime + this.state.startTimeOffset)
: formatDuration(cutTime + this.state.startTimeOffset)
}
/>
);
@ -539,7 +561,7 @@ class App extends React.Component {
)
}
<div id="current-time-display">{util.formatDuration(this.getOffsetCurrentTime())}</div>
<div id="current-time-display">{formatDuration(this.getOffsetCurrentTime())}</div>
</div>
</Hammer>

View File

@ -1,6 +1,7 @@
const _ = require('lodash');
const path = require('path');
const fs = require('fs');
const swal = require('sweetalert2');
function formatDuration(_seconds, fileNameFriendly) {
const seconds = _seconds || 0;
@ -57,10 +58,31 @@ async function transferTimestampsWithOffset(inPath, outPath, offset) {
}
}
const toast = swal.mixin({
toast: true,
position: 'top',
showConfirmButton: false,
timer: 3000,
});
const errorToast = title => toast({
type: 'error',
title,
});
async function showFfmpegFail(err) {
console.error(err);
return errorToast(`Failed to run ffmpeg: ${err.stack}`);
}
module.exports = {
formatDuration,
parseDuration,
getOutPath,
transferTimestamps,
transferTimestampsWithOffset,
toast,
errorToast,
showFfmpegFail,
};

View File

@ -57,6 +57,13 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.2.tgz#85c5c47af6d244fab77bce6b9bd830e38c978409"
integrity sha512-x5HFsW+E/nQalGMw7hu+fvPqnBeBaIr0lWJ2SG0PPL2j+Pm9lYvCrsZJGIgauPIENx0v10INIyFjmSNUD/gSqQ==
"@babel/runtime@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f"
integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==
dependencies:
regenerator-runtime "^0.12.0"
"@babel/template@^7.1.0":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644"
@ -2733,6 +2740,13 @@ invariant@^2.2.2:
dependencies:
loose-envify "^1.0.0"
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
@ -3847,7 +3861,7 @@ prop-types@^15.5.10:
loose-envify "^1.3.1"
object-assign "^4.1.1"
prop-types@^15.6.2:
prop-types@^15.5.7, prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==
@ -3935,6 +3949,15 @@ react-hammerjs@^0.5.0:
dependencies:
hammerjs "^2.0.8"
react-sortable-hoc@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-1.4.0.tgz#b477ce700ba755754200a1dabd36e588e2f5608d"
integrity sha512-4++hdwMTrzpOHcqndi2M2gEsqgoGMGmmYzs3wp/xZdap/d8oT2yUR3m6STNi1d1trRyl9Ud0C54agbYH7XdQAQ==
dependencies:
"@babel/runtime" "^7.2.0"
invariant "^2.2.4"
prop-types "^15.5.7"
react@^15.3.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
@ -4041,7 +4064,7 @@ readable-stream@^2.0.6, readable-stream@^2.1.4:
string_decoder "~1.0.0"
util-deprecate "~1.0.1"
readable-stream@^2.2.2:
readable-stream@^2.1.0, readable-stream@^2.2.2:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
@ -4107,6 +4130,11 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.12.0:
version "0.12.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-transform@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
@ -4489,6 +4517,14 @@ sshpk@^1.7.0:
jsbn "~0.1.0"
tweetnacl "~0.14.0"
string-to-stream@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string-to-stream/-/string-to-stream-1.1.1.tgz#aba78f73e70661b130ee3e1c0192be4fef6cb599"
integrity sha512-QySF2+3Rwq0SdO3s7BAp4x+c3qsClpPQ6abAmb0DGViiSBAkT5kL6JT2iyzEVP+T1SmzHrQD1TwlP9QAHCc+Sw==
dependencies:
inherits "^2.0.1"
readable-stream "^2.1.0"
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"