diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..01d3cfe --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +### Description + + + +### Additional Notes + +- This PR fixes or works on following ticket(s): [SIRI-](https://scireum.myjetbrains.com/youtrack/issue/SIRI-) +- This PR is related to PR: + +### Checklist + +- [ ] Code change has been tested and works locally +- [ ] TSC (TypeScript Compiler) has been run and changes are reflected in the dist folder diff --git a/README.md b/README.md index 86d8701..5e3543e 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,138 @@ Still heavily work in progress :) -![image](https://user-images.githubusercontent.com/2427877/119615699-f9c9e380-bdff-11eb-9a54-f3876ad9138d.png) +![screenshot](https://user-images.githubusercontent.com/2427877/121416664-559c7c80-c969-11eb-95d7-aeed87b1168a.png) ## Functionality - Playback of all browser supported formats - Toggleable Subtitles/Captions via VTT - Basic playback controls +- Basic keyboard shortcuts - Playback quality controls +- Playback speed controls - Basic fullscreen capabilities +- Picture-in-picture mode - Progress and buffering indicator +## Dependencies + +### Modern browsers + +None :) + +### Internet Explorer 11 + +Polyfills for `Array.prototype.forEach`, `NodeList.prototype.forEach` and `Element.prototype.matches`. + ## Parameters +| Name | Description | Type | Default | +|------------------|-------------------------------------------------------------------------------------------------------------------|----------|--| +| selector | A selector query string pointing to the div the player should be rendered in | string | '' | +| baseUri | The absolute URL pointing to the base directory of the library (used for loading icons, ...) | string | '' | +| poster | The relative or absolute URL pointing to the video preview image | string | '' | +| sources | A list of all video qualities and their sources. Structure described below | array | - ' +| quality | The name of the quality that should be loaded initially | string | - | +| subtitles | The relative or absolute URL pointing to the video captions VTT file | string | null | +| autoplay | Starts the video playback directly when 'true' is passed | boolean | false | +| rememberVolume | Saves and Restores the volume and mute state via local storage when 'true' is passed | boolean | false | +| rememberQuality | Saves and Restores the playback quality via local storage when 'true' is passed | boolean | false | +| startTime | Starts the video playback offset by the given number of seconds | number | 0 | +| deeplink | Shows a deeplink button that copies the url to clipboard on click when filled | string | '' | +| deeplinkCallback | A function that is called when the deeplink button is clicked - if it returns false, the copy action is supressed | function | - | +| closeCallback | Shows a close button that invokes the provided callback on clicked when filled | function | - | +| translations | Can be provided to overwrite the default english translations. Structure described below | object | - | + +## Sources + +Upon initialization of the player multiple video qualities with multiple source formats can be provided. For this an +array of objects is +passed to the `sources` parameter. The order of the objects also determines their order in the quality setting dropdown. +Each object has the following structure: + +| Name | Description | +|---------|--------------------------------------------------------------------------------------| +| quality | Identifier and also name of the quality option shown in the dropdown | +| sources | A list of nested objects describing the different formats. Structure described below | + +| Name | Description | +|---------|-----------------------------------------------------------------| +| type | The mime time of the video file format, for example `video/mp4` | +| sources | The actual URI pointing to the video file | + +### Sample + +```javascript +new Cinematic({ + ... + sources: [ + { + quality: '1080p', + sources: [ + { + type: 'video/webm', + source: '1080.webm' + }, + { + type: 'video/mp4', + source: '1080.mp4' + } + ] + }, + { + quality: '720p', + sources: [ + { + type: 'video/webm', + source: '720.webm' + }, + { + type: 'video/mp4', + source: '720.mp4' + } + ] + } +] +}); +``` + +## Translations + +The player provides english translations as a default. With the `translations` parameter described above these can be +overwritten. +The following keys can be provided: + +| Name | Description | Default | +|----------------|-----------------------------------------------------------------------------|----------------------------| +| pause | Tooltip on the play/pause button when the video is currently playing. | Pause | +| play | Tooltip on the play/pause button when the video is currently paused. | Play | +| restart | Tooltip on the play/pause button when the video reached its end. | Restart | +| mute | Tooltip on the volume button when video is currently not muted. | Mute | +| unmute | Tooltip on the volume button when video is currently muted. | Unmute | +| settings | Tooltip on the settings button. | Settings | +| quality | Heading of the quality settings section. | Quality | +| playbackSpeed | Heading of the speed settings section. | Speed | +| close | Tooltip on the optional close button. | Close | +| deeplink | Tooltip on the optional deeplink copy button. | Copy deeplink to clipboard | +| deeplinkCopied | Popup that is shown when the deeplink button is pressed. | Link was copied | +| fullscreen | Tooltip on the fullscreen button when video is currently not in fullscreen. | Fullscreen | +| exitFullscreen | Tooltip on the fullscreen button when video is currently in fullscreen. | Exit Fullscreen | +| showSubtitles | Tooltip on the subtitles button when video subtitles are currently hidden. | Show Subtitles | +| hideSubtitles | Tooltip on the subtitles button when video subtitles are currently shown. | Hide Subtitles | + +## Build / Development + +Install typescript: + +``` +brew install typescript +``` + +Change .ts file as necessary. + +Run TypeScript build in the main project directory: -| Name | Description | Default | -|---|---|---| -| selector | A selector query string pointing to the div the player should be rendered in | '' | -| poster | The relative or absolute URL pointing to the video preview image | '' | -| subtitles | The relative or absolute URL pointing to the video captions VTT file | null | +``` +tsc +``` diff --git a/built/cinematic.js b/built/cinematic.js deleted file mode 100644 index 94e9a5b..0000000 --- a/built/cinematic.js +++ /dev/null @@ -1,302 +0,0 @@ -var Cinematic = /** @class */ (function () { - function Cinematic(options) { - this.totalSeconds = 0; - this.playedSeconds = 0; - this.volume = 0; - this.quality = '720'; - this.fullScreenEnabled = false; - this.options = options; - var _passedContainer = document.querySelector(this.options.selector); - if (!_passedContainer) { - throw new Error('passed selector does not point to a DOM element.'); - } - this._container = _passedContainer; - this.fullScreenEnabled = document.fullscreenEnabled; - this.renderPlayer(); - this.setupEvents(); - this._video.load(); - } - Cinematic.prototype.renderPlayer = function () { - this._container.classList.add('video-container'); - var _video = document.createElement('video'); - _video.preload = 'metadata'; - _video.poster = this.options.poster; - this._container.appendChild(_video); - this._video = _video; - // TODO as option - var _mp4 = document.createElement('source'); - _mp4.src = '../video/720.mp4'; - _mp4.type = 'video/mp4'; - _video.appendChild(_mp4); - var _webM = document.createElement('source'); - _webM.src = '../video/720.webm'; - _webM.type = 'video/webm'; - _video.appendChild(_webM); - if (this.options.subtitles) { - var _subtitles = document.createElement('track'); - _subtitles.label = 'subtitles'; - _subtitles.kind = 'subtitles'; - _subtitles.src = this.options.subtitles; - _subtitles.default = true; - _video.appendChild(_subtitles); - } - this.tracks = _video.textTracks[0]; - this.tracks.mode = 'hidden'; - this.cues = this.tracks.cues; - var _cuesContainer = document.createElement('div'); - _cuesContainer.classList.add('video-cues-container'); - _cuesContainer.classList.add('hidden'); - this._container.appendChild(_cuesContainer); - var _cues = document.createElement('div'); - _cues.classList.add('video-cues'); - _cues.classList.add('hidden'); - _cuesContainer.appendChild(_cues); - this._cues = _cues; - this._cuesContainer = _cuesContainer; - var _controls = document.createElement('div'); - _controls.classList.add('video-controls'); - this._container.appendChild(_controls); - this._controls = _controls; - var _playButton = document.createElement('i'); - _playButton.classList.add('video-control-button'); - _playButton.classList.add('material-icons'); - _playButton.textContent = 'play_arrow'; - _controls.appendChild(_playButton); - this._playButton = _playButton; - var _progressWrapper = document.createElement('div'); - _progressWrapper.classList.add('video-progress-wrapper'); - _controls.appendChild(_progressWrapper); - var _bufferBar = document.createElement('progress'); - _bufferBar.classList.add('video-buffer-bar'); - _bufferBar.value = 0; - _progressWrapper.appendChild(_bufferBar); - this._bufferBar = _bufferBar; - var _progressBar = document.createElement('progress'); - _progressBar.classList.add('video-progress-bar'); - _progressBar.value = 0; - _progressWrapper.appendChild(_progressBar); - this._progressBar = _progressBar; - var _timer = document.createElement('span'); - _timer.classList.add('video-control-timer'); - _timer.textContent = '00:00:00 / 00:00:00'; - _controls.appendChild(_timer); - this._timer = _timer; - var _volumeWrapper = document.createElement('div'); - _volumeWrapper.classList.add('video-volume-wrapper'); - _controls.appendChild(_volumeWrapper); - var _volumeSlider = document.createElement('input'); - _volumeSlider.type = 'range'; - _volumeSlider.min = '1'; - _volumeSlider.max = '100'; - _volumeSlider.value = '50'; - _volumeSlider.classList.add('video-volume-slider'); - _volumeWrapper.appendChild(_volumeSlider); - this._volumeSlider = _volumeSlider; - var _volumeButton = document.createElement('i'); - _volumeButton.classList.add('video-control-button'); - _volumeButton.classList.add('material-icons'); - _volumeButton.textContent = 'volume_up'; - _volumeWrapper.appendChild(_volumeButton); - this._volumeButton = _volumeButton; - var _qualityWrapper = document.createElement('div'); - _qualityWrapper.classList.add('video-control-dropdown'); - _controls.appendChild(_qualityWrapper); - var _qualityButton = document.createElement('i'); - _qualityButton.classList.add('video-control-button'); - _qualityButton.classList.add('material-icons'); - _qualityButton.textContent = 'settings'; - _qualityWrapper.appendChild(_qualityButton); - var _dropDownContent = document.createElement('div'); - _dropDownContent.classList.add('video-dropdown-content'); - _qualityWrapper.appendChild(_dropDownContent); - var _option1080p = document.createElement('div'); - _option1080p.classList.add('video-quality-option'); - _option1080p.dataset.quality = '1080'; - _option1080p.textContent = '1080p'; - _dropDownContent.appendChild(_option1080p); - var _option720p = document.createElement('div'); - _option720p.classList.add('video-quality-option'); - _option720p.dataset.quality = '720'; - _option720p.textContent = '720p'; - _dropDownContent.appendChild(_option720p); - var _option360p = document.createElement('div'); - _option360p.classList.add('video-quality-option'); - _option360p.dataset.quality = '360'; - _option360p.textContent = '360p'; - _dropDownContent.appendChild(_option360p); - this._qualityOptions = _dropDownContent.childNodes; - var _captionsButton = document.createElement('i'); - _captionsButton.classList.add('video-control-button'); - _captionsButton.classList.add('material-icons-outlined'); - _captionsButton.textContent = 'subtitles'; - _controls.appendChild(_captionsButton); - this._captionsButton = _captionsButton; - if (this.fullScreenEnabled) { - var _fullScreenButton = document.createElement('i'); - _fullScreenButton.classList.add('video-control-button'); - _fullScreenButton.classList.add('material-icons'); - _fullScreenButton.textContent = 'fullscreen'; - _controls.appendChild(_fullScreenButton); - this._fullScreenButton = _fullScreenButton; - } - }; - ; - Cinematic.prototype.setupEvents = function () { - var me = this; - this._playButton.addEventListener('click', function (e) { - if (me._video.paused || me._video.ended) { - me._video.play(); - } - else { - me._video.pause(); - } - }); - this._volumeButton.addEventListener('click', function (e) { - me._video.muted = !me._video.muted; - me._volumeSlider.value = me._video.muted ? '0' : me.volume.toString(); - if (me._video.muted) { - me._volumeButton.textContent = 'volume_off'; - } - else { - if (me.volume > 50) { - me._volumeButton.textContent = 'volume_up'; - } - else { - me._volumeButton.textContent = 'volume_down'; - } - } - }); - this._volumeSlider.addEventListener('change', function (e) { - me.volume = parseInt(this.value); - me._video.volume = me.volume / 100; - if (me.volume > 50) { - me._volumeButton.textContent = 'volume_up'; - } - else { - me._volumeButton.textContent = 'volume_down'; - } - }); - var onCueEnter = function () { - me._cues.textContent = this.text; - me._cues.classList.remove('hidden'); - }; - var onCueExit = function () { - me._cues.textContent = ''; - me._cues.classList.add('hidden'); - }; - this._video.addEventListener('loadedmetadata', function () { - me.totalSeconds = this.duration; - me._progressBar.setAttribute('max', me.totalSeconds.toString()); - me._bufferBar.setAttribute('max', me.totalSeconds.toString()); - me.updateTimer(); - if (me.cues) { - for (var i = 0; i < me.cues.length; i++) { - var cue = me.cues[i]; - cue.onenter = onCueEnter; - cue.onexit = onCueExit; - } - } - }); - this._video.addEventListener('timeupdate', function () { - me.playedSeconds = this.currentTime; - me._progressBar.value = me.playedSeconds; - me.updateTimer(); - }); - this._video.addEventListener('play', function () { - //me._endcard.classList.add('hidden'); - me._playButton.textContent = 'pause'; - }); - this._video.addEventListener('pause', function () { - //me._endcard.classList.remove('hidden'); - me._playButton.textContent = 'play_arrow'; - }); - this._video.addEventListener('ended', function () { - //me._endcard.classList.remove('hidden'); - me._playButton.textContent = 'restart_alt'; - }); - this._video.addEventListener('progress', function () { - if (this.duration > 0) { - for (var i = 0; i < this.buffered.length; i++) { - var bufferRangeIndex = this.buffered.length - 1 - i; - var bufferStart = this.buffered.start(bufferRangeIndex); - var bufferEnd = this.buffered.end(bufferRangeIndex); - if (bufferStart <= this.currentTime) { - var buffered = (bufferEnd / this.duration) * 100; - me._bufferBar.value = buffered; - break; - } - } - } - }); - this._progressBar.addEventListener('click', function (event) { - var target = event.target; - var rect = target.getBoundingClientRect(); - var pos = (event.clientX - rect.left) / this.offsetWidth; - me._video.currentTime = pos * me._video.duration; - }); - if (this.fullScreenEnabled) { - this._fullScreenButton.addEventListener('click', function (e) { - me.handleFullscreen(); - }); - document.addEventListener('fullscreenchange', function (e) { - me._container.dataset.fullscreen = document.fullscreenElement; - }); - } - this._qualityOptions.forEach(function (_qualityOption) { - _qualityOption.addEventListener('click', function (e) { - var newQuality = _qualityOption.dataset.quality; - var currentQuality = me.quality; - if (!newQuality) { - return; - } - me._qualityOptions.forEach(function (_qualityOption) { - _qualityOption.classList.remove('active'); - }); - _qualityOption.classList.add('active'); - if (newQuality !== currentQuality) { - var currentTime = me._video.currentTime; - var _mp4Source = me._video.querySelector('source[type="video/mp4"]'); - if (_mp4Source) { - _mp4Source.src = '../video/' + newQuality + '.mp4'; - } - var _webmSource = me._video.querySelector('source[type="video/webm"]'); - if (_webmSource) { - _webmSource.src = '../video/' + newQuality + '.webm'; - } - me._video.load(); - me._video.currentTime = currentTime; - me._video.play(); - me.quality = newQuality; - } - }); - }); - this._captionsButton.addEventListener('click', function (e) { - this.classList.toggle('material-icons'); - this.classList.toggle('material-icons-outlined'); - me._cuesContainer.classList.toggle('hidden'); - }); - }; - Cinematic.prototype.formatTime = function (seconds) { - return new Date(seconds * 1000).toISOString().substr(11, 8); - }; - Cinematic.prototype.updateTimer = function () { - this._timer.textContent = this.formatTime(this.playedSeconds) + ' / ' + this.formatTime(this.totalSeconds); - }; - Cinematic.prototype.handleFullscreen = function () { - if (this.isFullScreen()) { - document.exitFullscreen(); - this._container.dataset.fullscreen = false; - this._fullScreenButton.textContent = 'fullscreen'; - } - else { - this._container.requestFullscreen(); - this._container.dataset.fullscreen = true; - this._fullScreenButton.textContent = 'fullscreen_exit'; - } - }; - Cinematic.prototype.isFullScreen = function () { - return document.fullscreenElement; - }; - return Cinematic; -}()); -//# sourceMappingURL=cinematic.js.map \ No newline at end of file diff --git a/built/cinematic.js.map b/built/cinematic.js.map deleted file mode 100644 index 0a415e3..0000000 --- a/built/cinematic.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"cinematic.js","sourceRoot":"","sources":["../lib/cinematic.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cinematic.css b/dist/cinematic.css new file mode 100644 index 0000000..3a08fa2 --- /dev/null +++ b/dist/cinematic.css @@ -0,0 +1,582 @@ +/*region Container / Video*/ +.cinematicjs-video-container { + position: relative; + display: flex; + width: 100%; + height: 100%; + background-color: #000; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +} + +.cinematicjs-video-container, .cinematicjs-video-container * { + box-sizing: border-box; + word-wrap: normal; + word-break: normal; +} + +.cinematicjs-video-container video { + flex-basis: 0; + flex-shrink: 1; + flex-grow: 1; + width: 100%; + background-size: cover; + outline: none; +} + +.cinematicjs-video-container.cinematicjs-video-user-inactive { + cursor: none; +} + +/*endregion*/ + +/*region Cues / Subtitles*/ +.cinematicjs-video-cues-container { + display: flex; + position: absolute; + top: 48px; + bottom: 80px; + left: 32px; + right: 32px; + align-items: flex-end; + justify-content: center; +} + +.cinematicjs-video-cues-container > div { + color: white; + background-color: #00000094; + padding: 4px 8px; + border-radius: 4px; +} + +/*endregion*/ + +.cinematicjs-ui-wrapper { + display: flex; + flex-direction: column; + justify-content: space-between; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + transition: visibility 0.5s ease-in, opacity 0.5s ease-out; + pointer-events: none; +} + +.cinematicjs-ui-wrapper * { + pointer-events: all; +} + +/*region Header*/ +.cinematicjs-video-header { + display: flex; + flex-wrap: wrap; + list-style-type: none; + background: transparent; + padding: 8px; + align-items: center; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.5) 45%, rgba(0, 0, 0, 0.25) 82%, rgba(0, 0, 0, 0) 100%); +} + +.cinematicjs-video-header .cinematicjs-video-icon { + max-height: 48px; + max-width: 48px; + margin-right: 8px; + box-shadow: 0 0 7px rgba(0, 0, 0, 0.2), 0 0 1em rgba(0, 0, 0, 0.7); +} + +.cinematicjs-video-header .cinematicjs-video-title { + margin-right: 8px; + color: #ffffff; + cursor: default; + opacity: 0.9; + transition: opacity .1s ease-in-out; + text-shadow: 0 0 7px rgba(0, 0, 0, 0.2), 0 0 1em rgba(0, 0, 0, 0.7); + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.cinematicjs-video-header .cinematicjs-video-title.cinematicjs-clickable:hover { + opacity: 1; +} + +.cinematicjs-video-header .cinematicjs-video-description:hover { + opacity: 1; +} + +.cinematicjs-video-header .cinematicjs-video-info-button { + color: #ffffff; + cursor: pointer; + flex-grow: 0; + opacity: 0.9; + transition: opacity .1s ease-in-out; + text-shadow: 0 0 7px rgba(0, 0, 0, 0.2), 0 0 1em rgba(0, 0, 0, 0.7); + line-height: 8px; + border-radius: 4px; + padding: 2px; +} + +.cinematicjs-video-header .cinematicjs-video-info-button:hover { + opacity: 1; +} + +.cinematicjs-video-header .cinematicjs-video-info-button:focus:not(:focus-visible) { + outline: none; +} + +.cinematicjs-video-header .cinematicjs-video-info-button:focus-visible { + outline: 2px solid rgba(255, 255, 255, 0.8); + outline-offset: 2px; + opacity: 1; +} + +.cinematicjs-video-header .cinematicjs-video-header-spacer { + flex-grow: 1; +} + +.cinematicjs-video-header .cinematicjs-video-close-button { + color: #ffffff; + cursor: pointer; + flex-grow: 0; + opacity: 0.9; + transition: opacity .1s ease-in-out; + text-shadow: 0 0 7px rgba(0, 0, 0, 0.2), 0 0 1em rgba(0, 0, 0, 0.7); + border-radius: 4px; + padding: 2px; +} + +.cinematicjs-video-header .cinematicjs-video-close-button:hover { + opacity: 1; +} + +.cinematicjs-video-header .cinematicjs-video-close-button:focus:not(:focus-visible) { + outline: none; +} + +.cinematicjs-video-header .cinematicjs-video-close-button:focus-visible { + outline: 2px solid rgba(255, 255, 255, 0.8); + outline-offset: 2px; + opacity: 1; +} + +/*endregion*/ + +.cinematicjs-ui-wrapper .cinematicjs-video-description { + flex-grow: 1; + overflow-y: auto; + margin: 8px; + color: #ffffff; + cursor: pointer; + opacity: 0.9; + transition: opacity .1s ease-in-out; + text-shadow: 0 0 7px rgba(0, 0, 0, 0.2), 0 0 1em rgba(0, 0, 0, 0.7); +} + +/*region Footer / Controls*/ +.cinematicjs-video-footer { + display: flex; + flex-direction: column; + padding: 4px; + background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.5) 45%, rgba(0, 0, 0, 0.25) 82%, rgba(0, 0, 0, 0) 100%); +} + +.cinematicjs-video-controls { + display: flex; + align-items: center; + margin-top: 4px; +} + +.cinematicjs-video-controls > * { + margin: 4px; +} + +.cinematicjs-video-controls .cinematicjs-hidden, .cinematicjs-video-controls .cinematicjs-video-control-button.cinematicjs-hidden { + display: none !important; +} + +.cinematicjs-video-controls .video-control-spacer { + flex-grow: 1; +} + +.cinematicjs-video-controls .cinematicjs-video-control-button { + display: flex; + align-items: center; + color: #ffffff; + cursor: pointer; + flex-grow: 0; + opacity: 0.9; + transition: opacity .1s ease-in-out; + border-radius: 4px; + padding: 2px; +} + +.cinematicjs-video-controls .cinematicjs-video-control-button:hover { + opacity: 1; +} + +.cinematicjs-video-controls .cinematicjs-video-control-button:focus:not(:focus-visible) { + outline: none; +} + +.cinematicjs-video-controls .cinematicjs-video-control-button:focus-visible { + outline: 2px solid rgba(255, 255, 255, 0.8); + outline-offset: 2px; + opacity: 1; +} + +.cinematicjs-video-control-button svg, .cinematicjs-video-close-button svg, .cinematicjs-video-info-button svg { + display: inline-block; + width: 18px; + height: 18px; + margin: 3px; + fill: #ffffff; + pointer-events: none; +} + +/*endregion*/ + +/*region Progress / Buffer Bar*/ +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper { + position: relative; + width: 100%; + flex-grow: 1; + padding: 8px 0; + background: rgba(0, 0, 0, 0.4); + border-radius: 4px; +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-progress-bar, +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-buffer-bar { + position: absolute; + top: 50%; + transform: translateY(-50%); + left: 0; + right: 0; + cursor: pointer; +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-progress-bar, +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-buffer-bar { + display: block; + width: 100%; + height: 6px; + border: none; + overflow: hidden; + background: transparent; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -webkit-appearance: none; + appearance: none; +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-buffer-bar { + background: rgba(128, 128, 128, 0.5); +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-progress-bar::-webkit-progress-bar { + background: transparent; +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-progress-bar::-webkit-progress-value { + background: #ffffff; + box-shadow: 0 0 4px rgba(255, 255, 255, 0.5); +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-progress-bar::-moz-progress-bar { + background: #ffffff; + box-shadow: 0 0 4px rgba(255, 255, 255, 0.5); +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-buffer-bar::-webkit-progress-bar { + background: rgba(128, 128, 128, 0.5); +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-buffer-bar::-webkit-progress-value { + background: rgba(180, 180, 180, 0.6); +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper .cinematicjs-video-buffer-bar::-moz-progress-bar { + background: rgba(180, 180, 180, 0.6); +} + +.cinematicjs-video-footer .cinematicjs-video-progress-wrapper:focus-within { + outline: 2px solid rgba(255, 255, 255, 0.8); + outline-offset: 2px; +} + +/*endregion*/ + +/*region Deeplink Button*/ +.cinematicjs-video-controls .cinematicjs-video-control-button.cinematicjs-copied svg { + fill: #69f0ae; +} + +.cinematicjs-video-controls .cinematicjs-video-control-button.cinematicjs-copied:before { + content: attr(data-copied-text); + position: absolute; + transition: all 0.15s ease; + color: #000; + border-radius: 10px; + top: auto; + bottom: 32px; + transform: translate3d(-50%, 0, 0); + font-size: 0.8em; + padding: 0.5em 0.75em; + background: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif +} + +/*endregion*/ + +/*region Timer*/ +.cinematicjs-video-controls .cinematicjs-video-control-timer { + flex-shrink: 0; + padding-left: 8px; + color: #ffffff; + text-shadow: 0 0 7px rgba(0, 0, 0, 0.2), 0 0 1em rgba(0, 0, 0, 0.3); +} + +/*endregion*/ + +/*region Fullscreen*/ +.cinematicjs-video-container[data-fullscreen=true] { + max-width: 100%; + margin: 0; + padding: 0; +} + +.cinematicjs-video-container[data-fullscreen=true] video { + height: auto; +} + +.cinematicjs-video-container[data-fullscreen=true] .cinematicjs-ui-wrapper { + position: absolute; + width: 100%; + z-index: 2147483647; +} + +/* hide controls on fullscreen with WebKit */ +.cinematicjs-video-container[data-fullscreen=true] video::-webkit-media-controls { + display: none !important; +} + +html:-ms-fullscreen { + width: 100%; +} + +:-webkit-full-screen { + background-color: transparent; +} + +/*endregion*/ + +/*region Volume Control*/ +.cinematicjs-video-volume-wrapper { + display: flex +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider { + display: none; + width: 80px; + background-color: transparent; + -webkit-appearance: none; +} + +.cinematicjs-video-volume-wrapper:hover .cinematicjs-video-volume-slider { + display: initial; +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider:focus:not(:focus-visible) { + outline: none; +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider:focus-visible { + outline: 2px solid rgba(255, 255, 255, 0.8); + outline-offset: 2px; +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider::-webkit-slider-runnable-track { + background: #ffffff3a; + border-radius: 4px; + width: 100%; + height: 4px; + cursor: pointer; +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider::-webkit-slider-thumb { + width: 8px; + height: 8px; + background: #ffffff; + border-radius: 4px; + cursor: pointer; + -webkit-appearance: none; + margin-top: -2px; +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider::-moz-range-track { + background: #ffffff3a; + border-radius: 4px; + width: 100%; + height: 4px; + cursor: pointer; +} + +.cinematicjs-video-volume-wrapper .cinematicjs-video-volume-slider::-moz-range-thumb { + width: 8px; + height: 8px; + background: #ffffff; + border-radius: 4px; + cursor: pointer; +} + +/*endregion*/ + +/*region Dropdown*/ +.cinematicjs-video-control-dropdown { + position: relative; + height: 24px; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content { + display: none; + position: absolute; + bottom: 32px; + right: 0; + min-width: 90px; + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); + z-index: 1; + border-radius: 8px; + overflow: hidden; + background-color: rgba(255, 255, 255, 0.9); + color: black; + text-decoration: none; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content select { + padding: 0; + width: 60px; +} + +.cinematicjs-video-control-dropdown.cinematicjs-dropdown-active .cinematicjs-video-dropdown-content { + display: block; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-section { + display: flex; + padding: 12px; + justify-content: space-between; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-section + .cinematicjs-video-dropdown-section { + border-top: 1px solid rgb(0 0 0 / 15%); +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content span { + margin: 0px; + font-size: 18px; + font-weight: bold; + cursor: default; + margin-right: 8px; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content select { + flex-grow: 0; + appearance: none; + border: none; + font-size: 18px; + text-align: end; + background: transparent; + cursor: pointer; + text-decoration: underline; + text-underline-offset: 1px; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content select:focus:not(:focus-visible) { + outline: none !important; + background-color: transparent !important; + border: none !important; + box-shadow: none !important; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content select.mouse-focus { + outline: none !important; + background-color: transparent !important; + border: none !important; + box-shadow: none !important; +} + +.cinematicjs-video-control-dropdown .cinematicjs-video-dropdown-content select:focus-visible:not(.mouse-focus) { + outline: 2px solid #000000 !important; + outline-offset: 2px; + background-color: rgba(0, 0, 0, 0.05); +} + +/*endregion*/ + +/*region Feedback Overlay*/ +.cinematicjs-video-overlay-wrapper { + display: flex; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + align-items: center; + justify-content: center; + pointer-events: none; + + transition: visibility 0.1s ease-in, opacity 0.1s ease-out; +} + +.cinematicjs-video-overlay-container { + width: 136px; + height: 136px; + fill: #ffffff; + background: rgba(0, 0, 0, 0.5); + padding: 40px; + border-radius: 50%; + + transition: transform 0.1s ease-in; +} + +.cinematicjs-video-overlay-wrapper.cinematicjs-hidden .cinematicjs-video-overlay-container { + transform: scale(0.7); +} + +.cinematicjs-video-overlay-container .cinematicjs-video-overlay-icon svg { + width: 56px; + height: 56px; + fill: #ffffff; +} + +.cinematicjs-video-overlay-container .cinematicjs-video-overlay-text { + margin-top: 4px; + text-align: center; + color: #ffffff; +} + +/*endregion*/ + +/*region SVG icons*/ +.cinematicjs-icon-container { + /* Hide the icon container so it does not mess with the page height */ + display: none; +} + +/*endregion*/ + +/*region Helpers*/ +.cinematicjs-hidden { + visibility: hidden; + opacity: 0; +} + +.cinematicjs-clickable { + cursor: pointer !important; +} + +/*endregion*/ diff --git a/dist/cinematic.js b/dist/cinematic.js new file mode 100644 index 0000000..47d0704 --- /dev/null +++ b/dist/cinematic.js @@ -0,0 +1,1299 @@ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); + return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var Cinematic = /** @class */ (function () { + function Cinematic(options) { + this.defaults = { + selector: '', + baseUri: '../dist', + autoplay: false, + startTime: 0, + deeplink: '', + rememberVolume: false, + rememberQuality: false, + quality: '720p', + sources: [], + video: null, + playlist: null, + translations: { + pause: 'Pause', + play: 'Play', + restart: 'Restart', + mute: 'Mute', + unmute: 'Unmute', + settings: 'Settings', + quality: 'Quality', + playbackSpeed: 'Speed', + fullscreen: 'Fullscreen', + close: 'Close', + deeplink: 'Copy deeplink to clipboard', + deeplinkCopied: 'Link was copied', + exitFullscreen: 'Exit Fullscreen', + showSubtitles: 'Show Subtitles', + hideSubtitles: 'Hide Subtitles', + pictureInPicture: 'Picture in picture', + chromecast: 'Stream', + showVideoInfo: 'Show video information', + hideVideoInfo: 'Hide video information' + } + }; + this._sources = new Map(); + this.totalSeconds = 0; + this.playedSeconds = 0; + this.volume = 0; + this.quality = ''; + this.speed = 1; + this._isChangingQuality = false; + this._playButtonKeyboardActivated = false; + this.captionsEnabled = false; + this.fullScreenEnabled = false; + this.pipEnabled = false; + this.userActive = false; + this.options = __assign(__assign({}, this.defaults), options); + var _passedContainer = document.querySelector(this.options.selector); + if (!_passedContainer) { + throw new Error('CinematicJS: Passed selector does not point to a DOM element.'); + } + this._container = _passedContainer; + if (this.options.playlist) { + this.playlist = this.options.playlist; + } + else if (this.options.video) { + this.playlist = new CinematicPlaylist(false, [this.options.video]); + } + else { + throw new Error('CinematicJS: Either a single `video` or a `playlist` has to be passed as options.'); + } + this.filterPlayableSources(); + this.quality = this.options.quality; + if (this.options.rememberQuality) { + var storedQuality = this.readFromLocalStore('quality'); + if (storedQuality) { + this.quality = this.handleVideoQualityFallback(storedQuality); + } + } + if ('pictureInPictureEnabled' in document) { + this.pipEnabled = true; + } + this.loadIcons(); + this.renderPlayer(); + this.updateDisplayedVideoInfo(); + this.setupEvents(); + this._video.load(); + if (this.options.rememberVolume) { + var storedVolume = this.readFromLocalStore('volume'); + if (storedVolume) { + this._video.volume = Number.parseFloat(storedVolume); + } + var storedMuteState = this.readFromLocalStore('muted'); + if (storedMuteState) { + this._video.muted = storedMuteState === 'true'; + } + } + this._container.cinematic = this; + } + Cinematic.prototype.filterPlayableSources = function () { + var _video = document.createElement('video'); + for (var _i = 0, _a = this.playlist.videos; _i < _a.length; _i++) { + var video = _a[_i]; + // Only keep qualities with at least one playable source + video.sources = video.sources.filter(function (source) { + // Only keep sources that may be playable by the browser + source.sources = source.sources.filter(function (source) { + return _video.canPlayType(source.type) !== ''; + }); + return source.sources.length > 0; + }); + } + }; + Cinematic.prototype.loadIcons = function () { + var _iconContainer = document.createElement('span'); + _iconContainer.classList.add('cinematicjs-icon-container'); + document.body.appendChild(_iconContainer); + var request = new XMLHttpRequest(); + request.open("GET", this.options.baseUri + '/icons.svg', true); + request.responseType = "document"; + request.onload = function () { + var _a; + var svg = (_a = request === null || request === void 0 ? void 0 : request.responseXML) === null || _a === void 0 ? void 0 : _a.documentElement; + // Don't render anything that is not an SVG, e.g. an HTML error page + if ((svg === null || svg === void 0 ? void 0 : svg.nodeName) === 'svg') { + _iconContainer.appendChild(svg); + } + }; + request.send(); + }; + Cinematic.prototype.renderPlayer = function () { + var _this = this; + this._container.classList.add('cinematicjs-video-container'); + this._container.role = 'region'; + this._container.ariaLabel = 'Video player'; + var initialVideo = this.playlist.getCurrentVideo(); + this._video = document.createElement('video'); + this._video.preload = 'metadata'; + this._video.tabIndex = 0; + this._video.playsInline = true; + this._video.ariaLabel = 'Video player'; + // Suppress the unwanted right-click context menu of the video element itself + this._video.oncontextmenu = function () { return false; }; + if (this.options.autoplay) { + this._video.autoplay = true; + } + this._container.appendChild(this._video); + var startSource = initialVideo.getSourcesForQuality(this.quality); + if (!startSource) { + throw new Error('CinematicJS: Passed quality does not match any of the passed sources.'); + } + this.updateVideoSourceElements(startSource.sources); + this._overlayWrapper = document.createElement('div'); + this._overlayWrapper.classList.add('cinematicjs-video-overlay-wrapper', 'cinematicjs-hidden'); + this._container.appendChild(this._overlayWrapper); + var _overlayContainer = document.createElement('div'); + _overlayContainer.classList.add('cinematicjs-video-overlay-container'); + this._overlayWrapper.appendChild(_overlayContainer); + this._overlayIcon = document.createElement('div'); + this._overlayIcon.classList.add('cinematicjs-video-overlay-icon'); + Cinematic.renderButtonIcon(this._overlayIcon, 'mute'); + _overlayContainer.appendChild(this._overlayIcon); + this._overlayText = document.createElement('div'); + this._overlayText.classList.add('cinematicjs-video-overlay-text'); + _overlayContainer.appendChild(this._overlayText); + this._uiWrapper = document.createElement('div'); + this._uiWrapper.classList.add('cinematicjs-ui-wrapper'); + this._container.appendChild(this._uiWrapper); + var _header = document.createElement('div'); + _header.classList.add('cinematicjs-video-header'); + this._uiWrapper.appendChild(_header); + this._videoTitleIcon = document.createElement('img'); + this._videoTitleIcon.classList.add('cinematicjs-video-icon'); + _header.appendChild(this._videoTitleIcon); + this._videoTitle = document.createElement('div'); + this._videoTitle.classList.add('cinematicjs-video-title'); + this._videoTitle.addEventListener('click', function () { return _this.handleVideoInfoToggle(); }); + _header.appendChild(this._videoTitle); + this._videoInfoButton = document.createElement('div'); + this._videoInfoButton.classList.add('cinematicjs-video-info-button'); + this._videoInfoButton.role = 'button'; + this._videoInfoButton.tabIndex = 0; + this._videoInfoButton.ariaLabel = this.options.translations.showVideoInfo; + this._videoInfoButton.ariaExpanded = 'false'; + this._videoInfoButton.title = this.options.translations.showVideoInfo; + Cinematic.renderButtonIcon(this._videoInfoButton, 'info'); + _header.appendChild(this._videoInfoButton); + var _headerSpacer = document.createElement('div'); + _headerSpacer.classList.add('cinematicjs-video-header-spacer'); + _header.appendChild(_headerSpacer); + this._chromecastButton = document.createElement('div'); + this._chromecastButton.classList.add('cinematicjs-video-control-button', 'cinematicjs-hidden'); + this._chromecastButton.role = 'button'; + this._chromecastButton.tabIndex = 0; + this._chromecastButton.ariaLabel = this.options.translations.chromecast; + this._chromecastButton.title = this.options.translations.chromecast; + Cinematic.renderButtonIcon(this._chromecastButton, 'chromecast'); + _header.appendChild(this._chromecastButton); + if (this._video.remote) { + this._video.remote.watchAvailability(function (available) { + _this._chromecastButton.classList.toggle('cinematicjs-hidden', !available); + }).catch(function () { + _this._chromecastButton.classList.add('cinematicjs-hidden'); + }); + } + if (this.options.closeCallback) { + this._closeButton = document.createElement('div'); + this._closeButton.classList.add('cinematicjs-video-close-button'); + this._closeButton.role = 'button'; + this._closeButton.tabIndex = 0; + this._closeButton.ariaLabel = this.options.translations.close; + this._closeButton.title = this.options.translations.close; + Cinematic.renderButtonIcon(this._closeButton, 'close'); + _header.appendChild(this._closeButton); + } + this._videoDescription = document.createElement('div'); + this._videoDescription.classList.add('cinematicjs-video-description', 'cinematicjs-hidden'); + this._uiWrapper.appendChild(this._videoDescription); + var _footer = document.createElement('div'); + _footer.classList.add('cinematicjs-video-footer'); + this._uiWrapper.appendChild(_footer); + var _progressWrapper = document.createElement('div'); + _progressWrapper.classList.add('cinematicjs-video-progress-wrapper'); + _footer.appendChild(_progressWrapper); + this._bufferBar = document.createElement('progress'); + this._bufferBar.classList.add('cinematicjs-video-buffer-bar'); + this._bufferBar.value = 0; + _progressWrapper.appendChild(this._bufferBar); + this._progressBar = document.createElement('progress'); + this._progressBar.classList.add('cinematicjs-video-progress-bar'); + this._progressBar.role = 'slider'; + this._progressBar.tabIndex = 0; + this._progressBar.ariaLabel = 'Video progress'; + this._progressBar.ariaValueMin = '0'; + this._progressBar.ariaValueMax = '100'; + this._progressBar.ariaValueNow = '0'; + this._progressBar.value = 0; + _progressWrapper.appendChild(this._progressBar); + this._controls = document.createElement('div'); + this._controls.classList.add('cinematicjs-video-controls'); + _footer.appendChild(this._controls); + this._playButton = document.createElement('div'); + this._playButton.classList.add('cinematicjs-video-control-button'); + this._playButton.role = 'button'; + this._playButton.tabIndex = 0; + this._playButton.ariaLabel = this.options.translations.play; + Cinematic.renderButtonIcon(this._playButton, 'play'); + this._controls.appendChild(this._playButton); + this._timer = document.createElement('span'); + this._timer.classList.add('cinematicjs-video-control-timer'); + this._timer.textContent = '00:00:00 / 00:00:00'; + this._controls.appendChild(this._timer); + var _spacer = document.createElement('div'); + _spacer.classList.add('video-control-spacer'); + this._controls.appendChild(_spacer); + var _volumeWrapper = document.createElement('div'); + _volumeWrapper.classList.add('cinematicjs-video-volume-wrapper'); + this._controls.appendChild(_volumeWrapper); + this._volumeSlider = document.createElement('input'); + this._volumeSlider.type = 'range'; + this._volumeSlider.min = '0'; + this._volumeSlider.max = '1'; + this._volumeSlider.step = '0.05'; + this._volumeSlider.value = '1'; + this._volumeSlider.ariaLabel = 'Volume'; + this._volumeSlider.classList.add('cinematicjs-video-volume-slider'); + _volumeWrapper.appendChild(this._volumeSlider); + this._volumeButton = document.createElement('div'); + this._volumeButton.classList.add('cinematicjs-video-control-button'); + this._volumeButton.role = 'button'; + this._volumeButton.tabIndex = 0; + this._volumeButton.ariaLabel = this.options.translations.mute; + this._volumeButton.title = this.options.translations.mute; + Cinematic.renderButtonIcon(this._volumeButton, 'sound'); + _volumeWrapper.appendChild(this._volumeButton); + this._settingsWrapper = document.createElement('div'); + this._settingsWrapper.classList.add('cinematicjs-video-control-dropdown'); + this._controls.appendChild(this._settingsWrapper); + this._settingsButton = document.createElement('div'); + this._settingsButton.classList.add('cinematicjs-video-control-button'); + this._settingsButton.role = 'button'; + this._settingsButton.tabIndex = 0; + this._settingsButton.ariaLabel = this.options.translations.mute; + this._settingsButton.ariaExpanded = 'false'; + this._settingsButton.title = this.options.translations.settings; + Cinematic.renderButtonIcon(this._settingsButton, 'settings'); + this._settingsWrapper.appendChild(this._settingsButton); + globalThis.addEventListener('click', function (event) { + // Clicks inside the Dropdown should not close it again. + if (!(event.target instanceof Element) || !(event.target).matches('.cinematicjs-video-control-dropdown, .cinematicjs-video-control-dropdown *')) { + _this._settingsWrapper.classList.remove('cinematicjs-dropdown-active'); + _this._settingsButton.ariaExpanded = 'false'; + } + }); + var _dropDownContent = document.createElement('div'); + _dropDownContent.classList.add('cinematicjs-video-dropdown-content'); + this._settingsWrapper.appendChild(_dropDownContent); + // Adds keyboard support for closing the dropdown with Escape + _dropDownContent.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + event.preventDefault(); + event.stopPropagation(); + _this._settingsWrapper.classList.remove('cinematicjs-dropdown-active'); + _this._settingsWrapper.ariaExpanded = 'false'; + _this._settingsButton.focus(); + } + }); + // Close dropdown when focus moves outside of it + _dropDownContent.addEventListener('focusout', function (event) { + // Use setTimeout to allow the browser to update document.activeElement + setTimeout(function () { + var activeElement = document.activeElement; + // Check if the new focus target is outside the dropdown + if (activeElement && !_this._settingsWrapper.contains(activeElement)) { + _this._settingsWrapper.classList.remove('cinematicjs-dropdown-active'); + _this._settingsButton.ariaExpanded = 'false'; + } + }, 0); + }); + this._qualitySettingsSection = document.createElement('div'); + this._qualitySettingsSection.classList.add('cinematicjs-video-dropdown-section'); + _dropDownContent.appendChild(this._qualitySettingsSection); + var _qualitySettingsTitle = document.createElement('span'); + _qualitySettingsTitle.textContent = this.options.translations.quality; + this._qualitySettingsSection.appendChild(_qualitySettingsTitle); + this._qualitySelect = document.createElement('select'); + this._qualitySelect.name = 'quality'; + this._qualitySelect.ariaLabel = this.options.translations.quality; + this._qualitySelect.tabIndex = 0; + this._qualitySelect.addEventListener('change', function () { + _this.handleQualityChange(_this._qualitySelect.value); + // Return focus to quality select after change + setTimeout(function () { + _this._qualitySelect.focus(); + }, 100); + }); + // Track mouse interactions to prevent focus styles on click + var isMouseDown = false; + this._qualitySelect.addEventListener('mousedown', function () { + isMouseDown = true; + _this._qualitySelect.classList.add('mouse-focus'); + }); + this._qualitySelect.addEventListener('focus', function () { + if (!isMouseDown) { + _this._qualitySelect.classList.remove('mouse-focus'); + } + isMouseDown = false; + }); + this._qualitySelect.addEventListener('blur', function () { + _this._qualitySelect.classList.remove('mouse-focus'); + }); + this.renderQualityOptions(); + this._qualitySettingsSection.appendChild(this._qualitySelect); + var _speedSettingsSection = document.createElement('div'); + _speedSettingsSection.classList.add('cinematicjs-video-dropdown-section'); + _dropDownContent.appendChild(_speedSettingsSection); + var _speedSettingsTitle = document.createElement('span'); + _speedSettingsTitle.textContent = this.options.translations.playbackSpeed; + _speedSettingsSection.appendChild(_speedSettingsTitle); + var _speedSelect = document.createElement('select'); + _speedSelect.name = 'speed'; + _speedSelect.ariaLabel = this.options.translations.playbackSpeed; + _speedSelect.tabIndex = 0; + _speedSelect.addEventListener('change', function () { + _this.handleSpeedChange(_speedSelect.value); + // Return focus to speed select after change + setTimeout(function () { + _speedSelect.focus(); + }, 100); + }); + // Track mouse interactions to prevent focus styles on click + var speedMouseDown = false; + _speedSelect.addEventListener('mousedown', function () { + speedMouseDown = true; + _speedSelect.classList.add('mouse-focus'); + }); + _speedSelect.addEventListener('focus', function () { + if (!speedMouseDown) { + _speedSelect.classList.remove('mouse-focus'); + } + speedMouseDown = false; + }); + _speedSelect.addEventListener('blur', function () { + _speedSelect.classList.remove('mouse-focus'); + }); + for (var _i = 0, _a = [0.5, 1, 1.25, 1.5, 1.75, 2]; _i < _a.length; _i++) { + var speedSetting = _a[_i]; + var _option = document.createElement('option'); + _option.textContent = speedSetting + 'x'; + _option.value = speedSetting + ''; + _speedSelect.appendChild(_option); + } + _speedSelect.value = '1'; + _speedSettingsSection.appendChild(_speedSelect); + if (this.options.deeplink) { + this._deeplinkButton = document.createElement('div'); + this._deeplinkButton.classList.add('cinematicjs-video-control-button'); + this._deeplinkButton.role = 'button'; + this._deeplinkButton.tabIndex = 0; + this._deeplinkButton.ariaLabel = this.options.translations.deeplink; + this._deeplinkButton.title = this.options.translations.deeplink; + this._deeplinkButton.dataset.copiedText = this.options.translations.deeplinkCopied; + Cinematic.renderButtonIcon(this._deeplinkButton, 'deeplink'); + this._controls.appendChild(this._deeplinkButton); + } + this._cuesContainer = document.createElement('div'); + this._cuesContainer.classList.add('cinematicjs-video-cues-container', 'cinematicjs-hidden'); + this._container.appendChild(this._cuesContainer); + this._cues = document.createElement('div'); + this._cues.classList.add('video-cues', 'cinematicjs-hidden'); + this._cuesContainer.appendChild(this._cues); + this._captionsButton = document.createElement('div'); + this._captionsButton.classList.add('cinematicjs-video-control-button'); + this._captionsButton.role = 'button'; + this._captionsButton.tabIndex = 0; + this._captionsButton.ariaLabel = this.options.translations.showSubtitles; + this._captionsButton.ariaPressed = 'false'; + this._captionsButton.title = this.options.translations.showSubtitles; + Cinematic.renderButtonIcon(this._captionsButton, 'expanded-cc'); + this._controls.appendChild(this._captionsButton); + this.prepareSubtitles(); + if (this.pipEnabled) { + this._pipButton = document.createElement('div'); + this._pipButton.classList.add('cinematicjs-video-control-button'); + this._pipButton.role = 'button'; + this._pipButton.tabIndex = 0; + this._pipButton.ariaLabel = this.options.translations.pictureInPicture; + this._pipButton.title = this.options.translations.pictureInPicture; + Cinematic.renderButtonIcon(this._pipButton, 'inpicture'); + this._controls.appendChild(this._pipButton); + } + this._fullScreenButton = document.createElement('div'); + this._fullScreenButton.classList.add('cinematicjs-video-control-button', 'cinematicjs-hidden'); + this._fullScreenButton.role = 'button'; + this._fullScreenButton.tabIndex = 0; + this._fullScreenButton.ariaLabel = this.options.translations.fullscreen; + this._fullScreenButton.title = this.options.translations.fullscreen; + Cinematic.renderButtonIcon(this._fullScreenButton, 'fullscreen'); + this._controls.appendChild(this._fullScreenButton); + }; + Cinematic.prototype.updateVideoSourceElements = function (sources) { + var _this = this; + var _previousSource = null; + for (var _i = 0, sources_1 = sources; _i < sources_1.length; _i++) { + var source = sources_1[_i]; + var _source = this._sources.get(source.type); + if (_source) { + // Update the existing source element + _source.src = source.source; + _previousSource = _source; + return; + } + // Create a new source element. + _source = document.createElement('source'); + _source.src = source.source; + _source.type = source.type; + this._sources.set(source.type, _source); + if (_previousSource) { + // Insert the new source element after the previous one. + _previousSource.insertAdjacentElement('afterend', _source); + } + else { + // Insert the first source element at the beginning of the video element. + this._video.insertBefore(_source, this._video.firstChild); + } + _previousSource = _source; + } + // Remove all source elements that are not contained in the new sources array. + this._sources.forEach(function (_source, type) { + if (!sources.some(function (source) { return source.type === type; })) { + _source.remove(); + _this._sources.delete(type); + } + }); + }; + Cinematic.prototype.renderQualityOptions = function () { + this._qualitySelect.textContent = ''; + if (this.playlist.getCurrentVideo().sources.length > 1) { + for (var _i = 0, _a = this.playlist.getCurrentVideo().sources; _i < _a.length; _i++) { + var source = _a[_i]; + var _option = document.createElement('option'); + _option.textContent = source.quality; + _option.value = source.quality; + this._qualitySelect.appendChild(_option); + } + this._qualitySelect.value = this.quality; + this._qualitySettingsSection.classList.remove('cinematicjs-hidden'); + } + else { + this._qualitySettingsSection.classList.add('cinematicjs-hidden'); + } + }; + /** + * Falls back to the best available quality for the current video when it does not provide the given quality. + * + * @param newQuality the preferred quality to play + * @private + */ + Cinematic.prototype.handleVideoQualityFallback = function (newQuality) { + if (!newQuality) { + return newQuality; + } + var currentVideo = this.playlist.getCurrentVideo(); + var newSource = currentVideo.getSourcesForQuality(newQuality); + if (!newSource) { + newQuality = currentVideo.getBestAvailableQuality(); + } + return newQuality; + }; + Cinematic.prototype.handleQualityChange = function (newQuality) { + var _this = this; + if (!newQuality) { + return; + } + newQuality = this.handleVideoQualityFallback(newQuality); + var newSource = this.playlist.getCurrentVideo().getSourcesForQuality(newQuality); + if (!newSource) { + return; + } + if (this.options.rememberQuality) { + this.writeToLocalStore('quality', newQuality); + } + var currentTime = this._video.currentTime; + var wasPlaying = !this._video.paused; + // Set flag to prevent focus changes during quality change + this._isChangingQuality = true; + this.updateVideoSourceElements(newSource.sources); + this._video.load(); + this._video.currentTime = currentTime; + this._video.playbackRate = this.speed; + if (wasPlaying) { + this._video.play(); + } + this.quality = newQuality; + // Reset flag after quality change completes + setTimeout(function () { + _this._isChangingQuality = false; + }, 200); + }; + Cinematic.prototype.handleSpeedChange = function (newSpeed) { + if (!newSpeed) { + return; + } + this.speed = typeof newSpeed === 'string' ? Number.parseFloat(newSpeed) : newSpeed; + this._video.playbackRate = this.speed; + }; + Cinematic.prototype.handleVideoInfoToggle = function () { + this._videoDescription.classList.toggle('cinematicjs-hidden'); + var isHidden = this._videoDescription.classList.contains('cinematicjs-hidden'); + if (isHidden) { + this._videoInfoButton.title = this.options.translations.showVideoInfo; + this._videoInfoButton.ariaLabel = this.options.translations.showVideoInfo; + this._videoInfoButton.ariaExpanded = 'false'; + } + else { + this._videoInfoButton.title = this.options.translations.hideVideoInfo; + this._videoInfoButton.ariaLabel = this.options.translations.hideVideoInfo; + this._videoInfoButton.ariaExpanded = 'true'; + } + }; + Cinematic.prototype.prepareSubtitles = function () { + var _this = this; + var _oldTrack = this._video.querySelector('track'); + if (_oldTrack) { + _oldTrack.remove(); + this._captionsButton.classList.add('cinematicjs-hidden'); + } + var video = this.playlist.getCurrentVideo(); + if (!video.subtitles) { + this._cues.classList.add('cinematicjs-hidden'); + this._captionsButton.classList.add('cinematicjs-hidden'); + this.tracks = null; + this.cues = null; + return; + } + var _subtitles = document.createElement('track'); + _subtitles.label = 'subtitles'; + _subtitles.kind = 'subtitles'; + _subtitles.src = video.subtitles; + _subtitles.default = true; + this._video.appendChild(_subtitles); + if (_subtitles.readyState === 2) { + this.handleLoadedTrack(); + } + else { + _subtitles.addEventListener('load', function () { return _this.handleLoadedTrack(); }); + } + this._captionsButton.classList.remove('cinematicjs-hidden'); + }; + Cinematic.prototype.handleLoadedTrack = function () { + this.tracks = this._video.textTracks[0]; + this.tracks.mode = 'hidden'; + this.cues = this.tracks.cues; + var me = this; + var onCueEnter = function () { + me._cues.textContent = this.text; + me._cues.classList.remove('cinematicjs-hidden'); + }; + var onCueExit = function () { + me._cues.textContent = ''; + me._cues.classList.add('cinematicjs-hidden'); + }; + if (this.cues) { + for (var i = 0; i < this.cues.length; i++) { + var cue = this.cues[i]; + cue.onenter = onCueEnter; + cue.onexit = onCueExit; + } + } + }; + Cinematic.prototype.setupEvents = function () { + var _this = this; + var me = this; + // Helper function to add both click and keyboard support to buttons + var addButtonHandler = function (_button, handler) { + _button.addEventListener('click', function (event) { return handler(event); }); + _button.addEventListener('keydown', function (event) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handler(event); + } + }); + }; + window.addEventListener('resize', function () { return _this.handlePlayerResize(); }); + this.handlePlayerResize(); + if (globalThis.ResizeObserver) { + new ResizeObserver(function () { return _this.handlePlayerResize(); }).observe(this._container); + } + addButtonHandler(this._playButton, function (event) { + _this._playButtonKeyboardActivated = event instanceof KeyboardEvent; + if (_this._video.ended) { + _this.playlist.resetToBeginning(); + _this.handleVideoChange(); + } + else if (_this._video.paused) { + _this._video.play(); + } + else { + _this._video.pause(); + } + }); + addButtonHandler(this._volumeButton, function () { + _this._video.muted = !_this._video.muted; + }); + // Settings button handler + addButtonHandler(this._settingsButton, function (event) { + _this._settingsWrapper.classList.toggle('cinematicjs-dropdown-active'); + var isExpanded = _this._settingsWrapper.classList.contains('cinematicjs-dropdown-active'); + _this._settingsButton.ariaExpanded = isExpanded.toString(); + // Only focus the select element when opening via keyboard, not mouse + if (isExpanded && event instanceof KeyboardEvent) { + setTimeout(function () { + if (_this._qualitySettingsSection.classList.contains('cinematicjs-hidden')) { + // If quality select is hidden, focus speed select + var speedSelect = _this._settingsWrapper.querySelector('select[name="speed"]'); + if (speedSelect) { + speedSelect.focus(); + } + } + else { + _this._qualitySelect.focus(); + } + }, 0); + } + if (event) { + event.stopPropagation(); + } + }); + this._volumeSlider.addEventListener('change', function () { + // To allow the user to change from mute to a specific volume via the slider. + _this._video.muted = false; + _this._video.volume = _this.volume = Number.parseFloat(_this._volumeSlider.value); + }); + this._video.addEventListener('loadedmetadata', function () { + me.totalSeconds = this.duration; + me._progressBar.setAttribute('max', me.totalSeconds.toString()); + me._bufferBar.setAttribute('max', me.totalSeconds.toString()); + me.updateTimer(); + if (me.options.startTime > 0) { + this.currentTime = me.options.startTime; + } + me.fullScreenEnabled = document.fullscreenEnabled || document.webkitFullscreenEnabled || me._video.webkitSupportsFullscreen; + me._fullScreenButton.classList.toggle('cinematicjs-hidden', !me.fullScreenEnabled); + }); + this._video.addEventListener('timeupdate', function () { + me.playedSeconds = this.currentTime; + me._progressBar.value = me.playedSeconds; + // Update aria-valuenow for accessibility + var percentage = me.totalSeconds > 0 ? Math.round((me.playedSeconds / me.totalSeconds) * 100) : 0; + me._progressBar.ariaValueNow = percentage.toString(); + me.updateTimer(); + }); + this._video.addEventListener('volumechange', function () { + if (_this.options.rememberVolume) { + _this.writeToLocalStore('volume', _this._video.volume.toString()); + _this.writeToLocalStore('muted', String(_this._video.muted)); + } + if (_this._video.muted) { + // Set the volume slider to its min value to indicate the mute. + _this._volumeSlider.value = '0'; + Cinematic.switchButtonIcon(_this._volumeButton, 'mute'); + _this._volumeButton.title = _this.options.translations.unmute; + _this._volumeButton.ariaLabel = _this.options.translations.unmute; + } + else { + _this._volumeSlider.value = _this._video.volume.toString(); + _this._volumeButton.title = _this.options.translations.mute; + _this._volumeButton.ariaLabel = _this.options.translations.mute; + if (_this.volume > 0.5) { + Cinematic.switchButtonIcon(_this._volumeButton, 'sound'); + } + else { + Cinematic.switchButtonIcon(_this._volumeButton, 'low'); + } + } + }); + this._video.addEventListener('play', function () { + Cinematic.switchButtonIcon(me._playButton, 'pause'); + me._playButton.title = me.options.translations.pause; + me._playButton.ariaLabel = me.options.translations.pause; + // Don't change focus during quality changes + if (!me._isChangingQuality) { + // Only focus the video if the play button wasn't activated via keyboard + if (me._playButtonKeyboardActivated) { + // Keep focus on the play button for keyboard users + me._playButton.focus(); + } + else { + me._video.focus(); + } + } + me._playButtonKeyboardActivated = false; + // Shows the timer even when the video container is invisible during initialization of the player + _this.handlePlayerResize(); + }); + this._video.addEventListener('pause', function () { + Cinematic.switchButtonIcon(me._playButton, 'play'); + me._playButton.title = me.options.translations.play; + me._playButton.ariaLabel = me.options.translations.play; + // Return focus to the play button if it was keyboard activated + if (me._playButtonKeyboardActivated) { + me._playButton.focus(); + } + me._playButtonKeyboardActivated = false; + }); + this._video.addEventListener('ended', function () { + if (_this.playlist.shouldPlayNextVideo()) { + _this.playlist.startNextVideo(); + _this.handleVideoChange(); + } + else { + Cinematic.switchButtonIcon(_this._playButton, 'repeat'); + _this._playButton.title = me.options.translations.restart; + _this._playButton.ariaLabel = me.options.translations.restart; + _this.showControls(); + } + }); + this._video.addEventListener('progress', function () { + if (this.duration > 0) { + for (var i = 0; i < this.buffered.length; i++) { + var bufferRangeIndex = this.buffered.length - 1 - i; + var bufferStart = this.buffered.start(bufferRangeIndex); + var bufferEnd = this.buffered.end(bufferRangeIndex); + if (bufferStart <= this.currentTime) { + me._bufferBar.value = (bufferEnd / this.duration) * 100; + break; + } + } + } + }); + this._video.addEventListener('click', function () { + globalThis.setTimeout(function () { + if (_this._video.ended) { + _this.playlist.resetToBeginning(); + _this.handleVideoChange(); + _this.showOverlay('play', null, true); + } + else if (me._video.paused) { + me._video.play(); + _this.showOverlay('play', null, true); + } + else { + me._video.pause(); + _this.showOverlay('pause', null, true); + } + _this.userActive = true; + }, 300); + }); + this._video.addEventListener('dblclick', function (event) { + if (_this.doubleClickTimeout) { + clearTimeout(_this.doubleClickTimeout); + } + // Get the bounding rectangle of target + var rect = _this._video.getBoundingClientRect(); + var thirds = rect.width / 3; + // Mouse position + var x = event.clientX - rect.left; + if (x <= thirds) { + _this._video.currentTime -= 10; + _this.showOverlay('backwards', '- 10s', true); + } + else if (x <= thirds * 2) { + _this.toggleFullScreen(); + } + else { + _this._video.currentTime += 10; + _this.showOverlay('fastforward', '+ 10s', true); + } + _this.userActive = true; + }); + this._container.addEventListener('mousemove', function () { return _this.userActive = true; }); + // Show controls when a video element receives focus + this._video.addEventListener('focus', function () { + _this.userActive = true; + _this.showControls(); + }); + // Keep controls visible when keyboard navigating through them + this._controls.addEventListener('focusin', function () { + _this.userActive = true; + _this.showControls(); + }); + this._progressBar.addEventListener('focus', function () { + _this.userActive = true; + _this.showControls(); + }); + this.userActiveCheck = globalThis.setInterval(function () { + if (!_this.userActive) { + return; + } + _this.userActive = false; + _this.showControls(); + clearTimeout(_this.userInactiveTimeout); + _this.userInactiveTimeout = globalThis.setTimeout(function () { + // Check if any control element has focus + var _activeElement = document.activeElement; + var hasControlFocus = _activeElement && (_activeElement.parentElement == _this._controls || + _activeElement == _this._progressBar || + _activeElement == _this._volumeSlider || + _this._controls.contains(_activeElement)); + // We don't want to hide the controls when: + // - The settings popup is currently open/visible + // - Any control element has keyboard focus + if (!_this.userActive && !_this._settingsWrapper.classList.contains('cinematicjs-dropdown-active') && !hasControlFocus) { + _this.hideControls(); + if (_activeElement && _activeElement.parentElement == _this._controls) { + // We put focus on the video element so hotkeys work again after a control bar button is pressed + // and the user is inactive again. + _this._video.focus(); + } + } + }, 2000); + }, 250); + this._progressBar.addEventListener('click', function (event) { + var _target = event.target; + var rect = _target.getBoundingClientRect(); + var pos = (event.clientX - rect.left) / this.offsetWidth; + me._video.currentTime = pos * me._video.duration; + }); + addButtonHandler(this._fullScreenButton, function () { return me.toggleFullScreen(); }); + document.addEventListener('fullscreenchange', function () { return _this.handleFullScreenChange(); }); + document.addEventListener('webkitfullscreenchange', function () { return _this.handleFullScreenChange(); }); + if (this.options.deeplink) { + addButtonHandler(this._deeplinkButton, function () { + if (!_this.options.deeplinkCallback || _this.options.deeplinkCallback.call(_this)) { + me.copyToClipboard(me.options.deeplink, me._deeplinkButton); + } + }); + } + addButtonHandler(this._captionsButton, function () { + me._cuesContainer.classList.toggle('cinematicjs-hidden'); + if (me.captionsEnabled) { + me._captionsButton.title = me.options.translations.showSubtitles; + me._captionsButton.ariaLabel = me.options.translations.showSubtitles; + me._captionsButton.ariaPressed = 'false'; + Cinematic.switchButtonIcon(me._captionsButton, 'expanded-cc'); + } + else { + me._captionsButton.title = me.options.translations.hideSubtitles; + me._captionsButton.ariaLabel = me.options.translations.hideSubtitles; + me._captionsButton.ariaPressed = 'true'; + Cinematic.switchButtonIcon(me._captionsButton, 'cc'); + } + me.captionsEnabled = !me.captionsEnabled; + }); + if (this.pipEnabled) { + addButtonHandler(this._pipButton, function () { return __awaiter(_this, void 0, void 0, function () { + var error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 5, , 6]); + if (!(this._video === document.pictureInPictureElement)) return [3 /*break*/, 2]; + return [4 /*yield*/, document.exitPictureInPicture()]; + case 1: + _a.sent(); + return [3 /*break*/, 4]; + case 2: return [4 /*yield*/, this._video.requestPictureInPicture()]; + case 3: + _a.sent(); + _a.label = 4; + case 4: return [3 /*break*/, 6]; + case 5: + error_1 = _a.sent(); + console.error(error_1); + return [3 /*break*/, 6]; + case 6: return [2 /*return*/]; + } + }); + }); }); + } + if (this.options.closeCallback) { + addButtonHandler(this._closeButton, function () { + var _a; + if (_this.isFullScreen()) { + _this.toggleFullScreen(); + } + (_a = _this.options.closeCallback) === null || _a === void 0 ? void 0 : _a.apply(_this); + }); + } + // Add keyboard handler for video info button + addButtonHandler(this._videoInfoButton, function () { return _this.handleVideoInfoToggle(); }); + // Add keyboard handler for chromecast button + addButtonHandler(this._chromecastButton, function () { + if (_this._video.remote) { + _this._video.remote.prompt(); + } + }); + this._video.addEventListener('keydown', function (event) { + var key = event.key; + event.preventDefault(); + event.stopPropagation(); + switch (key) { + // Space bar allows pausing/resume the video + case ' ': + case 'Spacebar': + _this.userActive = true; + if (_this._video.paused) { + _this._video.play(); + _this.showOverlay('play', null, true); + } + else { + _this._video.pause(); + _this.showOverlay('pause', null, true); + } + break; + // Escape leaves the fullscreen when currently enabled + case 'Escape': + _this.userActive = true; + if (_this.fullScreenEnabled && _this.isFullScreen()) { + _this.toggleFullScreen(); + } + break; + // Left Arrow skips 10 seconds into the past + case 'ArrowLeft': + case 'Left': + _this.userActive = true; + _this._video.currentTime -= 10; + _this.showOverlay('backwards', '- 10s', true); + break; + // Right Arrow skips 10 seconds into the future + case 'ArrowRight': + case 'Right': + _this.userActive = true; + _this._video.currentTime += 10; + _this.showOverlay('fastforward', '+ 10s', true); + break; + // Down Arrow decreases the volume by 5% + case 'ArrowDown': + case 'Down': + _this.userActive = true; + if (_this._video.volume > 0) { + var currentVolume = Math.round((_this._video.volume + Cinematic.getEpsilon()) * 100); + _this.volume = (currentVolume - 5) / 100; + _this._video.volume = _this.volume; + if (_this.volume === 0) { + // Also switch on mute when we reach 0% volume + _this._video.muted = true; + _this.showOverlay('mute', '0 %', true); + } + else { + _this.showOverlay('low', Math.round(_this.volume * 100) + ' %', true); + } + _this._volumeSlider.value = _this.volume.toString(); + } + break; + // Up Arrow increases the volume by 5% + case 'ArrowUp': + case 'Up': + _this.userActive = true; + if (_this._video.volume < 1) { + var currentVolume = Math.round((_this._video.volume + Cinematic.getEpsilon()) * 100); + _this.volume = (currentVolume + 5) / 100; + _this._video.volume = _this.volume; + // Unmute if we previously were muted + _this._video.muted = false; + _this.showOverlay('sound', Math.round(_this.volume * 100) + ' %', true); + _this._volumeSlider.value = _this.volume.toString(); + } + break; + } + }); + return true; + }; + Cinematic.prototype.handleVideoChange = function () { + this.prepareSubtitles(); + this.renderQualityOptions(); + this.handleQualityChange(this.quality); + this.handleSpeedChange(this.speed); + this.updateDisplayedVideoInfo(); + this._video.currentTime = 0; + this._video.play(); + }; + Cinematic.prototype.updateDisplayedVideoInfo = function () { + var currentVideo = this.playlist.getCurrentVideo(); + this._video.poster = currentVideo.poster || ''; + this._videoTitleIcon.src = currentVideo.titleIcon || ''; + this._videoTitleIcon.classList.toggle('cinematicjs-hidden', this._videoTitleIcon.src.length === 0); + this._videoTitle.textContent = currentVideo.title || ''; + this._videoTitle.classList.toggle('cinematicjs-clickable', !!currentVideo.description); + this._videoInfoButton.classList.toggle('cinematicjs-hidden', !currentVideo.description); + this._videoDescription.textContent = currentVideo.description || ''; + }; + Cinematic.prototype.handlePlayerResize = function () { + if (this._container.clientWidth >= 328) { + this._timer.classList.remove('cinematicjs-hidden'); + } + else { + this._timer.classList.add('cinematicjs-hidden'); + } + }; + Cinematic.renderButtonIcon = function (_button, icon) { + var _icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + _icon.setAttribute('viewBox', '0 0 24 24'); + var _use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); + _use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-' + icon); + _icon.appendChild(_use); + _button.appendChild(_icon); + }; + Cinematic.switchButtonIcon = function (_button, newIcon) { + var _a; + (_a = _button.querySelector('svg use')) === null || _a === void 0 ? void 0 : _a.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-' + newIcon); + }; + Cinematic.prototype.showOverlay = function (icon, text, hideAutomatically) { + var _this = this; + Cinematic.switchButtonIcon(this._overlayIcon, icon); + this._overlayText.textContent = text; + this._overlayWrapper.classList.remove('cinematicjs-hidden'); + clearTimeout(this.overlayHideTimeout); + if (hideAutomatically) { + this.overlayHideTimeout = globalThis.setTimeout(function () { + _this._overlayWrapper.classList.add('cinematicjs-hidden'); + }, 500); + } + }; + Cinematic.prototype.formatTime = function (seconds) { + var hourComponent = Math.floor(seconds / 3600); + var minuteComponent = Math.floor(seconds / 60 % 60); + var secondComponent = Math.floor(seconds % 60); + var timer = this.toTimerComponent(minuteComponent) + ':' + this.toTimerComponent(secondComponent); + if (this.totalSeconds >= (60 * 60)) { + // Include the hours in both timers when the video is at least an hour long + return this.toTimerComponent(hourComponent) + ':' + timer; + } + return timer; + }; + Cinematic.prototype.toTimerComponent = function (value) { + return value < 10 ? '0' + value : value; + }; + Cinematic.prototype.updateTimer = function () { + this._timer.textContent = this.formatTime(this.playedSeconds) + ' / ' + this.formatTime(this.totalSeconds); + }; + Cinematic.prototype.writeToLocalStore = function (name, value) { + try { + if (globalThis.localStorage) { + globalThis.localStorage.setItem('cinematic-js-' + name, value); + } + } + catch (error) { + console.log('CinematicJS: Cannot write to local store', { name: name, value: value, error: error }); + } + }; + Cinematic.prototype.readFromLocalStore = function (name) { + try { + if (globalThis.localStorage) { + return globalThis.localStorage.getItem('cinematic-js-' + name); + } + } + catch (error) { + console.log('CinematicJS: Cannot read from local store', { name: name, error: error }); + } + return null; + }; + Cinematic.prototype.toggleFullScreen = function () { + if (document.fullscreenElement) { + document.exitFullscreen(); + } + else if (document.webkitFullscreenElement) { + // Need this to support Safari + document.webkitExitFullscreen(); + } + else if (this._container.webkitRequestFullscreen) { + // Need this to support Safari + this._container.webkitRequestFullscreen(); + } + else if (this._video.webkitEnterFullscreen) { + // Need this to support iOS Safari + this._video.webkitEnterFullscreen(); + } + else { + this._container.requestFullscreen(); + } + }; + Cinematic.prototype.handleFullScreenChange = function () { + if (this.isFullScreen()) { + this._container.dataset.fullscreen = true; + Cinematic.switchButtonIcon(this._fullScreenButton, 'closefullscreen'); + this._fullScreenButton.title = this.options.translations.exitFullscreen; + this._fullScreenButton.ariaLabel = this.options.translations.exitFullscreen; + } + else { + this._container.dataset.fullscreen = false; + Cinematic.switchButtonIcon(this._fullScreenButton, 'fullscreen'); + this._fullScreenButton.title = this.options.translations.fullscreen; + this._fullScreenButton.ariaLabel = this.options.translations.fullscreen; + } + }; + Cinematic.prototype.showControls = function () { + this._container.classList.remove('cinematicjs-video-user-inactive'); + this._uiWrapper.classList.remove('cinematicjs-hidden'); + }; + Cinematic.prototype.hideControls = function () { + if (this._video.paused) { + return; + } + this._container.classList.add('cinematicjs-video-user-inactive'); + this._uiWrapper.classList.add('cinematicjs-hidden'); + }; + Cinematic.prototype.isFullScreen = function () { + return document.fullscreenElement || document.webkitFullscreenElement; + }; + Cinematic.prototype.copyToClipboard = function (text, _element) { + /* + * inspired by clipboard.js v1.5.12 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ + var fakeElem = document.createElement('textarea'); + fakeElem.contentEditable = 'true'; + // Prevent zooming on iOS + fakeElem.style.fontSize = '12pt'; + // Reset box model + fakeElem.style.border = '0'; + fakeElem.style.padding = '0'; + fakeElem.style.margin = '0'; + // Move element out of the screen horizontally + fakeElem.style.position = 'absolute'; + fakeElem.style[document.documentElement.getAttribute('dir') == 'rtl' ? 'right' : 'left'] = '-9999px'; + // Move element to the same position vertically + fakeElem.style.top = (window.scrollY || document.documentElement.scrollTop) + 'px'; + fakeElem.readOnly = true; + fakeElem.value = text; + document.body.appendChild(fakeElem); + fakeElem.focus(); + var range = document.createRange(); + range.selectNodeContents(fakeElem); + var selection = globalThis.getSelection(); + selection === null || selection === void 0 ? void 0 : selection.removeAllRanges(); + selection === null || selection === void 0 ? void 0 : selection.addRange(range); + fakeElem.setSelectionRange(0, text.length); + if (document.execCommand('copy') && _element !== undefined) { + _element.classList.add('cinematicjs-copied'); + setTimeout(function () { + _element.classList.remove('cinematicjs-copied'); + }, 2000); + } + fakeElem.remove(); + // Return focus to the button after copying + if (_element) { + _element.focus(); + } + /* Try alternative */ + var copy = function (event) { + if (event.clipboardData) { + event.clipboardData.setData('text/plain', text); + } + else if (globalThis.clipboardData) { + globalThis.clipboardData.setData('Text', text); + } + event.preventDefault(); + }; + globalThis.addEventListener('copy', copy); + document.execCommand('copy'); + globalThis.removeEventListener('copy', copy); + }; + Cinematic.getEpsilon = function () { + if (Number.EPSILON) { + return Number.EPSILON; + } + var epsilon = 1; + while ((1 + 0.5 * epsilon) !== 1) { + epsilon *= 0.5; + } + return epsilon; + }; + return Cinematic; +}()); +var CinematicVideo = /** @class */ (function () { + function CinematicVideo(options) { + this.poster = options.poster; + this.titleIcon = options.titleIcon; + this.title = options.title; + this.description = options.description; + this.subtitles = options.subtitles; + this.sources = options.sources; + } + CinematicVideo.prototype.getSourcesForQuality = function (quality) { + if (this.sources.length === 1) { + return this.sources[0]; + } + for (var _i = 0, _a = this.sources; _i < _a.length; _i++) { + var source = _a[_i]; + if (source.quality === quality) { + return source; + } + } + return null; + }; + CinematicVideo.prototype.getBestAvailableQuality = function () { + return this.sources[0].quality; + }; + return CinematicVideo; +}()); +var CinematicPlaylist = /** @class */ (function () { + function CinematicPlaylist(loop, videos) { + this.loop = loop; + this.videos = videos; + this.currentVideo = 0; + if (this.videos.length === 0) { + throw new Error('CinematicJS: At least one video has to be passed.'); + } + } + CinematicPlaylist.prototype.getCurrentVideo = function () { + return this.videos[this.currentVideo]; + }; + CinematicPlaylist.prototype.shouldPlayNextVideo = function () { + return this.videos.length > 1 && (this.currentVideo + 1 < this.videos.length || this.loop); + }; + CinematicPlaylist.prototype.startNextVideo = function () { + this.currentVideo++; + if (this.loop && this.currentVideo >= this.videos.length) { + this.resetToBeginning(); + } + }; + CinematicPlaylist.prototype.resetToBeginning = function () { + this.currentVideo = 0; + }; + return CinematicPlaylist; +}()); +//# sourceMappingURL=cinematic.js.map \ No newline at end of file diff --git a/dist/cinematic.js.map b/dist/cinematic.js.map new file mode 100644 index 0000000..9e32afc --- /dev/null +++ b/dist/cinematic.js.map @@ -0,0 +1 @@ +{"version":3,"file":"cinematic.js","sourceRoot":"","sources":["../lib/cinematic.ts"],"names":[],"mappings":"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","sourcesContent":["interface Document {\n webkitExitFullscreen: any;\n webkitFullscreenElement: any;\n webkitFullscreenEnabled: any;\n pictureInPictureElement: any;\n exitPictureInPicture: () => Promise;\n}\n\ninterface HTMLVideoElement {\n webkitEnterFullscreen: any;\n webkitSupportsFullscreen: any;\n requestPictureInPicture: () => Promise;\n}\n\ninterface Options {\n selector: string;\n baseUri: string;\n autoplay: boolean;\n startTime: number;\n deeplink: string;\n deeplinkCallback?: Function\n rememberVolume: boolean;\n rememberQuality: boolean;\n quality: string;\n sources: VideoQuality[];\n video: CinematicVideo | null;\n playlist: CinematicPlaylist | null;\n closeCallback?: CloseCallback;\n translations: Translations;\n}\n\ninterface VideoOptions {\n poster: string;\n titleIcon: string;\n title: string;\n description: string;\n subtitles: string;\n sources: VideoQuality[];\n}\n\ninterface CloseCallback {\n (): void;\n}\n\ninterface VideoQuality {\n quality: string;\n sources: VideoSource[];\n}\n\ninterface VideoSource {\n type: string;\n source: string;\n}\n\ninterface Translations {\n pause: string;\n play: string;\n restart: string;\n mute: string;\n unmute: string;\n settings: string;\n quality: string;\n playbackSpeed: string;\n fullscreen: string;\n deeplink: string;\n close: string;\n deeplinkCopied: string;\n exitFullscreen: string;\n showSubtitles: string;\n hideSubtitles: string;\n pictureInPicture: string;\n chromecast: string;\n showVideoInfo: string;\n hideVideoInfo: string;\n}\n\nclass Cinematic {\n\n options: Options;\n\n defaults: Options = {\n selector: '',\n baseUri: '../dist',\n autoplay: false,\n startTime: 0,\n deeplink: '',\n rememberVolume: false,\n rememberQuality: false,\n quality: '720p',\n sources: [],\n video: null,\n playlist: null,\n translations: {\n pause: 'Pause',\n play: 'Play',\n restart: 'Restart',\n mute: 'Mute',\n unmute: 'Unmute',\n settings: 'Settings',\n quality: 'Quality',\n playbackSpeed: 'Speed',\n fullscreen: 'Fullscreen',\n close: 'Close',\n deeplink: 'Copy deeplink to clipboard',\n deeplinkCopied: 'Link was copied',\n exitFullscreen: 'Exit Fullscreen',\n showSubtitles: 'Show Subtitles',\n hideSubtitles: 'Hide Subtitles',\n pictureInPicture: 'Picture in picture',\n chromecast: 'Stream',\n showVideoInfo: 'Show video information',\n hideVideoInfo: 'Hide video information'\n }\n };\n\n _container: any;\n _video: HTMLVideoElement;\n _sources: Map = new Map();\n _cues: HTMLElement;\n _cuesContainer: HTMLElement;\n _uiWrapper: HTMLDivElement;\n _videoTitleIcon: HTMLImageElement;\n _videoTitle: HTMLDivElement;\n _videoInfoButton: HTMLDivElement;\n _videoDescription: HTMLDivElement;\n _controls: HTMLElement;\n _playButton: HTMLDivElement;\n _bufferBar: HTMLProgressElement;\n _progressBar: HTMLProgressElement;\n _timer: HTMLElement;\n _volumeSlider: HTMLInputElement;\n _volumeButton: HTMLDivElement;\n _settingsWrapper: HTMLDivElement;\n _settingsButton: HTMLDivElement;\n _qualitySelect: HTMLSelectElement;\n _qualitySettingsSection: HTMLDivElement;\n _captionsButton: HTMLDivElement;\n _deeplinkButton: HTMLDivElement;\n _pipButton: HTMLDivElement;\n _chromecastButton: HTMLDivElement;\n _fullScreenButton: HTMLDivElement;\n _closeButton: HTMLDivElement;\n _overlayWrapper: HTMLDivElement;\n _overlayIcon: HTMLDivElement;\n _overlayText: HTMLDivElement;\n\n totalSeconds = 0;\n playedSeconds = 0;\n volume = 0;\n quality = '';\n speed = 1;\n tracks: TextTrack | null;\n _isChangingQuality = false;\n _playButtonKeyboardActivated = false;\n cues: TextTrackCueList | null;\n playlist: CinematicPlaylist;\n\n captionsEnabled = false;\n fullScreenEnabled = false;\n pipEnabled = false;\n userActive = false;\n userActiveCheck: number;\n userInactiveTimeout: number;\n overlayHideTimeout: number;\n doubleClickTimeout: number;\n\n constructor(options: Options) {\n this.options = {...this.defaults, ...options};\n\n const _passedContainer = document.querySelector(this.options.selector);\n if (!_passedContainer) {\n throw new Error('CinematicJS: Passed selector does not point to a DOM element.');\n }\n this._container = _passedContainer;\n\n if (this.options.playlist) {\n this.playlist = this.options.playlist;\n } else if (this.options.video) {\n this.playlist = new CinematicPlaylist(false, [this.options.video]);\n } else {\n throw new Error('CinematicJS: Either a single `video` or a `playlist` has to be passed as options.');\n }\n\n this.filterPlayableSources();\n\n this.quality = this.options.quality;\n if (this.options.rememberQuality) {\n const storedQuality = this.readFromLocalStore('quality');\n if (storedQuality) {\n this.quality = this.handleVideoQualityFallback(storedQuality);\n }\n }\n\n if ('pictureInPictureEnabled' in document) {\n this.pipEnabled = true;\n }\n\n this.loadIcons();\n this.renderPlayer();\n this.updateDisplayedVideoInfo();\n this.setupEvents();\n\n this._video.load();\n\n if (this.options.rememberVolume) {\n const storedVolume = this.readFromLocalStore('volume');\n if (storedVolume) {\n this._video.volume = Number.parseFloat(storedVolume);\n }\n const storedMuteState = this.readFromLocalStore('muted');\n if (storedMuteState) {\n this._video.muted = storedMuteState === 'true';\n }\n }\n\n this._container.cinematic = this as Cinematic;\n }\n\n filterPlayableSources() {\n const _video = document.createElement('video');\n for (const video of this.playlist.videos) {\n // Only keep qualities with at least one playable source\n video.sources = video.sources.filter(source => {\n // Only keep sources that may be playable by the browser\n source.sources = source.sources.filter(source => {\n return _video.canPlayType(source.type) !== '';\n });\n return source.sources.length > 0;\n });\n }\n }\n\n loadIcons() {\n const _iconContainer = document.createElement('span');\n _iconContainer.classList.add('cinematicjs-icon-container');\n document.body.appendChild(_iconContainer);\n\n const request = new XMLHttpRequest();\n request.open(\"GET\", this.options.baseUri + '/icons.svg', true);\n request.responseType = \"document\";\n request.onload = () => {\n const svg = request?.responseXML?.documentElement;\n // Don't render anything that is not an SVG, e.g. an HTML error page\n if (svg?.nodeName === 'svg') {\n _iconContainer.appendChild(svg);\n }\n }\n request.send();\n }\n\n renderPlayer() {\n this._container.classList.add('cinematicjs-video-container');\n this._container.role = 'region';\n this._container.ariaLabel = 'Video player';\n\n let initialVideo = this.playlist.getCurrentVideo();\n\n this._video = document.createElement('video');\n this._video.preload = 'metadata';\n this._video.tabIndex = 0;\n this._video.playsInline = true;\n this._video.ariaLabel = 'Video player';\n // Suppress the unwanted right-click context menu of the video element itself\n this._video.oncontextmenu = () => false;\n if (this.options.autoplay) {\n this._video.autoplay = true;\n }\n this._container.appendChild(this._video);\n\n let startSource = initialVideo.getSourcesForQuality(this.quality);\n\n if (!startSource) {\n throw new Error('CinematicJS: Passed quality does not match any of the passed sources.');\n }\n\n this.updateVideoSourceElements(startSource.sources);\n\n this._overlayWrapper = document.createElement('div');\n this._overlayWrapper.classList.add('cinematicjs-video-overlay-wrapper', 'cinematicjs-hidden');\n this._container.appendChild(this._overlayWrapper);\n\n const _overlayContainer = document.createElement('div');\n _overlayContainer.classList.add('cinematicjs-video-overlay-container');\n this._overlayWrapper.appendChild(_overlayContainer);\n\n this._overlayIcon = document.createElement('div');\n this._overlayIcon.classList.add('cinematicjs-video-overlay-icon');\n Cinematic.renderButtonIcon(this._overlayIcon, 'mute');\n _overlayContainer.appendChild(this._overlayIcon);\n\n this._overlayText = document.createElement('div');\n this._overlayText.classList.add('cinematicjs-video-overlay-text');\n _overlayContainer.appendChild(this._overlayText);\n\n this._uiWrapper = document.createElement('div');\n this._uiWrapper.classList.add('cinematicjs-ui-wrapper');\n this._container.appendChild(this._uiWrapper);\n\n const _header = document.createElement('div');\n _header.classList.add('cinematicjs-video-header');\n this._uiWrapper.appendChild(_header);\n\n this._videoTitleIcon = document.createElement('img');\n this._videoTitleIcon.classList.add('cinematicjs-video-icon');\n _header.appendChild(this._videoTitleIcon);\n\n this._videoTitle = document.createElement('div');\n this._videoTitle.classList.add('cinematicjs-video-title');\n this._videoTitle.addEventListener('click', () => this.handleVideoInfoToggle());\n _header.appendChild(this._videoTitle);\n\n this._videoInfoButton = document.createElement('div');\n this._videoInfoButton.classList.add('cinematicjs-video-info-button');\n this._videoInfoButton.role = 'button';\n this._videoInfoButton.tabIndex = 0;\n this._videoInfoButton.ariaLabel = this.options.translations.showVideoInfo;\n this._videoInfoButton.ariaExpanded = 'false';\n this._videoInfoButton.title = this.options.translations.showVideoInfo;\n Cinematic.renderButtonIcon(this._videoInfoButton, 'info');\n _header.appendChild(this._videoInfoButton);\n\n const _headerSpacer = document.createElement('div');\n _headerSpacer.classList.add('cinematicjs-video-header-spacer');\n _header.appendChild(_headerSpacer);\n\n this._chromecastButton = document.createElement('div');\n this._chromecastButton.classList.add('cinematicjs-video-control-button', 'cinematicjs-hidden');\n this._chromecastButton.role = 'button';\n this._chromecastButton.tabIndex = 0;\n this._chromecastButton.ariaLabel = this.options.translations.chromecast;\n this._chromecastButton.title = this.options.translations.chromecast;\n Cinematic.renderButtonIcon(this._chromecastButton, 'chromecast');\n _header.appendChild(this._chromecastButton);\n\n if (this._video.remote) {\n this._video.remote.watchAvailability((available) => {\n this._chromecastButton.classList.toggle('cinematicjs-hidden', !available);\n }).catch(() => {\n this._chromecastButton.classList.add('cinematicjs-hidden');\n });\n }\n\n if (this.options.closeCallback) {\n this._closeButton = document.createElement('div');\n this._closeButton.classList.add('cinematicjs-video-close-button');\n this._closeButton.role = 'button';\n this._closeButton.tabIndex = 0;\n this._closeButton.ariaLabel = this.options.translations.close;\n this._closeButton.title = this.options.translations.close;\n Cinematic.renderButtonIcon(this._closeButton, 'close');\n _header.appendChild(this._closeButton);\n }\n\n this._videoDescription = document.createElement('div');\n this._videoDescription.classList.add('cinematicjs-video-description', 'cinematicjs-hidden');\n this._uiWrapper.appendChild(this._videoDescription);\n\n const _footer = document.createElement('div');\n _footer.classList.add('cinematicjs-video-footer');\n this._uiWrapper.appendChild(_footer);\n\n const _progressWrapper = document.createElement('div');\n _progressWrapper.classList.add('cinematicjs-video-progress-wrapper');\n _footer.appendChild(_progressWrapper);\n\n this._bufferBar = document.createElement('progress');\n this._bufferBar.classList.add('cinematicjs-video-buffer-bar');\n this._bufferBar.value = 0;\n _progressWrapper.appendChild(this._bufferBar);\n\n this._progressBar = document.createElement('progress');\n this._progressBar.classList.add('cinematicjs-video-progress-bar');\n this._progressBar.role = 'slider';\n this._progressBar.tabIndex = 0;\n this._progressBar.ariaLabel = 'Video progress';\n this._progressBar.ariaValueMin = '0';\n this._progressBar.ariaValueMax = '100';\n this._progressBar.ariaValueNow = '0';\n this._progressBar.value = 0;\n _progressWrapper.appendChild(this._progressBar);\n\n this._controls = document.createElement('div');\n this._controls.classList.add('cinematicjs-video-controls');\n _footer.appendChild(this._controls);\n\n this._playButton = document.createElement('div');\n this._playButton.classList.add('cinematicjs-video-control-button');\n this._playButton.role = 'button';\n this._playButton.tabIndex = 0;\n this._playButton.ariaLabel = this.options.translations.play;\n Cinematic.renderButtonIcon(this._playButton, 'play');\n this._controls.appendChild(this._playButton);\n\n this._timer = document.createElement('span');\n this._timer.classList.add('cinematicjs-video-control-timer');\n this._timer.textContent = '00:00:00 / 00:00:00';\n this._controls.appendChild(this._timer);\n\n const _spacer = document.createElement('div');\n _spacer.classList.add('video-control-spacer');\n this._controls.appendChild(_spacer);\n\n const _volumeWrapper = document.createElement('div');\n _volumeWrapper.classList.add('cinematicjs-video-volume-wrapper');\n this._controls.appendChild(_volumeWrapper);\n\n this._volumeSlider = document.createElement('input');\n this._volumeSlider.type = 'range';\n this._volumeSlider.min = '0';\n this._volumeSlider.max = '1';\n this._volumeSlider.step = '0.05';\n this._volumeSlider.value = '1';\n this._volumeSlider.ariaLabel = 'Volume';\n this._volumeSlider.classList.add('cinematicjs-video-volume-slider');\n _volumeWrapper.appendChild(this._volumeSlider);\n\n this._volumeButton = document.createElement('div');\n this._volumeButton.classList.add('cinematicjs-video-control-button');\n this._volumeButton.role = 'button';\n this._volumeButton.tabIndex = 0;\n this._volumeButton.ariaLabel = this.options.translations.mute;\n this._volumeButton.title = this.options.translations.mute;\n Cinematic.renderButtonIcon(this._volumeButton, 'sound');\n _volumeWrapper.appendChild(this._volumeButton);\n\n this._settingsWrapper = document.createElement('div');\n this._settingsWrapper.classList.add('cinematicjs-video-control-dropdown');\n this._controls.appendChild(this._settingsWrapper);\n\n this._settingsButton = document.createElement('div');\n this._settingsButton.classList.add('cinematicjs-video-control-button');\n this._settingsButton.role = 'button';\n this._settingsButton.tabIndex = 0;\n this._settingsButton.ariaLabel = this.options.translations.mute;\n this._settingsButton.ariaExpanded = 'false';\n this._settingsButton.title = this.options.translations.settings;\n Cinematic.renderButtonIcon(this._settingsButton, 'settings');\n this._settingsWrapper.appendChild(this._settingsButton);\n\n globalThis.addEventListener('click', (event) => {\n // Clicks inside the Dropdown should not close it again.\n if (!(event.target instanceof Element) || !(event.target).matches('.cinematicjs-video-control-dropdown, .cinematicjs-video-control-dropdown *')) {\n this._settingsWrapper.classList.remove('cinematicjs-dropdown-active');\n this._settingsButton.ariaExpanded = 'false';\n }\n });\n\n const _dropDownContent = document.createElement('div');\n _dropDownContent.classList.add('cinematicjs-video-dropdown-content');\n this._settingsWrapper.appendChild(_dropDownContent);\n\n // Adds keyboard support for closing the dropdown with Escape\n _dropDownContent.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n this._settingsWrapper.classList.remove('cinematicjs-dropdown-active');\n this._settingsWrapper.ariaExpanded = 'false';\n this._settingsButton.focus();\n }\n });\n\n // Close dropdown when focus moves outside of it\n _dropDownContent.addEventListener('focusout', (event: FocusEvent) => {\n // Use setTimeout to allow the browser to update document.activeElement\n setTimeout(() => {\n const activeElement = document.activeElement;\n // Check if the new focus target is outside the dropdown\n if (activeElement && !this._settingsWrapper.contains(activeElement)) {\n this._settingsWrapper.classList.remove('cinematicjs-dropdown-active');\n this._settingsButton.ariaExpanded = 'false';\n }\n }, 0);\n });\n\n this._qualitySettingsSection = document.createElement('div');\n this._qualitySettingsSection.classList.add('cinematicjs-video-dropdown-section');\n _dropDownContent.appendChild(this._qualitySettingsSection);\n\n const _qualitySettingsTitle = document.createElement('span');\n _qualitySettingsTitle.textContent = this.options.translations.quality;\n this._qualitySettingsSection.appendChild(_qualitySettingsTitle);\n\n this._qualitySelect = document.createElement('select');\n this._qualitySelect.name = 'quality';\n this._qualitySelect.ariaLabel = this.options.translations.quality;\n this._qualitySelect.tabIndex = 0;\n this._qualitySelect.addEventListener('change', () => {\n this.handleQualityChange(this._qualitySelect.value);\n // Return focus to quality select after change\n setTimeout(() => {\n this._qualitySelect.focus();\n }, 100);\n });\n\n // Track mouse interactions to prevent focus styles on click\n let isMouseDown = false;\n this._qualitySelect.addEventListener('mousedown', () => {\n isMouseDown = true;\n this._qualitySelect.classList.add('mouse-focus');\n });\n this._qualitySelect.addEventListener('focus', () => {\n if (!isMouseDown) {\n this._qualitySelect.classList.remove('mouse-focus');\n }\n isMouseDown = false;\n });\n this._qualitySelect.addEventListener('blur', () => {\n this._qualitySelect.classList.remove('mouse-focus');\n });\n\n this.renderQualityOptions();\n\n this._qualitySettingsSection.appendChild(this._qualitySelect);\n\n const _speedSettingsSection = document.createElement('div');\n _speedSettingsSection.classList.add('cinematicjs-video-dropdown-section');\n _dropDownContent.appendChild(_speedSettingsSection);\n\n const _speedSettingsTitle = document.createElement('span');\n _speedSettingsTitle.textContent = this.options.translations.playbackSpeed;\n _speedSettingsSection.appendChild(_speedSettingsTitle);\n\n const _speedSelect = document.createElement('select');\n _speedSelect.name = 'speed';\n _speedSelect.ariaLabel = this.options.translations.playbackSpeed\n _speedSelect.tabIndex = 0;\n _speedSelect.addEventListener('change', () => {\n this.handleSpeedChange(_speedSelect.value);\n // Return focus to speed select after change\n setTimeout(() => {\n _speedSelect.focus();\n }, 100);\n });\n\n // Track mouse interactions to prevent focus styles on click\n let speedMouseDown = false;\n _speedSelect.addEventListener('mousedown', () => {\n speedMouseDown = true;\n _speedSelect.classList.add('mouse-focus');\n });\n _speedSelect.addEventListener('focus', () => {\n if (!speedMouseDown) {\n _speedSelect.classList.remove('mouse-focus');\n }\n speedMouseDown = false;\n });\n _speedSelect.addEventListener('blur', () => {\n _speedSelect.classList.remove('mouse-focus');\n });\n\n for (const speedSetting of [0.5, 1, 1.25, 1.5, 1.75, 2]) {\n const _option = document.createElement('option');\n _option.textContent = speedSetting + 'x';\n _option.value = speedSetting + '';\n _speedSelect.appendChild(_option);\n }\n\n _speedSelect.value = '1';\n _speedSettingsSection.appendChild(_speedSelect);\n\n if (this.options.deeplink) {\n this._deeplinkButton = document.createElement('div');\n this._deeplinkButton.classList.add('cinematicjs-video-control-button');\n this._deeplinkButton.role = 'button';\n this._deeplinkButton.tabIndex = 0;\n this._deeplinkButton.ariaLabel = this.options.translations.deeplink;\n this._deeplinkButton.title = this.options.translations.deeplink;\n this._deeplinkButton.dataset.copiedText = this.options.translations.deeplinkCopied;\n Cinematic.renderButtonIcon(this._deeplinkButton, 'deeplink');\n this._controls.appendChild(this._deeplinkButton);\n }\n\n this._cuesContainer = document.createElement('div');\n this._cuesContainer.classList.add('cinematicjs-video-cues-container', 'cinematicjs-hidden');\n this._container.appendChild(this._cuesContainer);\n\n this._cues = document.createElement('div');\n this._cues.classList.add('video-cues', 'cinematicjs-hidden');\n this._cuesContainer.appendChild(this._cues);\n\n this._captionsButton = document.createElement('div');\n this._captionsButton.classList.add('cinematicjs-video-control-button');\n this._captionsButton.role = 'button';\n this._captionsButton.tabIndex = 0;\n this._captionsButton.ariaLabel = this.options.translations.showSubtitles;\n this._captionsButton.ariaPressed = 'false';\n this._captionsButton.title = this.options.translations.showSubtitles;\n Cinematic.renderButtonIcon(this._captionsButton, 'expanded-cc');\n this._controls.appendChild(this._captionsButton);\n\n this.prepareSubtitles();\n\n if (this.pipEnabled) {\n this._pipButton = document.createElement('div');\n this._pipButton.classList.add('cinematicjs-video-control-button');\n this._pipButton.role = 'button';\n this._pipButton.tabIndex = 0;\n this._pipButton.ariaLabel = this.options.translations.pictureInPicture;\n this._pipButton.title = this.options.translations.pictureInPicture;\n Cinematic.renderButtonIcon(this._pipButton, 'inpicture');\n this._controls.appendChild(this._pipButton);\n }\n\n this._fullScreenButton = document.createElement('div');\n this._fullScreenButton.classList.add('cinematicjs-video-control-button', 'cinematicjs-hidden');\n this._fullScreenButton.role = 'button';\n this._fullScreenButton.tabIndex = 0;\n this._fullScreenButton.ariaLabel = this.options.translations.fullscreen;\n this._fullScreenButton.title = this.options.translations.fullscreen;\n Cinematic.renderButtonIcon(this._fullScreenButton, 'fullscreen');\n this._controls.appendChild(this._fullScreenButton);\n }\n\n private updateVideoSourceElements(sources: VideoSource[]) {\n let _previousSource: HTMLSourceElement | null = null;\n for (const source of sources) {\n let _source = this._sources.get(source.type);\n if (_source) {\n // Update the existing source element\n _source.src = source.source;\n _previousSource = _source;\n return;\n }\n\n // Create a new source element.\n _source = document.createElement('source');\n _source.src = source.source;\n _source.type = source.type;\n this._sources.set(source.type, _source);\n\n if (_previousSource) {\n // Insert the new source element after the previous one.\n _previousSource.insertAdjacentElement('afterend', _source);\n } else {\n // Insert the first source element at the beginning of the video element.\n this._video.insertBefore(_source, this._video.firstChild);\n }\n\n _previousSource = _source;\n }\n\n // Remove all source elements that are not contained in the new sources array.\n this._sources.forEach((_source, type) => {\n if (!sources.some(source => source.type === type)) {\n _source.remove();\n this._sources.delete(type);\n }\n });\n }\n\n private renderQualityOptions() {\n this._qualitySelect.textContent = '';\n\n if (this.playlist.getCurrentVideo().sources.length > 1) {\n for (const source of this.playlist.getCurrentVideo().sources) {\n const _option = document.createElement('option');\n _option.textContent = source.quality;\n _option.value = source.quality;\n this._qualitySelect.appendChild(_option);\n }\n\n this._qualitySelect.value = this.quality;\n this._qualitySettingsSection.classList.remove('cinematicjs-hidden');\n } else {\n this._qualitySettingsSection.classList.add('cinematicjs-hidden');\n }\n }\n\n /**\n * Falls back to the best available quality for the current video when it does not provide the given quality.\n *\n * @param newQuality the preferred quality to play\n * @private\n */\n private handleVideoQualityFallback(newQuality: string) {\n if (!newQuality) {\n return newQuality;\n }\n\n let currentVideo = this.playlist.getCurrentVideo();\n let newSource = currentVideo.getSourcesForQuality(newQuality);\n if (!newSource) {\n newQuality = currentVideo.getBestAvailableQuality();\n }\n\n return newQuality;\n }\n\n private handleQualityChange(newQuality: string) {\n if (!newQuality) {\n return;\n }\n\n newQuality = this.handleVideoQualityFallback(newQuality);\n let newSource = this.playlist.getCurrentVideo().getSourcesForQuality(newQuality);\n if (!newSource) {\n return;\n }\n\n if (this.options.rememberQuality) {\n this.writeToLocalStore('quality', newQuality);\n }\n\n const currentTime = this._video.currentTime;\n const wasPlaying = !this._video.paused;\n\n // Set flag to prevent focus changes during quality change\n this._isChangingQuality = true;\n\n this.updateVideoSourceElements(newSource.sources);\n\n this._video.load();\n this._video.currentTime = currentTime;\n this._video.playbackRate = this.speed;\n if (wasPlaying) {\n this._video.play();\n }\n this.quality = newQuality;\n\n // Reset flag after quality change completes\n setTimeout(() => {\n this._isChangingQuality = false;\n }, 200);\n }\n\n private handleSpeedChange(newSpeed: string | number) {\n if (!newSpeed) {\n return;\n }\n this.speed = typeof newSpeed === 'string' ? Number.parseFloat(newSpeed) : newSpeed;\n this._video.playbackRate = this.speed;\n }\n\n private handleVideoInfoToggle() {\n this._videoDescription.classList.toggle('cinematicjs-hidden');\n const isHidden = this._videoDescription.classList.contains('cinematicjs-hidden');\n if (isHidden) {\n this._videoInfoButton.title = this.options.translations.showVideoInfo;\n this._videoInfoButton.ariaLabel = this.options.translations.showVideoInfo;\n this._videoInfoButton.ariaExpanded = 'false';\n } else {\n this._videoInfoButton.title = this.options.translations.hideVideoInfo;\n this._videoInfoButton.ariaLabel = this.options.translations.hideVideoInfo;\n this._videoInfoButton.ariaExpanded = 'true';\n }\n }\n\n private prepareSubtitles() {\n let _oldTrack = this._video.querySelector('track');\n if (_oldTrack) {\n _oldTrack.remove();\n this._captionsButton.classList.add('cinematicjs-hidden');\n }\n\n let video = this.playlist.getCurrentVideo();\n if (!video.subtitles) {\n this._cues.classList.add('cinematicjs-hidden');\n this._captionsButton.classList.add('cinematicjs-hidden');\n this.tracks = null;\n this.cues = null;\n return;\n }\n\n const _subtitles = document.createElement('track');\n _subtitles.label = 'subtitles';\n _subtitles.kind = 'subtitles';\n _subtitles.src = video.subtitles;\n _subtitles.default = true;\n this._video.appendChild(_subtitles);\n\n if (_subtitles.readyState === 2) {\n this.handleLoadedTrack();\n } else {\n _subtitles.addEventListener('load', () => this.handleLoadedTrack());\n }\n\n this._captionsButton.classList.remove('cinematicjs-hidden');\n }\n\n private handleLoadedTrack() {\n this.tracks = this._video.textTracks[0];\n this.tracks.mode = 'hidden';\n this.cues = this.tracks.cues;\n\n const me = this;\n const onCueEnter = function (this: any) {\n me._cues.textContent = this.text;\n me._cues.classList.remove('cinematicjs-hidden');\n };\n\n const onCueExit = function () {\n me._cues.textContent = '';\n me._cues.classList.add('cinematicjs-hidden');\n };\n\n if (this.cues) {\n for (let i = 0; i < this.cues.length; i++) {\n let cue = this.cues[i];\n cue.onenter = onCueEnter;\n cue.onexit = onCueExit;\n }\n }\n }\n\n setupEvents() {\n const me = this;\n\n // Helper function to add both click and keyboard support to buttons\n const addButtonHandler = (_button: HTMLElement, handler: (event?: Event) => void) => {\n _button.addEventListener('click', (event) => handler(event));\n _button.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handler(event);\n }\n });\n };\n\n window.addEventListener('resize', () => this.handlePlayerResize());\n this.handlePlayerResize();\n\n if (globalThis.ResizeObserver) {\n new ResizeObserver(() => this.handlePlayerResize()).observe(this._container);\n }\n\n addButtonHandler(this._playButton, (event) => {\n this._playButtonKeyboardActivated = event instanceof KeyboardEvent;\n if (this._video.ended) {\n this.playlist.resetToBeginning();\n this.handleVideoChange();\n } else if (this._video.paused) {\n this._video.play();\n } else {\n this._video.pause();\n }\n });\n\n addButtonHandler(this._volumeButton, () => {\n this._video.muted = !this._video.muted;\n });\n\n // Settings button handler\n addButtonHandler(this._settingsButton, (event) => {\n this._settingsWrapper.classList.toggle('cinematicjs-dropdown-active');\n const isExpanded = this._settingsWrapper.classList.contains('cinematicjs-dropdown-active');\n this._settingsButton.ariaExpanded = isExpanded.toString();\n\n // Only focus the select element when opening via keyboard, not mouse\n if (isExpanded && event instanceof KeyboardEvent) {\n setTimeout(() => {\n if (this._qualitySettingsSection.classList.contains('cinematicjs-hidden')) {\n // If quality select is hidden, focus speed select\n const speedSelect = this._settingsWrapper.querySelector('select[name=\"speed\"]') as HTMLSelectElement;\n if (speedSelect) {\n speedSelect.focus();\n }\n } else {\n this._qualitySelect.focus();\n }\n }, 0);\n }\n\n if (event) {\n event.stopPropagation();\n }\n });\n\n this._volumeSlider.addEventListener('change', () => {\n // To allow the user to change from mute to a specific volume via the slider.\n this._video.muted = false;\n this._video.volume = this.volume = Number.parseFloat(this._volumeSlider.value);\n });\n\n this._video.addEventListener('loadedmetadata', function () {\n me.totalSeconds = this.duration;\n me._progressBar.setAttribute('max', me.totalSeconds.toString());\n me._bufferBar.setAttribute('max', me.totalSeconds.toString());\n me.updateTimer();\n\n if (me.options.startTime > 0) {\n this.currentTime = me.options.startTime;\n }\n\n me.fullScreenEnabled = document.fullscreenEnabled || document.webkitFullscreenEnabled || me._video.webkitSupportsFullscreen;\n me._fullScreenButton.classList.toggle('cinematicjs-hidden', !me.fullScreenEnabled);\n });\n\n this._video.addEventListener('timeupdate', function () {\n me.playedSeconds = this.currentTime;\n me._progressBar.value = me.playedSeconds;\n\n // Update aria-valuenow for accessibility\n const percentage = me.totalSeconds > 0 ? Math.round((me.playedSeconds / me.totalSeconds) * 100) : 0;\n me._progressBar.ariaValueNow = percentage.toString();\n\n me.updateTimer();\n });\n\n this._video.addEventListener('volumechange', () => {\n if (this.options.rememberVolume) {\n this.writeToLocalStore('volume', this._video.volume.toString());\n this.writeToLocalStore('muted', String(this._video.muted));\n }\n\n if (this._video.muted) {\n // Set the volume slider to its min value to indicate the mute.\n this._volumeSlider.value = '0';\n Cinematic.switchButtonIcon(this._volumeButton, 'mute');\n this._volumeButton.title = this.options.translations.unmute;\n this._volumeButton.ariaLabel = this.options.translations.unmute;\n } else {\n this._volumeSlider.value = this._video.volume.toString();\n this._volumeButton.title = this.options.translations.mute;\n this._volumeButton.ariaLabel = this.options.translations.mute;\n if (this.volume > 0.5) {\n Cinematic.switchButtonIcon(this._volumeButton, 'sound');\n } else {\n Cinematic.switchButtonIcon(this._volumeButton, 'low');\n }\n }\n });\n\n this._video.addEventListener('play', () => {\n Cinematic.switchButtonIcon(me._playButton, 'pause');\n me._playButton.title = me.options.translations.pause;\n me._playButton.ariaLabel = me.options.translations.pause;\n\n // Don't change focus during quality changes\n if (!me._isChangingQuality) {\n // Only focus the video if the play button wasn't activated via keyboard\n if (me._playButtonKeyboardActivated) {\n // Keep focus on the play button for keyboard users\n me._playButton.focus();\n } else {\n me._video.focus();\n }\n }\n me._playButtonKeyboardActivated = false;\n\n // Shows the timer even when the video container is invisible during initialization of the player\n this.handlePlayerResize();\n });\n\n this._video.addEventListener('pause', () => {\n Cinematic.switchButtonIcon(me._playButton, 'play');\n me._playButton.title = me.options.translations.play;\n me._playButton.ariaLabel = me.options.translations.play;\n\n // Return focus to the play button if it was keyboard activated\n if (me._playButtonKeyboardActivated) {\n me._playButton.focus();\n }\n me._playButtonKeyboardActivated = false;\n });\n\n this._video.addEventListener('ended', () => {\n if (this.playlist.shouldPlayNextVideo()) {\n this.playlist.startNextVideo();\n this.handleVideoChange();\n } else {\n Cinematic.switchButtonIcon(this._playButton, 'repeat');\n this._playButton.title = me.options.translations.restart;\n this._playButton.ariaLabel = me.options.translations.restart;\n this.showControls();\n }\n });\n\n this._video.addEventListener('progress', function () {\n if (this.duration > 0) {\n for (let i = 0; i < this.buffered.length; i++) {\n const bufferRangeIndex = this.buffered.length - 1 - i;\n const bufferStart = this.buffered.start(bufferRangeIndex);\n const bufferEnd = this.buffered.end(bufferRangeIndex);\n if (bufferStart <= this.currentTime) {\n me._bufferBar.value = (bufferEnd / this.duration) * 100;\n break;\n }\n }\n }\n });\n\n this._video.addEventListener('click', () => {\n globalThis.setTimeout(() => {\n if (this._video.ended) {\n this.playlist.resetToBeginning();\n this.handleVideoChange();\n this.showOverlay('play', null, true);\n } else if (me._video.paused) {\n me._video.play();\n this.showOverlay('play', null, true);\n } else {\n me._video.pause();\n this.showOverlay('pause', null, true);\n }\n this.userActive = true;\n }, 300);\n });\n\n this._video.addEventListener('dblclick', (event) => {\n if (this.doubleClickTimeout) {\n clearTimeout(this.doubleClickTimeout);\n }\n\n // Get the bounding rectangle of target\n const rect = this._video.getBoundingClientRect();\n const thirds = rect.width / 3;\n\n // Mouse position\n const x = event.clientX - rect.left;\n\n if (x <= thirds) {\n this._video.currentTime -= 10;\n this.showOverlay('backwards', '- 10s', true);\n } else if (x <= thirds * 2) {\n this.toggleFullScreen();\n } else {\n this._video.currentTime += 10;\n this.showOverlay('fastforward', '+ 10s', true);\n }\n this.userActive = true;\n });\n\n this._container.addEventListener('mousemove', () => this.userActive = true);\n\n // Show controls when a video element receives focus\n this._video.addEventListener('focus', () => {\n this.userActive = true;\n this.showControls();\n });\n\n // Keep controls visible when keyboard navigating through them\n this._controls.addEventListener('focusin', () => {\n this.userActive = true;\n this.showControls();\n });\n\n this._progressBar.addEventListener('focus', () => {\n this.userActive = true;\n this.showControls();\n });\n\n this.userActiveCheck = globalThis.setInterval(() => {\n if (!this.userActive) {\n return;\n }\n\n this.userActive = false;\n\n this.showControls();\n\n clearTimeout(this.userInactiveTimeout);\n\n this.userInactiveTimeout = globalThis.setTimeout(() => {\n // Check if any control element has focus\n const _activeElement = document.activeElement;\n const hasControlFocus = _activeElement && (\n _activeElement.parentElement == this._controls ||\n _activeElement == this._progressBar ||\n _activeElement == this._volumeSlider ||\n this._controls.contains(_activeElement as Node)\n );\n\n // We don't want to hide the controls when:\n // - The settings popup is currently open/visible\n // - Any control element has keyboard focus\n if (!this.userActive && !this._settingsWrapper.classList.contains('cinematicjs-dropdown-active') && !hasControlFocus) {\n this.hideControls();\n\n if (_activeElement && _activeElement.parentElement == this._controls) {\n // We put focus on the video element so hotkeys work again after a control bar button is pressed\n // and the user is inactive again.\n this._video.focus();\n }\n }\n }, 2000);\n\n\n }, 250);\n\n this._progressBar.addEventListener('click', function (event) {\n const _target = event.target as HTMLElement;\n const rect = _target.getBoundingClientRect();\n const pos = (event.clientX - rect.left) / this.offsetWidth;\n me._video.currentTime = pos * me._video.duration;\n });\n\n addButtonHandler(this._fullScreenButton, () => me.toggleFullScreen());\n\n document.addEventListener('fullscreenchange', () => this.handleFullScreenChange());\n document.addEventListener('webkitfullscreenchange', () => this.handleFullScreenChange());\n\n if (this.options.deeplink) {\n addButtonHandler(this._deeplinkButton, () => {\n if (!this.options.deeplinkCallback || this.options.deeplinkCallback.call(this)) {\n me.copyToClipboard(me.options.deeplink, me._deeplinkButton);\n }\n });\n }\n\n addButtonHandler(this._captionsButton, () => {\n me._cuesContainer.classList.toggle('cinematicjs-hidden');\n if (me.captionsEnabled) {\n me._captionsButton.title = me.options.translations.showSubtitles;\n me._captionsButton.ariaLabel = me.options.translations.showSubtitles;\n me._captionsButton.ariaPressed = 'false';\n Cinematic.switchButtonIcon(me._captionsButton, 'expanded-cc');\n } else {\n me._captionsButton.title = me.options.translations.hideSubtitles;\n me._captionsButton.ariaLabel = me.options.translations.hideSubtitles;\n me._captionsButton.ariaPressed = 'true';\n Cinematic.switchButtonIcon(me._captionsButton, 'cc');\n }\n me.captionsEnabled = !me.captionsEnabled;\n });\n\n if (this.pipEnabled) {\n addButtonHandler(this._pipButton, async () => {\n try {\n if (this._video === document.pictureInPictureElement) {\n await document.exitPictureInPicture();\n } else {\n await this._video.requestPictureInPicture();\n }\n } catch (error) {\n console.error(error)\n }\n });\n }\n\n if (this.options.closeCallback) {\n addButtonHandler(this._closeButton, () => {\n if (this.isFullScreen()) {\n this.toggleFullScreen();\n }\n this.options.closeCallback?.apply(this);\n });\n }\n\n // Add keyboard handler for video info button\n addButtonHandler(this._videoInfoButton, () => this.handleVideoInfoToggle());\n\n // Add keyboard handler for chromecast button\n addButtonHandler(this._chromecastButton, () => {\n if (this._video.remote) {\n this._video.remote.prompt();\n }\n });\n\n this._video.addEventListener('keydown', event => {\n const {key} = event;\n\n event.preventDefault();\n event.stopPropagation();\n\n switch (key) {\n // Space bar allows pausing/resume the video\n case ' ':\n case 'Spacebar':\n this.userActive = true;\n if (this._video.paused) {\n this._video.play();\n this.showOverlay('play', null, true);\n } else {\n this._video.pause();\n this.showOverlay('pause', null, true);\n }\n break;\n // Escape leaves the fullscreen when currently enabled\n case 'Escape':\n this.userActive = true;\n if (this.fullScreenEnabled && this.isFullScreen()) {\n this.toggleFullScreen();\n }\n break;\n // Left Arrow skips 10 seconds into the past\n case 'ArrowLeft':\n case 'Left':\n this.userActive = true;\n this._video.currentTime -= 10;\n this.showOverlay('backwards', '- 10s', true);\n break;\n // Right Arrow skips 10 seconds into the future\n case 'ArrowRight':\n case 'Right':\n this.userActive = true;\n this._video.currentTime += 10;\n this.showOverlay('fastforward', '+ 10s', true);\n break;\n // Down Arrow decreases the volume by 5%\n case 'ArrowDown':\n case 'Down':\n this.userActive = true;\n if (this._video.volume > 0) {\n let currentVolume = Math.round((this._video.volume + Cinematic.getEpsilon()) * 100);\n this.volume = (currentVolume - 5) / 100;\n this._video.volume = this.volume;\n if (this.volume === 0) {\n // Also switch on mute when we reach 0% volume\n this._video.muted = true;\n this.showOverlay('mute', '0 %', true);\n } else {\n this.showOverlay('low', Math.round(this.volume * 100) + ' %', true);\n }\n this._volumeSlider.value = this.volume.toString();\n }\n break;\n // Up Arrow increases the volume by 5%\n case 'ArrowUp':\n case 'Up':\n this.userActive = true;\n if (this._video.volume < 1) {\n let currentVolume = Math.round((this._video.volume + Cinematic.getEpsilon()) * 100);\n this.volume = (currentVolume + 5) / 100;\n this._video.volume = this.volume;\n // Unmute if we previously were muted\n this._video.muted = false;\n this.showOverlay('sound', Math.round(this.volume * 100) + ' %', true);\n this._volumeSlider.value = this.volume.toString();\n }\n break;\n }\n });\n\n return true;\n }\n\n private handleVideoChange() {\n this.prepareSubtitles();\n this.renderQualityOptions();\n this.handleQualityChange(this.quality);\n this.handleSpeedChange(this.speed);\n this.updateDisplayedVideoInfo();\n\n this._video.currentTime = 0;\n this._video.play();\n }\n\n private updateDisplayedVideoInfo() {\n const currentVideo = this.playlist.getCurrentVideo();\n this._video.poster = currentVideo.poster || '';\n this._videoTitleIcon.src = currentVideo.titleIcon || '';\n this._videoTitleIcon.classList.toggle('cinematicjs-hidden', this._videoTitleIcon.src.length === 0);\n this._videoTitle.textContent = currentVideo.title || '';\n this._videoTitle.classList.toggle('cinematicjs-clickable', !!currentVideo.description);\n this._videoInfoButton.classList.toggle('cinematicjs-hidden', !currentVideo.description);\n this._videoDescription.textContent = currentVideo.description || '';\n }\n\n private handlePlayerResize() {\n if (this._container.clientWidth >= 328) {\n this._timer.classList.remove('cinematicjs-hidden');\n } else {\n this._timer.classList.add('cinematicjs-hidden');\n }\n }\n\n private static renderButtonIcon(_button: HTMLDivElement, icon: string) {\n const _icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n _icon.setAttribute('viewBox', '0 0 24 24');\n const _use = document.createElementNS('http://www.w3.org/2000/svg', 'use');\n _use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-' + icon);\n _icon.appendChild(_use);\n _button.appendChild(_icon);\n }\n\n private static switchButtonIcon(_button: HTMLDivElement, newIcon: string) {\n _button.querySelector('svg use')?.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-' + newIcon);\n }\n\n private showOverlay(icon: string, text: string | null, hideAutomatically: boolean) {\n Cinematic.switchButtonIcon(this._overlayIcon, icon);\n this._overlayText.textContent = text;\n this._overlayWrapper.classList.remove('cinematicjs-hidden');\n\n clearTimeout(this.overlayHideTimeout);\n\n if (hideAutomatically) {\n this.overlayHideTimeout = globalThis.setTimeout(() => {\n this._overlayWrapper.classList.add('cinematicjs-hidden');\n }, 500);\n }\n }\n\n formatTime(seconds: number) {\n let hourComponent = Math.floor(seconds / 3600);\n let minuteComponent = Math.floor(seconds / 60 % 60);\n let secondComponent = Math.floor(seconds % 60);\n\n let timer = this.toTimerComponent(minuteComponent) + ':' + this.toTimerComponent(secondComponent);\n\n if (this.totalSeconds >= (60 * 60)) {\n // Include the hours in both timers when the video is at least an hour long\n return this.toTimerComponent(hourComponent) + ':' + timer;\n }\n\n return timer;\n }\n\n toTimerComponent(value: number) {\n return value < 10 ? '0' + value : value;\n }\n\n updateTimer() {\n this._timer.textContent = this.formatTime(this.playedSeconds) + ' / ' + this.formatTime(this.totalSeconds);\n }\n\n writeToLocalStore(name: string, value: string) {\n try {\n if (globalThis.localStorage) {\n globalThis.localStorage.setItem('cinematic-js-' + name, value);\n }\n } catch (error) {\n console.log('CinematicJS: Cannot write to local store', {name: name, value: value, error: error});\n }\n }\n\n readFromLocalStore(name: string): string | null {\n try {\n if (globalThis.localStorage) {\n return globalThis.localStorage.getItem('cinematic-js-' + name);\n }\n } catch (error) {\n console.log('CinematicJS: Cannot read from local store', {name: name, error: error});\n }\n return null;\n }\n\n toggleFullScreen() {\n if (document.fullscreenElement) {\n document.exitFullscreen();\n } else if (document.webkitFullscreenElement) {\n // Need this to support Safari\n document.webkitExitFullscreen();\n } else if (this._container.webkitRequestFullscreen) {\n // Need this to support Safari\n this._container.webkitRequestFullscreen();\n } else if (this._video.webkitEnterFullscreen) {\n // Need this to support iOS Safari\n this._video.webkitEnterFullscreen();\n } else {\n this._container.requestFullscreen();\n }\n }\n\n handleFullScreenChange() {\n if (this.isFullScreen()) {\n this._container.dataset.fullscreen = true;\n Cinematic.switchButtonIcon(this._fullScreenButton, 'closefullscreen');\n this._fullScreenButton.title = this.options.translations.exitFullscreen;\n this._fullScreenButton.ariaLabel = this.options.translations.exitFullscreen;\n } else {\n this._container.dataset.fullscreen = false;\n Cinematic.switchButtonIcon(this._fullScreenButton, 'fullscreen');\n this._fullScreenButton.title = this.options.translations.fullscreen;\n this._fullScreenButton.ariaLabel = this.options.translations.fullscreen;\n }\n }\n\n showControls() {\n this._container.classList.remove('cinematicjs-video-user-inactive');\n this._uiWrapper.classList.remove('cinematicjs-hidden');\n }\n\n hideControls() {\n if (this._video.paused) {\n return;\n }\n\n this._container.classList.add('cinematicjs-video-user-inactive');\n this._uiWrapper.classList.add('cinematicjs-hidden');\n }\n\n isFullScreen() {\n return document.fullscreenElement || document.webkitFullscreenElement;\n }\n\n copyToClipboard(text: string, _element: HTMLElement) {\n /*\n * inspired by clipboard.js v1.5.12\n * https://zenorocha.github.io/clipboard.js\n *\n * Licensed MIT © Zeno Rocha\n */\n const fakeElem = document.createElement('textarea');\n fakeElem.contentEditable = 'true';\n // Prevent zooming on iOS\n fakeElem.style.fontSize = '12pt';\n // Reset box model\n fakeElem.style.border = '0';\n fakeElem.style.padding = '0';\n fakeElem.style.margin = '0';\n // Move element out of the screen horizontally\n fakeElem.style.position = 'absolute';\n fakeElem.style[document.documentElement.getAttribute('dir') == 'rtl' ? 'right' : 'left'] = '-9999px';\n // Move element to the same position vertically\n fakeElem.style.top = (window.scrollY || document.documentElement.scrollTop) + 'px';\n fakeElem.readOnly = true;\n fakeElem.value = text;\n document.body.appendChild(fakeElem);\n fakeElem.focus();\n\n const range = document.createRange();\n range.selectNodeContents(fakeElem);\n const selection = globalThis.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n fakeElem.setSelectionRange(0, text.length);\n\n if (document.execCommand('copy') && _element !== undefined) {\n _element.classList.add('cinematicjs-copied');\n setTimeout(function () {\n _element.classList.remove('cinematicjs-copied');\n }, 2000);\n }\n fakeElem.remove();\n\n // Return focus to the button after copying\n if (_element) {\n _element.focus();\n }\n\n /* Try alternative */\n const copy = function (event: ClipboardEvent) {\n if (event.clipboardData) {\n event.clipboardData.setData('text/plain', text);\n } else if ((globalThis).clipboardData) {\n (globalThis).clipboardData.setData('Text', text);\n }\n event.preventDefault();\n }\n\n globalThis.addEventListener('copy', copy);\n document.execCommand('copy');\n globalThis.removeEventListener('copy', copy);\n }\n\n private static getEpsilon(): number {\n if (Number.EPSILON) {\n return Number.EPSILON;\n }\n let epsilon = 1;\n while ((1 + 0.5 * epsilon) !== 1) {\n epsilon *= 0.5;\n }\n return epsilon;\n }\n}\n\nclass CinematicVideo {\n poster: string;\n titleIcon: string;\n title: string;\n description: string;\n subtitles: string | null;\n sources: VideoQuality[];\n\n constructor(options: VideoOptions) {\n this.poster = options.poster;\n this.titleIcon = options.titleIcon;\n this.title = options.title;\n this.description = options.description;\n this.subtitles = options.subtitles;\n this.sources = options.sources;\n }\n\n getSourcesForQuality(quality: string): VideoQuality | null {\n if (this.sources.length === 1) {\n return this.sources[0];\n }\n for (let source of this.sources) {\n if (source.quality === quality) {\n return source;\n }\n }\n return null;\n }\n\n getBestAvailableQuality(): string {\n return this.sources[0].quality;\n }\n}\n\nclass CinematicPlaylist {\n loop: boolean;\n videos: CinematicVideo[];\n currentVideo: number;\n\n constructor(loop: boolean, videos: CinematicVideo[]) {\n this.loop = loop;\n this.videos = videos;\n this.currentVideo = 0;\n\n if (this.videos.length === 0) {\n throw new Error('CinematicJS: At least one video has to be passed.');\n }\n }\n\n getCurrentVideo(): CinematicVideo {\n return this.videos[this.currentVideo];\n }\n\n shouldPlayNextVideo(): boolean {\n return this.videos.length > 1 && (this.currentVideo + 1 < this.videos.length || this.loop);\n }\n\n startNextVideo() {\n this.currentVideo++;\n if (this.loop && this.currentVideo >= this.videos.length) {\n this.resetToBeginning();\n }\n }\n\n resetToBeginning() {\n this.currentVideo = 0;\n }\n}\n"]} \ No newline at end of file diff --git a/dist/icons.svg b/dist/icons.svg new file mode 100644 index 0000000..43b2317 --- /dev/null +++ b/dist/icons.svg @@ -0,0 +1,79 @@ + + + diff --git a/docs/index.html b/docs/index.html index 101bfee..0a963d8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,9 +1,10 @@ - - - + + +