Implemented support for multiple subtitle tracks
This commit is contained in:
parent
110376146f
commit
0a56ad07b4
167
multiplayer.js
167
multiplayer.js
@ -498,25 +498,13 @@
|
||||
'title': 'Kopiera länk till den här tidpunkten',
|
||||
'data-title_en': 'Copy URL at current time'},
|
||||
[createIcon(['timelink'])]);
|
||||
this._subtitlesButton = parent.createChild(
|
||||
'button',
|
||||
{'id': 'subtitles-button',
|
||||
'title': 'Undertexter är av',
|
||||
'class': 'hidden',
|
||||
'data-title_alt': 'Undertexter är på',
|
||||
'data-title_en': 'Subtitles are off',
|
||||
'data-title_alt_en': 'Subtitles are on'},
|
||||
[createIcon(['subtitles-off',
|
||||
'subtitles-on'])]);
|
||||
this._subtitlesButton.addEventListener('click', (event) => {
|
||||
const track = this._mainSource.textTracks[0];
|
||||
if(track.mode === 'disabled') {
|
||||
track.mode = 'showing';
|
||||
} else {
|
||||
track.mode = 'disabled';
|
||||
}
|
||||
this.toggleButtonState(this._subtitlesButton);
|
||||
});
|
||||
|
||||
// setSubtitles() requires this._subtitlesSelect to
|
||||
// be in the correct position in the DOM already,
|
||||
// so creating a dummy
|
||||
this._subtitlesSelect = parent.createChild('button',
|
||||
{'class': 'hidden'},
|
||||
['placeholder']);
|
||||
|
||||
// setResolutions() requires this._resolutionSelect to
|
||||
// be in the correct position in the DOM already,
|
||||
@ -567,13 +555,10 @@
|
||||
const defaultRes = 0;
|
||||
const token = presentation.token;
|
||||
this.setResolutions(resolutions, defaultRes);
|
||||
if(presentation.subtitles
|
||||
&& this._subtitlesButton.classList.contains('hidden')) {
|
||||
this._subtitlesButton.classList.remove('hidden');
|
||||
}
|
||||
if(!presentation.subtitles
|
||||
&& !this._subtitlesButton.classList.contains('hidden')) {
|
||||
this._subtitlesButton.classList.add('hidden');
|
||||
if(presentation.subtitles) {
|
||||
this.setSubtitles(Object.keys(presentation.subtitles));
|
||||
} else {
|
||||
this._subtitlesSelect.classList.add('hidden');
|
||||
}
|
||||
|
||||
// create streams
|
||||
@ -601,10 +586,14 @@
|
||||
|
||||
// subs, if present
|
||||
if(presentation.subtitles) {
|
||||
video.createChild(
|
||||
'track',
|
||||
{'kind': 'subtitles',
|
||||
'src': `${presentation.subtitles}?token=${token}`});
|
||||
for(const key in presentation.subtitles) {
|
||||
const file = presentation.subtitles[key];
|
||||
video.createChild(
|
||||
'track',
|
||||
{'kind': 'subtitles',
|
||||
'label': key,
|
||||
'src': `${file}?token=${token}`});
|
||||
}
|
||||
}
|
||||
|
||||
//misc details
|
||||
@ -830,6 +819,100 @@
|
||||
return select;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate the list of subtitle choices.
|
||||
*
|
||||
* The available subtitles are passed in the 'subtitles' arg.
|
||||
*
|
||||
* If there is only one subtitle track, the menu is eliminated
|
||||
* and it becomes a button toggle instead.
|
||||
*/
|
||||
setSubtitles(subtitles) {
|
||||
let select = null;
|
||||
if(subtitles.length === 1) {
|
||||
select = createElement(
|
||||
'button',
|
||||
{'id': 'subtitles-select',
|
||||
'title': 'Undertexter är av',
|
||||
'data-title_alt': 'Undertexter är på',
|
||||
'data-title_en': 'Subtitles are off',
|
||||
'data-title_alt_en': 'Subtitles are on'},
|
||||
[createIcon(['subtitles-off',
|
||||
'subtitles-on'])]);
|
||||
select.addEventListener('click', (event) => {
|
||||
const track = this._mainSource.textTracks[0];
|
||||
if(track.mode === 'disabled') {
|
||||
track.mode = 'showing';
|
||||
} else {
|
||||
track.mode = 'disabled';
|
||||
}
|
||||
this.toggleButtonState(select);
|
||||
});
|
||||
} else {
|
||||
select = createElement('div', {'id': 'subtitles-select',
|
||||
'class': 'select'});
|
||||
const current = select.createChild(
|
||||
'button',
|
||||
{'id': 'subtitles-current',
|
||||
'title': 'Undertexter är av',
|
||||
'data-title-off': 'Undertexter är av',
|
||||
'data-title-off_en': 'Subtitles are off',
|
||||
'data-subtitles-state': 'off'
|
||||
},
|
||||
[createIcon(['subtitles-off',
|
||||
'subtitles-on'])]);
|
||||
const onIcon = current.querySelector(
|
||||
'svg use[href="#subtitles-on-icon"]');
|
||||
const offIcon = current.querySelector(
|
||||
'svg use[href="#subtitles-off-icon"]');
|
||||
const list = select.createChild('ul', {'id': 'subtitles-list',
|
||||
'class': 'list'});
|
||||
for(let i=0; i<subtitles.length; ++i) {
|
||||
list.createChild('li')
|
||||
.createChild('button',
|
||||
{'data-choice': subtitles[i]},
|
||||
[subtitles[i]]);
|
||||
}
|
||||
list.createChild('li').createChild(
|
||||
'button',
|
||||
{'data-text-content_en': 'Off',
|
||||
'data-choice': 'off'},
|
||||
['Av']);
|
||||
|
||||
const buttons = list.querySelectorAll('button');
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener('click', (event) => {
|
||||
const choice = event.currentTarget.dataset.choice;
|
||||
if(choice === current.dataset.subtitlesState) {
|
||||
return;
|
||||
}
|
||||
current.dataset.subtitlesState = choice;
|
||||
const length = this._mainSource.textTracks.length
|
||||
for(let i=0; i<length; i++) {
|
||||
const track = this._mainSource.textTracks[i]
|
||||
if(choice !== 'off' && track.label === choice) {
|
||||
track.mode = 'showing';
|
||||
} else {
|
||||
track.mode = 'disabled';
|
||||
}
|
||||
}
|
||||
if(choice === 'off') {
|
||||
current.title = current.dataset.titleOff;
|
||||
onIcon.classList.add('hidden');
|
||||
offIcon.classList.remove('hidden');
|
||||
} else {
|
||||
current.title = choice;
|
||||
offIcon.classList.add('hidden');
|
||||
onIcon.classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
this._subtitlesSelect.replaceWith(select);
|
||||
this._subtitlesSelect = select;
|
||||
return select;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a consistently formatted time string.
|
||||
*
|
||||
@ -956,12 +1039,24 @@
|
||||
newMainParent.classList.add('main');
|
||||
switchIcons(newMainParent);
|
||||
|
||||
const oldTrack = this._mainSource.textTracks[0];
|
||||
const newTrack = newMain.textTracks[0];
|
||||
const oldState = oldTrack.mode;
|
||||
oldTrack.mode = newTrack.mode;
|
||||
newTrack.mode = oldState;
|
||||
|
||||
let oldTrackLabel = null;
|
||||
for(let i=0; i<this._mainSource.textTracks.length; i++) {
|
||||
const track = this._mainSource.textTracks[i];
|
||||
if(track.mode === "showing") {
|
||||
track.mode = "disabled";
|
||||
oldTrackLabel = track.label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(oldTrackLabel !== null) {
|
||||
for(let i=0; i<newMain.textTracks.length; i++) {
|
||||
const track = newMain.textTracks[i];
|
||||
if(track.label === oldTrackLabel) {
|
||||
track.mode = "showing";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._mainSource = newMain;
|
||||
this.syncSources();
|
||||
}
|
||||
|
@ -252,6 +252,7 @@ button {
|
||||
margin-bottom: var(--controls-height);
|
||||
padding-bottom: var(--gap);
|
||||
list-style: none;
|
||||
width: max-content;
|
||||
}
|
||||
.list li {
|
||||
background-color: var(--fade);
|
||||
|
Loading…
x
Reference in New Issue
Block a user