Merge pull request #1712 from hicom150/change_audio_tracks
Add support for multiple audio tracks
This commit is contained in:
17
src/renderer/controllers/audio-tracks-controller.js
Normal file
17
src/renderer/controllers/audio-tracks-controller.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const { dispatch } = require('../lib/dispatcher')
|
||||||
|
|
||||||
|
module.exports = class AudioTracksController {
|
||||||
|
constructor (state) {
|
||||||
|
this.state = state
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAudioTrack (ix) {
|
||||||
|
this.state.playing.audioTracks.selectedIndex = ix
|
||||||
|
dispatch('skip', 0.2) // HACK: hardcoded seek value for smooth audio change
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleAudioTracksMenu () {
|
||||||
|
const audioTracks = this.state.playing.audioTracks
|
||||||
|
audioTracks.showMenu = !audioTracks.showMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -105,6 +105,11 @@ function getDefaultPlayState () {
|
|||||||
selectedIndex: -1, /* current subtitle track */
|
selectedIndex: -1, /* current subtitle track */
|
||||||
showMenu: false /* popover menu, above the video */
|
showMenu: false /* popover menu, above the video */
|
||||||
},
|
},
|
||||||
|
audioTracks: {
|
||||||
|
tracks: [],
|
||||||
|
selectedIndex: 0, /* current audio track */
|
||||||
|
showMenu: false /* popover menu, above the video */
|
||||||
|
},
|
||||||
aspectRatio: 0 /* aspect ratio of the video */
|
aspectRatio: 0 /* aspect ratio of the video */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,10 @@ function onState (err, _state) {
|
|||||||
const SubtitlesController = require('./controllers/subtitles-controller')
|
const SubtitlesController = require('./controllers/subtitles-controller')
|
||||||
return new SubtitlesController(state)
|
return new SubtitlesController(state)
|
||||||
}),
|
}),
|
||||||
|
audioTracks: createGetter(() => {
|
||||||
|
const AudioTracksController = require('./controllers/audio-tracks-controller')
|
||||||
|
return new AudioTracksController(state)
|
||||||
|
}),
|
||||||
torrent: createGetter(() => {
|
torrent: createGetter(() => {
|
||||||
const TorrentController = require('./controllers/torrent-controller')
|
const TorrentController = require('./controllers/torrent-controller')
|
||||||
return new TorrentController(state)
|
return new TorrentController(state)
|
||||||
@@ -281,6 +285,10 @@ const dispatchHandlers = {
|
|||||||
checkForSubtitles: () => controllers.subtitles().checkForSubtitles(),
|
checkForSubtitles: () => controllers.subtitles().checkForSubtitles(),
|
||||||
addSubtitles: (files, autoSelect) => controllers.subtitles().addSubtitles(files, autoSelect),
|
addSubtitles: (files, autoSelect) => controllers.subtitles().addSubtitles(files, autoSelect),
|
||||||
|
|
||||||
|
// Audio Tracks
|
||||||
|
selectAudioTrack: (index) => controllers.audioTracks().selectAudioTrack(index),
|
||||||
|
toggleAudioTracksMenu: () => controllers.audioTracks().toggleAudioTracksMenu(),
|
||||||
|
|
||||||
// Local media: <video>, <audio>, external players
|
// Local media: <video>, <audio>, external players
|
||||||
mediaStalled: () => controllers.media().mediaStalled(),
|
mediaStalled: () => controllers.media().mediaStalled(),
|
||||||
mediaError: (err) => controllers.media().mediaError(err),
|
mediaError: (err) => controllers.media().mediaError(err),
|
||||||
|
|||||||
@@ -95,6 +95,13 @@ function renderMedia (state) {
|
|||||||
delete file.selectedSubtitle
|
delete file.selectedSubtitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Switch to selected audio track
|
||||||
|
const audioTracks = mediaElement.audioTracks || []
|
||||||
|
for (let j = 0; j < audioTracks.length; j++) {
|
||||||
|
const isSelectedTrack = j === state.playing.audioTracks.selectedIndex
|
||||||
|
audioTracks[j].enabled = isSelectedTrack
|
||||||
|
}
|
||||||
|
|
||||||
state.playing.volume = mediaElement.volume
|
state.playing.volume = mediaElement.volume
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +174,18 @@ function renderMedia (state) {
|
|||||||
|
|
||||||
// As soon as we know the video dimensions, resize the window
|
// As soon as we know the video dimensions, resize the window
|
||||||
dispatch('setDimensions', dimensions)
|
dispatch('setDimensions', dimensions)
|
||||||
|
|
||||||
|
// set audioTracks
|
||||||
|
const tracks = []
|
||||||
|
for (let i = 0; i < mediaElement.audioTracks.length; i++) {
|
||||||
|
tracks.push({
|
||||||
|
label: mediaElement.audioTracks[i].label || `Track ${i + 1}`,
|
||||||
|
language: mediaElement.audioTracks[i].language
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
state.playing.audioTracks.tracks = tracks
|
||||||
|
state.playing.audioTracks.selectedIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we can decode audio track
|
// check if we can decode audio track
|
||||||
@@ -481,6 +500,27 @@ function renderSubtitleOptions (state) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderAudioTrackOptions (state) {
|
||||||
|
const audioTracks = state.playing.audioTracks
|
||||||
|
if (!audioTracks.tracks.length || !audioTracks.showMenu) return
|
||||||
|
|
||||||
|
const items = audioTracks.tracks.map(function (track, ix) {
|
||||||
|
const isSelected = state.playing.audioTracks.selectedIndex === ix
|
||||||
|
return (
|
||||||
|
<li key={ix} onClick={dispatcher('selectAudioTrack', ix)}>
|
||||||
|
<i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
|
||||||
|
{track.label}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul key='audio-track-options' className='options-list'>
|
||||||
|
{items}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function renderPlayerControls (state) {
|
function renderPlayerControls (state) {
|
||||||
const positionPercent = 100 * state.playing.currentTime / state.playing.duration
|
const positionPercent = 100 * state.playing.currentTime / state.playing.duration
|
||||||
const playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 3px)' }
|
const playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 3px)' }
|
||||||
@@ -489,6 +529,9 @@ function renderPlayerControls (state) {
|
|||||||
: state.playing.subtitles.selectedIndex >= 0
|
: state.playing.subtitles.selectedIndex >= 0
|
||||||
? 'active'
|
? 'active'
|
||||||
: ''
|
: ''
|
||||||
|
const multiAudioClass = state.playing.audioTracks.tracks.length > 1
|
||||||
|
? 'active'
|
||||||
|
: 'disabled'
|
||||||
const prevClass = Playlist.hasPrevious(state) ? '' : 'disabled'
|
const prevClass = Playlist.hasPrevious(state) ? '' : 'disabled'
|
||||||
const nextClass = Playlist.hasNext(state) ? '' : 'disabled'
|
const nextClass = Playlist.hasNext(state) ? '' : 'disabled'
|
||||||
|
|
||||||
@@ -553,6 +596,14 @@ function renderPlayerControls (state) {
|
|||||||
>
|
>
|
||||||
closed_caption
|
closed_caption
|
||||||
</i>
|
</i>
|
||||||
|
), (
|
||||||
|
<i
|
||||||
|
key='audio-tracks'
|
||||||
|
className={'icon multi-audio float-right ' + multiAudioClass}
|
||||||
|
onClick={handleAudioTracks}
|
||||||
|
>
|
||||||
|
library_music
|
||||||
|
</i>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,6 +710,7 @@ function renderPlayerControls (state) {
|
|||||||
{elements}
|
{elements}
|
||||||
{renderCastOptions(state)}
|
{renderCastOptions(state)}
|
||||||
{renderSubtitleOptions(state)}
|
{renderSubtitleOptions(state)}
|
||||||
|
{renderAudioTrackOptions(state)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -702,6 +754,10 @@ function renderPlayerControls (state) {
|
|||||||
dispatch('toggleSubtitlesMenu')
|
dispatch('toggleSubtitlesMenu')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAudioTracks (e) {
|
||||||
|
dispatch('toggleAudioTracksMenu')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders the loading bar. Shows which parts of the torrent are loaded, which
|
// Renders the loading bar. Shows which parts of the torrent are loaded, which
|
||||||
|
|||||||
@@ -623,6 +623,11 @@ body.drag .app::after {
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.player .controls .icon.multi-audio {
|
||||||
|
font-size: 26px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.player .controls .icon.fullscreen {
|
.player .controls .icon.fullscreen {
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
|
|||||||
Reference in New Issue
Block a user