Skip to content

Commit

Permalink
Implement partial speed control
Browse files Browse the repository at this point in the history
J, K, L, however backward playing is not supported by chromium.
Also bump electron to 1.4.5
And don't use electron-compile anymore as it doesn't really give us anything
  • Loading branch information
mifi committed Nov 3, 2016
1 parent 95ed72e commit 2abacd0
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ Simple, cross platform video editor for lossless trimming / cutting of videos. G
The original video files will not be modified. Instead it creates a lossless export in the same directory as the original file with from/to timestamps. Note that the cut is currently not precise around the cutpoints, so video before/after the nearest keyframe will be lost. EXIF data is preserved.

### Keyboard shortcuts
- <kbd>SPACE</kbd> Play/pause
- <kbd>SPACE</kbd>, <kbd>k</kbd> Play/pause
- <kbd>j</kbd> Slow down video
- <kbd>l</kbd> Speed up video
- <kbd>←</kbd> Seek backward 1 sec
- <kbd>→</kbd> Seek forward 1 sec
- <kbd>.</kbd> (period) Tiny seek forward
Expand Down
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
"description": "",
"main": "index.js",
"scripts": {
"start": "electron src",
"build": "rm -rf dist && babel src -d dist --copy-files && ln -s ../node_modules dist/ && ln -s ../package.json ./dist/",
"start": "electron dist",
"watch": "npm run build && babel src -d dist --copy-files -w",
"start-dist": "./node_modules/electron-prebuilt-compile/node_modules/electron/cli.js dist",
"build": "rm -rf dist && babel src -d dist --copy-files && ln -s ../node_modules dist/ && ln -s ../package.json ./dist/",
"package": "electron-packager dist LosslessCut --out=package --asar --overwrite --all --version 1.3.8",
"zip": "(cd package && for f in LosslessCut-*; do zip -r $f; done)",
"gifify": "gifify -p 405:299 -r 5@3 Untitled.mov-00.00.00.971-00.00.19.780.mp4",
"lint": "eslint ."
},
"author": {
Expand All @@ -20,8 +21,8 @@
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"electron-packager": "^8.1.0",
"electron-prebuilt-compile": "^1.4.4",
"eslint": "^3.8.0",
"eslint-config-airbnb": "^12.0.0",
"eslint-plugin-import": "^1.16.0",
Expand All @@ -33,6 +34,7 @@
"capture-frame": "^1.0.0",
"classnames": "^2.2.5",
"configstore": "^2.1.0",
"electron": "^1.4.5",
"electron-default-menu": "^1.0.0",
"execa": "^0.5.0",
"jquery": "^3.1.1",
Expand Down
2 changes: 1 addition & 1 deletion src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ input, button, textarea, :focus {
padding: .4em;
}

.jump-cut-start, .jump-cut-end {
.jump-cut-start, .jump-cut-end, .playback-rate {
background: white;
border-radius: .3em;
color: rgba(0, 0, 0, 0.7);
Expand Down
47 changes: 40 additions & 7 deletions src/renderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class App extends React.Component {

const defaultState = {
working: false,
filePath: '', // Setting video src="" prevents memory leak
filePath: '', // Setting video src="" prevents memory leak in chromium
playing: false,
currentTime: undefined,
duration: undefined,
Expand All @@ -67,7 +67,12 @@ class App extends React.Component {

this.state = _.cloneDeep(defaultState);

const resetState = () => this.setState(defaultState);
const resetState = () => {
const video = getVideo();
video.currentTime = 0;
video.playbackRate = 1;
this.setState(defaultState);
};

const load = (filePath) => {
resetState();
Expand All @@ -88,6 +93,9 @@ class App extends React.Component {
};

keyboardJs.bind('space', () => this.playCommand());
keyboardJs.bind('k', () => this.playCommand());
keyboardJs.bind('j', () => this.changePlaybackRate(-1));
keyboardJs.bind('l', () => this.changePlaybackRate(1));
keyboardJs.bind('left', () => seekRel(-1));
keyboardJs.bind('right', () => seekRel(1));
keyboardJs.bind('period', () => shortStep(1));
Expand All @@ -98,6 +106,14 @@ class App extends React.Component {
keyboardJs.bind('o', () => this.setCutEnd());
}

onPlay(playing) {
this.setState({ playing });

if (!playing) {
getVideo().playbackRate = 1;
}
}

setCutStart() {
this.setState({ cutStartTime: this.state.currentTime });
}
Expand Down Expand Up @@ -125,11 +141,24 @@ class App extends React.Component {
setCursor((relX / $target[0].offsetWidth) * this.state.duration);
}

playCommand() {
changePlaybackRate(dir) {
const video = getVideo();
if (this.state.playing) {
return video.pause();
if (!this.state.playing) {
video.playbackRate = 0.5; // dir * 0.5;
video.play();
} else {
const newRate = video.playbackRate + (dir * 0.15);
video.playbackRate = _.clamp(newRate, 0.05, 16);
}
}

playbackRateChange() {
this.state.playbackRate = getVideo().playbackRate;
}

playCommand() {
const video = getVideo();
if (this.state.playing) return video.pause();

return video.play().catch((err) => {
console.log(err);
Expand Down Expand Up @@ -176,8 +205,9 @@ class App extends React.Component {
<div id="player">
<video
src={this.state.filePath}
onPlay={() => this.setState({ playing: true })}
onPause={() => this.setState({ playing: false })}
onRateChange={() => this.playbackRateChange()}
onPlay={() => this.onPlay(true)}
onPause={() => this.onPlay(false)}
onDurationChange={e => this.setState({ duration: e.target.duration })}
onTimeUpdate={e => this.setState({ currentTime: e.target.currentTime })}
/>
Expand Down Expand Up @@ -264,6 +294,9 @@ class App extends React.Component {
</div>

<div className="right-menu">
<button className="playback-rate" title="Playback rate">
{_.round(this.state.playbackRate, 1) || 1}x
</button>
<i
title="Capture frame"
className="button fa fa-camera"
Expand Down

0 comments on commit 2abacd0

Please sign in to comment.