Add theatre mode
This commit is contained in:
parent
54a3a12ed2
commit
054a103b28
|
@ -21,6 +21,11 @@
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/deep/ .video-js.vjs-theater-enabled {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100vh - #{$header-height} - #{$theater-bottom-space});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#video-not-found {
|
#video-not-found {
|
||||||
|
|
|
@ -368,7 +368,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
enableHotkeys: true,
|
enableHotkeys: true,
|
||||||
peertubeLink: false,
|
peertubeLink: false,
|
||||||
poster: this.video.previewUrl,
|
poster: this.video.previewUrl,
|
||||||
startTime
|
startTime,
|
||||||
|
theaterMode: true
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.videojsLocaleLoaded === false) {
|
if (this.videojsLocaleLoaded === false) {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>theater</title>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Artboard-4" transform="translate(-576.000000, -159.000000)" stroke="#fff" stroke-width="2">
|
||||||
|
<g id="33" transform="translate(576.000000, 159.000000)">
|
||||||
|
<rect id="Rectangle-433" x="1" y="6" width="22" height="12"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 702 B |
|
@ -10,6 +10,7 @@ import './settings-menu-button'
|
||||||
import './webtorrent-info-button'
|
import './webtorrent-info-button'
|
||||||
import './peertube-videojs-plugin'
|
import './peertube-videojs-plugin'
|
||||||
import './peertube-load-progress-bar'
|
import './peertube-load-progress-bar'
|
||||||
|
import './theater-button'
|
||||||
import { videojsUntyped } from './peertube-videojs-typings'
|
import { videojsUntyped } from './peertube-videojs-typings'
|
||||||
import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
|
import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
|
||||||
import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
|
import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
|
||||||
|
@ -28,6 +29,7 @@ function getVideojsOptions (options: {
|
||||||
peertubeLink: boolean,
|
peertubeLink: boolean,
|
||||||
poster: string,
|
poster: string,
|
||||||
startTime: number
|
startTime: number
|
||||||
|
theaterMode: boolean
|
||||||
}) {
|
}) {
|
||||||
const videojsOptions = {
|
const videojsOptions = {
|
||||||
controls: true,
|
controls: true,
|
||||||
|
@ -63,6 +65,7 @@ function getVideojsOptions (options: {
|
||||||
|
|
||||||
function getControlBarChildren (options: {
|
function getControlBarChildren (options: {
|
||||||
peertubeLink: boolean
|
peertubeLink: boolean
|
||||||
|
theaterMode: boolean
|
||||||
}) {
|
}) {
|
||||||
const children = {
|
const children = {
|
||||||
'playToggle': {},
|
'playToggle': {},
|
||||||
|
@ -105,6 +108,12 @@ function getControlBarChildren (options: {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.theaterMode === true) {
|
||||||
|
Object.assign(children, {
|
||||||
|
'theaterButton': {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(children, {
|
Object.assign(children, {
|
||||||
'fullscreenToggle': {}
|
'fullscreenToggle': {}
|
||||||
})
|
})
|
||||||
|
|
|
@ -55,6 +55,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
private player: any
|
private player: any
|
||||||
private currentVideoFile: VideoFile
|
private currentVideoFile: VideoFile
|
||||||
private torrent: WebTorrent.Torrent
|
private torrent: WebTorrent.Torrent
|
||||||
|
private fakeRenderer
|
||||||
private autoResolution = true
|
private autoResolution = true
|
||||||
private isAutoResolutionObservation = false
|
private isAutoResolutionObservation = false
|
||||||
|
|
||||||
|
@ -123,6 +124,8 @@ class PeerTubePlugin extends Plugin {
|
||||||
|
|
||||||
// Don't need to destroy renderer, video player will be destroyed
|
// Don't need to destroy renderer, video player will be destroyed
|
||||||
this.flushVideoFile(this.currentVideoFile, false)
|
this.flushVideoFile(this.currentVideoFile, false)
|
||||||
|
|
||||||
|
this.destroyFakeRenderer()
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentResolutionId () {
|
getCurrentResolutionId () {
|
||||||
|
@ -185,7 +188,6 @@ class PeerTubePlugin extends Plugin {
|
||||||
console.log('Adding ' + magnetOrTorrentUrl + '.')
|
console.log('Adding ' + magnetOrTorrentUrl + '.')
|
||||||
|
|
||||||
const oldTorrent = this.torrent
|
const oldTorrent = this.torrent
|
||||||
let fakeRenderer
|
|
||||||
const torrentOptions = {
|
const torrentOptions = {
|
||||||
store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
|
store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
|
||||||
max: 100
|
max: 100
|
||||||
|
@ -205,7 +207,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
if (options.delay) {
|
if (options.delay) {
|
||||||
const fakeVideoElem = document.createElement('video')
|
const fakeVideoElem = document.createElement('video')
|
||||||
renderVideo(torrent.files[0], fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => {
|
renderVideo(torrent.files[0], fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => {
|
||||||
fakeRenderer = renderer
|
this.fakeRenderer = renderer
|
||||||
|
|
||||||
if (err) console.error('Cannot render new torrent in fake video element.', err)
|
if (err) console.error('Cannot render new torrent in fake video element.', err)
|
||||||
|
|
||||||
|
@ -217,16 +219,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
|
|
||||||
// Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution)
|
// Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution)
|
||||||
this.addTorrentDelay = setTimeout(() => {
|
this.addTorrentDelay = setTimeout(() => {
|
||||||
if (fakeRenderer) {
|
this.destroyFakeRenderer()
|
||||||
if (fakeRenderer.destroy) {
|
|
||||||
try {
|
|
||||||
fakeRenderer.destroy()
|
|
||||||
} catch (err) {
|
|
||||||
console.log('Cannot destroy correctly fake renderer.', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fakeRenderer = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const paused = this.player.paused()
|
const paused = this.player.paused()
|
||||||
|
|
||||||
|
@ -567,6 +560,19 @@ class PeerTubePlugin extends Plugin {
|
||||||
return this.videoFiles[Math.floor(this.videoFiles.length / 2)]
|
return this.videoFiles[Math.floor(this.videoFiles.length / 2)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private destroyFakeRenderer () {
|
||||||
|
if (this.fakeRenderer) {
|
||||||
|
if (this.fakeRenderer.destroy) {
|
||||||
|
try {
|
||||||
|
this.fakeRenderer.destroy()
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Cannot destroy correctly fake renderer.', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.fakeRenderer = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657
|
// Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657
|
||||||
private initSmoothProgressBar () {
|
private initSmoothProgressBar () {
|
||||||
const SeekBar = videojsUntyped.getComponent('SeekBar')
|
const SeekBar = videojsUntyped.getComponent('SeekBar')
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
|
||||||
|
import { getStoredTheater, saveTheaterInStore } from './utils'
|
||||||
|
|
||||||
|
const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button')
|
||||||
|
class TheaterButton extends Button {
|
||||||
|
|
||||||
|
private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled'
|
||||||
|
|
||||||
|
constructor (player, options) {
|
||||||
|
super(player, options)
|
||||||
|
|
||||||
|
const enabled = getStoredTheater()
|
||||||
|
if (enabled === true) {
|
||||||
|
this.player_.addClass(TheaterButton.THEATER_MODE_CLASS)
|
||||||
|
this.handleTheaterChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildCSSClass () {
|
||||||
|
return `vjs-theater-control ${super.buildCSSClass()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTheaterChange () {
|
||||||
|
if (this.isTheaterEnabled()) {
|
||||||
|
this.controlText('Normal mode')
|
||||||
|
} else {
|
||||||
|
this.controlText('Theater mode')
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTheaterInStore(this.isTheaterEnabled())
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick () {
|
||||||
|
this.player_.toggleClass(TheaterButton.THEATER_MODE_CLASS)
|
||||||
|
|
||||||
|
this.handleTheaterChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
private isTheaterEnabled () {
|
||||||
|
return this.player_.hasClass(TheaterButton.THEATER_MODE_CLASS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TheaterButton.prototype.controlText_ = 'Theater mode'
|
||||||
|
|
||||||
|
TheaterButton.registerComponent('TheaterButton', TheaterButton)
|
|
@ -51,6 +51,13 @@ function getAverageBandwidth () {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStoredTheater () {
|
||||||
|
const value = getLocalStorage('theater-enabled')
|
||||||
|
if (value !== null && value !== undefined) return value === 'true'
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
function saveVolumeInStore (value: number) {
|
function saveVolumeInStore (value: number) {
|
||||||
return setLocalStorage('volume', value.toString())
|
return setLocalStorage('volume', value.toString())
|
||||||
}
|
}
|
||||||
|
@ -59,6 +66,10 @@ function saveMuteInStore (value: boolean) {
|
||||||
return setLocalStorage('mute', value.toString())
|
return setLocalStorage('mute', value.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveTheaterInStore (enabled: boolean) {
|
||||||
|
return setLocalStorage('theater-enabled', enabled.toString())
|
||||||
|
}
|
||||||
|
|
||||||
function saveAverageBandwidth (value: number) {
|
function saveAverageBandwidth (value: number) {
|
||||||
return setLocalStorage('average-bandwidth', value.toString())
|
return setLocalStorage('average-bandwidth', value.toString())
|
||||||
}
|
}
|
||||||
|
@ -133,6 +144,8 @@ export {
|
||||||
videoFileMaxByResolution,
|
videoFileMaxByResolution,
|
||||||
videoFileMinByResolution,
|
videoFileMinByResolution,
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
|
getStoredTheater,
|
||||||
|
saveTheaterInStore,
|
||||||
isMobile,
|
isMobile,
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,3 +31,5 @@ $footer-border-color: $header-border-color;
|
||||||
|
|
||||||
$video-thumbnail-height: 110px;
|
$video-thumbnail-height: 110px;
|
||||||
$video-thumbnail-width: 200px;
|
$video-thumbnail-width: 200px;
|
||||||
|
|
||||||
|
$theater-bottom-space: 85px;
|
||||||
|
|
|
@ -135,6 +135,7 @@
|
||||||
.vjs-resolution-control,
|
.vjs-resolution-control,
|
||||||
.vjs-fullscreen-control,
|
.vjs-fullscreen-control,
|
||||||
.vjs-peertube-link,
|
.vjs-peertube-link,
|
||||||
|
.vjs-theater-control,
|
||||||
.vjs-settings
|
.vjs-settings
|
||||||
{
|
{
|
||||||
color: $primary-foreground-color !important;
|
color: $primary-foreground-color !important;
|
||||||
|
@ -394,6 +395,26 @@
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-theater-control {
|
||||||
|
@include disable-outline;
|
||||||
|
|
||||||
|
width: 37px;
|
||||||
|
margin-right: 1px;
|
||||||
|
|
||||||
|
.vjs-icon-placeholder {
|
||||||
|
display: inline-block;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: url('#{$assets-path}/player/images/theater.svg') no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.vjs-fullscreen-control {
|
.vjs-fullscreen-control {
|
||||||
@include disable-outline;
|
@include disable-outline;
|
||||||
|
|
||||||
|
@ -440,6 +461,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 750px) {
|
@media screen and (max-width: 750px) {
|
||||||
|
.vjs-theater-control {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.vjs-dock-text {
|
.vjs-dock-text {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,8 @@ loadLocale(window.location.origin, videojs, navigator.language)
|
||||||
enableHotkeys: true,
|
enableHotkeys: true,
|
||||||
peertubeLink: true,
|
peertubeLink: true,
|
||||||
poster: window.location.origin + videoInfo.previewPath,
|
poster: window.location.origin + videoInfo.previewPath,
|
||||||
startTime
|
startTime,
|
||||||
|
theaterMode: false
|
||||||
})
|
})
|
||||||
videojs(videoContainerId, videojsOptions, function () {
|
videojs(videoContainerId, videojsOptions, function () {
|
||||||
const player = this
|
const player = this
|
||||||
|
|
Loading…
Reference in New Issue