Add additional video player keyboard shortcuts (#275)
* Skip forward 10 seconds ((CMD OR CTRL) ALT right) Skip back 10 seconds ((CMD OR CTRL) ALT left) Increase video speed ((CMD OR CTRL) +) Decrease video speed ((CMD OR CTRL) -) * Codestyle fix * The 'steps' should be implemented in base2, standard players use 1x, 2x, 4x, 8x, 16x fixed bug with shift + "=" which is "+" * resolve conflicts * remove ide specific data make playback rate more granular add to menu skip and speed entries * intendation fix * conflict resolve * rename setPlaybackRate to changePlaybackRate setRate return boolean depending on whether this cast target supports setting the playback rate. if setRate returns false - don`t change state redundant else if statement in changePlaybackRate function
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
dist
|
||||
62
main/menu.js
62
main/menu.js
@@ -92,6 +92,30 @@ function openSubtitles () {
|
||||
}
|
||||
}
|
||||
|
||||
function skipForward () {
|
||||
if (windows.main) {
|
||||
windows.main.send('dispatch', 'skip', 1)
|
||||
}
|
||||
}
|
||||
|
||||
function skipBack () {
|
||||
if (windows.main) {
|
||||
windows.main.send('dispatch', 'skip', -1)
|
||||
}
|
||||
}
|
||||
|
||||
function increasePlaybackRate () {
|
||||
if (windows.main) {
|
||||
windows.main.send('dispatch', 'changePlaybackRate', 1)
|
||||
}
|
||||
}
|
||||
|
||||
function decreasePlaybackRate () {
|
||||
if (windows.main) {
|
||||
windows.main.send('dispatch', 'changePlaybackRate', -1)
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowShow () {
|
||||
log('onWindowShow')
|
||||
getMenuItem('Full Screen').enabled = true
|
||||
@@ -110,6 +134,10 @@ function onPlayerOpen () {
|
||||
getMenuItem('Increase Volume').enabled = true
|
||||
getMenuItem('Decrease Volume').enabled = true
|
||||
getMenuItem('Add Subtitles File...').enabled = true
|
||||
getMenuItem('Skip forward 10 seconds').enabled = true
|
||||
getMenuItem('Skip back 10 seconds').enabled = true
|
||||
getMenuItem('Increase video speed').enabled = true
|
||||
getMenuItem('Decrease video speed').enabled = true
|
||||
}
|
||||
|
||||
function onPlayerClose () {
|
||||
@@ -118,6 +146,10 @@ function onPlayerClose () {
|
||||
getMenuItem('Increase Volume').enabled = false
|
||||
getMenuItem('Decrease Volume').enabled = false
|
||||
getMenuItem('Add Subtitles File...').enabled = false
|
||||
getMenuItem('Skip forward 10 seconds').enabled = false
|
||||
getMenuItem('Skip back 10 seconds').enabled = false
|
||||
getMenuItem('Increase video speed').enabled = false
|
||||
getMenuItem('Decrease video speed').enabled = false
|
||||
}
|
||||
|
||||
function onToggleFullScreen (isFullScreen) {
|
||||
@@ -311,6 +343,36 @@ function getAppMenuTemplate () {
|
||||
label: 'Add Subtitles File...',
|
||||
click: openSubtitles,
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Skip forward 10 seconds',
|
||||
accelerator: 'CmdOrCtrl+Alt+Right',
|
||||
click: skipForward,
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
label: 'Skip back 10 seconds',
|
||||
accelerator: 'CmdOrCtrl+Alt+Left',
|
||||
click: skipBack,
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Increase video speed',
|
||||
accelerator: 'CmdOrCtrl+plus',
|
||||
click: increasePlaybackRate,
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
label: 'Decrease video speed',
|
||||
accelerator: 'CmdOrCtrl+-',
|
||||
click: decreasePlaybackRate,
|
||||
enabled: false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -748,6 +748,13 @@ body.drag .app::after {
|
||||
padding: 5px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.player-controls .rate {
|
||||
display: inline;
|
||||
height: 30px;
|
||||
padding: 5px;
|
||||
margin-left: 20px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.player-controls .device,
|
||||
.player-controls .fullscreen,
|
||||
|
||||
@@ -285,6 +285,12 @@ function dispatch (action, ...args) {
|
||||
if (action === 'playbackJump') {
|
||||
jumpToTime(args[0] /* seconds */)
|
||||
}
|
||||
if (action === 'skip') {
|
||||
jumpToTime(state.playing.currentTime + (args[0] /* direction */ * 10))
|
||||
}
|
||||
if (action === 'changePlaybackRate') {
|
||||
changePlaybackRate(args[0] /* direction */)
|
||||
}
|
||||
if (action === 'changeVolume') {
|
||||
changeVolume(args[0] /* increase */)
|
||||
}
|
||||
@@ -399,7 +405,26 @@ function jumpToTime (time) {
|
||||
state.playing.jumpToTime = time
|
||||
}
|
||||
}
|
||||
|
||||
function changePlaybackRate (direction) {
|
||||
var rate = state.playing.playbackRate
|
||||
if (direction > 0 && rate >= 0.25 && rate < 2) {
|
||||
rate += 0.25
|
||||
} else if (direction < 0 && rate > 0.25 && rate <= 2) {
|
||||
rate -= 0.25
|
||||
} else if (direction < 0 && rate === 0.25) { /* when we set playback rate at 0 in html 5, playback hangs ;( */
|
||||
rate = -1
|
||||
} else if (direction > 0 && rate === -1) {
|
||||
rate = 0.25
|
||||
} else if ((direction > 0 && rate >= 1 && rate < 16) || (direction < 0 && rate > -16 && rate <= -1)) {
|
||||
rate *= 2
|
||||
} else if ((direction < 0 && rate > 1 && rate <= 16) || (direction > 0 && rate >= -16 && rate < -1)) {
|
||||
rate /= 2
|
||||
}
|
||||
state.playing.playbackRate = rate
|
||||
if (lazyLoadCast().isCasting() && !Cast.setRate(rate)) {
|
||||
state.playing.playbackRate = 1
|
||||
}
|
||||
}
|
||||
function changeVolume (delta) {
|
||||
// change volume with delta value
|
||||
setVolume(state.playing.volume + delta)
|
||||
|
||||
@@ -8,7 +8,8 @@ module.exports = {
|
||||
play,
|
||||
pause,
|
||||
seek,
|
||||
setVolume
|
||||
setVolume,
|
||||
setRate
|
||||
}
|
||||
|
||||
var airplay = require('airplay-js')
|
||||
@@ -344,6 +345,22 @@ function pause () {
|
||||
}
|
||||
}
|
||||
|
||||
function setRate (rate) {
|
||||
var device
|
||||
var result = true
|
||||
if (state.playing.location === 'chromecast') {
|
||||
// TODO find how to control playback rate on chromecast
|
||||
castCallback()
|
||||
result = false
|
||||
} else if (state.playing.location === 'airplay') {
|
||||
device = state.devices.airplay
|
||||
device.rate(rate, castCallback)
|
||||
} else {
|
||||
result = false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function seek (time) {
|
||||
var device = getDevice()
|
||||
if (device) {
|
||||
|
||||
@@ -80,6 +80,7 @@ function getDefaultPlayState () {
|
||||
isStalled: false,
|
||||
lastTimeUpdate: 0, /* Unix time in ms */
|
||||
mouseStationarySince: 0, /* Unix time in ms */
|
||||
playbackRate: 1,
|
||||
subtitles: {
|
||||
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
||||
selectedIndex: -1, /* current subtitle track */
|
||||
|
||||
@@ -26,7 +26,8 @@ function App (state) {
|
||||
state.playing.mouseStationarySince !== 0 &&
|
||||
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
||||
!state.playing.isPaused &&
|
||||
state.playing.location === 'local'
|
||||
state.playing.location === 'local' &&
|
||||
state.playing.playbackRate === 1
|
||||
|
||||
// Hide the header on Windows/Linux when in the player
|
||||
// On OSX, the header appears as part of the title bar
|
||||
|
||||
@@ -48,6 +48,9 @@ function renderMedia (state) {
|
||||
mediaElement.currentTime = state.playing.jumpToTime
|
||||
state.playing.jumpToTime = null
|
||||
}
|
||||
if (state.playing.playbackRate !== mediaElement.playbackRate) {
|
||||
mediaElement.playbackRate = state.playing.playbackRate
|
||||
}
|
||||
// Set volume
|
||||
if (state.playing.setVolume !== null && isFinite(state.playing.setVolume)) {
|
||||
mediaElement.volume = state.playing.setVolume
|
||||
@@ -440,6 +443,12 @@ function renderPlayerControls (state) {
|
||||
</span>
|
||||
`)
|
||||
|
||||
// render playback rate
|
||||
if (state.playing.playbackRate !== 1) {
|
||||
elements.push(hx`
|
||||
<span class="rate">speed: ${state.playing.playbackRate}X</span>
|
||||
`)
|
||||
}
|
||||
// Finally, the big button in the center plays or pauses the video
|
||||
elements.push(hx`
|
||||
<i class='icon play-pause' onclick=${dispatcher('playPause')}>
|
||||
|
||||
Reference in New Issue
Block a user