Implemented seeking and settings persistence

This commit is contained in:
Erik Thuning 2023-01-09 16:58:19 +01:00
parent c4569c46b5
commit 069d746871

@ -296,6 +296,17 @@
// the progress bar
this._progressPopup = null;
// all subtitle selection buttons
this._subtitleChoices = [];
// all resolution selection buttons
this._resolutionChoices = [];
// the mute toggle
this._volumeButton = null;
// the volume slider
this._volumeSlider = null;
// prepare shadow root
this.attachShadow({'mode': 'open'});
@ -322,7 +333,7 @@
'canvas', {id: 'buffer'});
this._progressBar = this._progressContainer.createChild(
'div', {id: 'progress'});
this._progressPopup = this._progressBar.createChild(
this._progressPopup = this._progressContainer.createChild(
'div', {id: 'progress-popup'});
this.initLeftControls(controlRoot.createChild(
@ -472,7 +483,7 @@
});
});
});
const volumeButton = parent.createChild(
this._volumeButton = parent.createChild(
'button',
{'id': 'volume-button',
'title': 'Stäng av ljud',
@ -481,28 +492,34 @@
'data-title_alt_en': 'Unmute'},
[createIcon(['volume', 'mute'])]);
const volumeSlider = parent.createChild('input',
this._volumeSlider = parent.createChild('input',
{'id': 'volume',
'type': 'range',
'min': '0',
'max': '1',
'step': '0.01'});
volumeSlider.value = 1;
this._volumeSlider.value = 1;
volumeButton.addEventListener('click', (event) => {
console.log(volumeButton);
this._volumeButton.addEventListener('click', (event) => {
const audio = this._audioSource;
if(!audio.muted) {
volumeSlider.setAttribute('value', 0);
this._volumeSlider.value = 0;
audio.muted = true;
localStorage.setItem('multi-player-muted', true);
} else {
volumeSlider.value = audio.volume;
this._volumeSlider.value = audio.volume;
audio.muted = false;
localStorage.removeItem('multi-player-muted');
}
this.toggleButtonState(volumeButton);
this.toggleButtonState(this._volumeButton);
});
volumeSlider.addEventListener('input', (event) => {
this._audioSource.volume = volumeSlider.valueAsNumber;
this._volumeSlider.addEventListener('input', (event) => {
const volume = this._volumeSlider.valueAsNumber;
this._audioSource.volume = volume;
if(this._audioSource.muted === true) {
this._volumeButton.click();
}
localStorage.setItem('multi-player-volume', volume);
});
this._elapsed = parent.createChild('span', {'id': 'elapsed'});
@ -577,11 +594,6 @@
const defaultRes = 0;
const token = presentation.token;
this.setResolutions(resolutions, defaultRes);
if(presentation.subtitles) {
this.setSubtitles(Object.keys(presentation.subtitles));
} else {
this._subtitlesSelect.classList.add('hidden');
}
// create streams
const streams = presentation.sources;
@ -662,13 +674,20 @@
event.currentTarget.querySelector('video'));
}
});
}
if(presentation.subtitles) {
this.setSubtitles(Object.keys(presentation.subtitles));
} else {
this._subtitlesSelect.classList.add('hidden');
}
this.setActivePlaylistItem();
this.autoBlurControls();
this.initProgressTracking();
this.initProgressContainer();
this.initBuffer();
this.recallSettings();
}
/*
@ -709,20 +728,51 @@
}
/*
* Set up progress tracking
* Set up progress container with progress tracking, seeking etc.
*/
initProgressTracking() {
this._controlSource.addEventListener(
'timeupdate', (event) => {
const elapsed = this._controlSource.currentTime;
this._elapsed.textContent = this.formatTime(elapsed);
const progressWidth = (
elapsed
/ this._controlSource.duration
* this._progressContainer.clientWidth);
this._progressBar.style.width = progressWidth + 'px';
initProgressContainer() {
// Initialize hover timestamp popup
const popup = this._progressContainer.querySelector(
'#progress-popup');
this._progressContainer.addEventListener('mousemove', (event) => {
const bounds =
this._progressContainer.getBoundingClientRect();
const xRel = event.clientX - bounds.x;
const fraction = xRel / this._progressContainer.clientWidth;
const time = fraction * this._controlSource.duration;
popup.textContent = this.formatTime(time);
const margin = popup.clientWidth / 2;
const xmax = this._progressContainer.clientWidth - margin;
let pos = xRel;
if(pos < margin) {
pos = margin;
} else if(pos > xmax) {
pos = xmax;
}
);
popup.style.left = pos + 'px';
});
// Enable seeking
this._progressContainer.addEventListener('click', (event) => {
const bounds =
this._progressContainer.getBoundingClientRect();
const xRel = event.clientX - bounds.x;
const fraction = xRel / this._progressContainer.clientWidth;
const time = fraction * this._controlSource.duration;
this.setTime(time);
});
// Initialize progressbar
this._controlSource.addEventListener('timeupdate', (event) => {
const elapsed = this._controlSource.currentTime;
this._elapsed.textContent = this.formatTime(elapsed);
const progressWidth = (
elapsed
/ this._controlSource.duration
* this._progressContainer.clientWidth);
this._progressBar.style.width = progressWidth + 'px';
});
}
/*
@ -767,6 +817,54 @@
window.requestAnimationFrame(paintBuffer);
}
/*
* Apply any saved settings from previous usage
*/
recallSettings() {
// Set subtitles state
const savedState = localStorage.getItem(
'multi-player-subs-state');
if(savedState === 'showing') {
const savedTrack = localStorage.getItem(
'multi-player-subs-track');
let found = false;
this._subtitleChoices.forEach((button) => {
if(savedTrack === button.textContent) {
button.click();
found = true;
}
});
if(!found) {
this._subtitleChoices[0].click();
}
}
// Apply saved volume
const savedLevel = localStorage.getItem('multi-player-volume');
if(savedLevel !== null) {
this._volumeSlider.value = savedLevel;
this._audioSource.volume = savedLevel;
}
// Apply saved mute state
const muted = localStorage.getItem('multi-player-muted');
if(muted) {
this._volumeButton.click();
}
// Apply saved resolution choice
const savedResolution = localStorage.getItem(
'multi-player-resolution');
if(savedResolution) {
this._resolutionChoices.forEach((button) => {
if(button.textContent === savedResolution) {
button.click();
}
});
}
//¤¤¤
}
/*
* Update the playlist to reflect which item is playing
*
@ -818,9 +916,9 @@
resolutions.reverse(),
resolutions.length - defaultIndex - 1);
const current = select.querySelector('#resolution-current');
const buttons = select.querySelectorAll(
this._resolutionChoices = select.querySelectorAll(
'#resolution-list button');
buttons.forEach((button) => {
this._resolutionChoices.forEach((button) => {
button.addEventListener('click', (event) => {
const res = event.currentTarget.textContent;
const time = this._mainSource.currentTime;
@ -841,6 +939,7 @@
if(!paused) {
this.togglePlayback();
}
localStorage.setItem('multi-player-resolution', res);
});
});
@ -876,8 +975,16 @@
} else {
track.mode = 'disabled';
}
localStorage.setItem('multi-player-subs-state',
track.mode);
this.toggleButtonState(select);
});
const savedState = localStorage.getItem(
'multi-player-subs-state');
if(savedState === 'showing') {
select.click();
}
} else {
select = createElement('div', {'id': 'subtitles-select',
'class': 'select'});
@ -908,8 +1015,9 @@
'data-choice': 'off'},
['Av']);
const buttons = list.querySelectorAll('button');
buttons.forEach((button) => {
this._subtitleChoices = list.querySelectorAll('button');
console.log('foo', this._subtitleChoices);
this._subtitleChoices.forEach((button) => {
button.addEventListener('click', (event) => {
const choice = event.currentTarget.dataset.choice;
if(choice === current.dataset.subtitlesState) {
@ -929,10 +1037,17 @@
current.title = current.dataset.titleOff;
onIcon.classList.add('hidden');
offIcon.classList.remove('hidden');
localStorage.setItem('multi-player-subs-state',
'disabled');
localStorage.removeItem('multi-player-subs-track');
} else {
current.title = choice;
offIcon.classList.add('hidden');
onIcon.classList.remove('hidden');
localStorage.setItem('multi-player-subs-state',
'showing');
localStorage.setItem('multi-player-subs-track',
choice);
}
});
});