import { LitElement, css, html } from 'lit' import './RangeSlider.js' import './SvgIcon.js' import { formatSeconds } from '../api/utils.js' class VideoPlayer extends LitElement { static properties = { media: { type: String }, autoplay: { type: Boolean }, videoEl: { state: true }, playing: { state: true }, controls: { state: true }, ctrlTimer: { state: true }, position: { state: true }, duration: { state: true }, remain: { state: true } } constructor() { super() this.media = '' this.hostHeight = 0 this.hostWidth = 0 this.playing = false this.controls = true this.ctrlTimer = {} this.position = 0 this.duration = 0 this.remain = true this.autoplay = false this.videoEl = document.createElement('video') this.videoEl.playsInline = true this.videoEl.preload = 'metadata' } firstUpdated() { this.videoEl.addEventListener('loadeddata', () => { this.duration = this.videoEl.duration }) this.videoEl.addEventListener('timeupdate', () => { this.position = this.videoEl.currentTime }) } willUpdate(att) { if (att.has('media')) { this.videoEl.src = this.media if (this.autoplay) { this.togglePlay() this.interact() } } this.update() } togglePlay() { if (this.playing) { this.videoEl.pause() } else { this.videoEl.play() } this.playing = !this.playing } interact() { if (this.playing) { // show controls this.controls = true clearTimeout(this.ctrlTimer) // timeout this.ctrlTimer = setTimeout(() => { if (this.playing) { this.controls = false } }, 2000) } } toggleFullscreen() { const container = this.shadowRoot.querySelector('.videoContainer') if (container.webkitSupportsFullscreen) { container.webkitEnterFullscreen() return } if (document.fullscreenElement !== null) { document.exitFullscreen() container.setAttribute('data-fullscreen', false) } else { container.requestFullscreen() container.setAttribute('data-fullscreen', true) } } toggleDuration() { console.log(this.remain) this.remain = !this.remain } seek({ detail }) { if (detail) { this.interact() this.videoEl.currentTime = detail.value this.position = detail.value } } render() { return html`
${this.videoEl}
${formatSeconds(this.position)} ${ this.remain ? `-${formatSeconds(this.duration - this.position)}` : formatSeconds(this.duration)}
` } static styles = css` :host { height: 100%; width: 100%; position: relative; } video { position: absolute; display: block; inset: 0; width: 100%; height: 100%; background: black; } .controls { position: absolute; padding-inline: 0.75em; padding-block: 0.5em; left: 0; right: 0; bottom: 0; z-index: 5; transition: opacity 0.25s ease; } .time { display: flex; color: white; font-size: 0.65em; padding-inline: 0.125em; padding-block: 1em 0.5em; } .dur { margin-inline-start: auto; } mm-icon { display: block; color: white; } mm-icon.fullscreen { font-size: 1.25em; width: 1em; margin-inline-start: auto; margin-block-end: 1em; } mm-range { --track-height: 0.3em; --thumb-size: 0.8em; --track-color: #ffffff50; } .touchbox { display: flex; align-items: center; justify-content: center; position: absolute; inset: 0; opacity: 1; transition: opacity 0.25s ease; } .playPause { display: grid; align-items: center; justify-content: center; font-size: 2.25em; transition: opacity 0.25 ease; } .playPause > mm-icon { inset: 0; grid-column: 1 / span 1; grid-row: 1 / span 1; } .invisible { pointer-events: none; opacity: 0; } ` } customElements.define('mm-vplayer', VideoPlayer)