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:
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 () {
|
function onWindowShow () {
|
||||||
log('onWindowShow')
|
log('onWindowShow')
|
||||||
getMenuItem('Full Screen').enabled = true
|
getMenuItem('Full Screen').enabled = true
|
||||||
@@ -110,6 +134,10 @@ function onPlayerOpen () {
|
|||||||
getMenuItem('Increase Volume').enabled = true
|
getMenuItem('Increase Volume').enabled = true
|
||||||
getMenuItem('Decrease Volume').enabled = true
|
getMenuItem('Decrease Volume').enabled = true
|
||||||
getMenuItem('Add Subtitles File...').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 () {
|
function onPlayerClose () {
|
||||||
@@ -118,6 +146,10 @@ function onPlayerClose () {
|
|||||||
getMenuItem('Increase Volume').enabled = false
|
getMenuItem('Increase Volume').enabled = false
|
||||||
getMenuItem('Decrease Volume').enabled = false
|
getMenuItem('Decrease Volume').enabled = false
|
||||||
getMenuItem('Add Subtitles File...').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) {
|
function onToggleFullScreen (isFullScreen) {
|
||||||
@@ -311,6 +343,36 @@ function getAppMenuTemplate () {
|
|||||||
label: 'Add Subtitles File...',
|
label: 'Add Subtitles File...',
|
||||||
click: openSubtitles,
|
click: openSubtitles,
|
||||||
enabled: false
|
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;
|
padding: 5px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
.player-controls .rate {
|
||||||
|
display: inline;
|
||||||
|
height: 30px;
|
||||||
|
padding: 5px;
|
||||||
|
margin-left: 20px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
.player-controls .device,
|
.player-controls .device,
|
||||||
.player-controls .fullscreen,
|
.player-controls .fullscreen,
|
||||||
|
|||||||
@@ -285,6 +285,12 @@ function dispatch (action, ...args) {
|
|||||||
if (action === 'playbackJump') {
|
if (action === 'playbackJump') {
|
||||||
jumpToTime(args[0] /* seconds */)
|
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') {
|
if (action === 'changeVolume') {
|
||||||
changeVolume(args[0] /* increase */)
|
changeVolume(args[0] /* increase */)
|
||||||
}
|
}
|
||||||
@@ -399,7 +405,26 @@ function jumpToTime (time) {
|
|||||||
state.playing.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) {
|
function changeVolume (delta) {
|
||||||
// change volume with delta value
|
// change volume with delta value
|
||||||
setVolume(state.playing.volume + delta)
|
setVolume(state.playing.volume + delta)
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ module.exports = {
|
|||||||
play,
|
play,
|
||||||
pause,
|
pause,
|
||||||
seek,
|
seek,
|
||||||
setVolume
|
setVolume,
|
||||||
|
setRate
|
||||||
}
|
}
|
||||||
|
|
||||||
var airplay = require('airplay-js')
|
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) {
|
function seek (time) {
|
||||||
var device = getDevice()
|
var device = getDevice()
|
||||||
if (device) {
|
if (device) {
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ function getDefaultPlayState () {
|
|||||||
isStalled: false,
|
isStalled: false,
|
||||||
lastTimeUpdate: 0, /* Unix time in ms */
|
lastTimeUpdate: 0, /* Unix time in ms */
|
||||||
mouseStationarySince: 0, /* Unix time in ms */
|
mouseStationarySince: 0, /* Unix time in ms */
|
||||||
|
playbackRate: 1,
|
||||||
subtitles: {
|
subtitles: {
|
||||||
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
||||||
selectedIndex: -1, /* current subtitle track */
|
selectedIndex: -1, /* current subtitle track */
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ function App (state) {
|
|||||||
state.playing.mouseStationarySince !== 0 &&
|
state.playing.mouseStationarySince !== 0 &&
|
||||||
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
||||||
!state.playing.isPaused &&
|
!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
|
// Hide the header on Windows/Linux when in the player
|
||||||
// On OSX, the header appears as part of the title bar
|
// On OSX, the header appears as part of the title bar
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ function renderMedia (state) {
|
|||||||
mediaElement.currentTime = state.playing.jumpToTime
|
mediaElement.currentTime = state.playing.jumpToTime
|
||||||
state.playing.jumpToTime = null
|
state.playing.jumpToTime = null
|
||||||
}
|
}
|
||||||
|
if (state.playing.playbackRate !== mediaElement.playbackRate) {
|
||||||
|
mediaElement.playbackRate = state.playing.playbackRate
|
||||||
|
}
|
||||||
// Set volume
|
// Set volume
|
||||||
if (state.playing.setVolume !== null && isFinite(state.playing.setVolume)) {
|
if (state.playing.setVolume !== null && isFinite(state.playing.setVolume)) {
|
||||||
mediaElement.volume = state.playing.setVolume
|
mediaElement.volume = state.playing.setVolume
|
||||||
@@ -440,6 +443,12 @@ function renderPlayerControls (state) {
|
|||||||
</span>
|
</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
|
// Finally, the big button in the center plays or pauses the video
|
||||||
elements.push(hx`
|
elements.push(hx`
|
||||||
<i class='icon play-pause' onclick=${dispatcher('playPause')}>
|
<i class='icon play-pause' onclick=${dispatcher('playPause')}>
|
||||||
|
|||||||
Reference in New Issue
Block a user