Add theatre mode

This commit is contained in:
Chocobozzz 2018-06-11 16:49:56 +02:00
parent 54a3a12ed2
commit 054a103b28
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
10 changed files with 135 additions and 14 deletions

View File

@ -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 {

View File

@ -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) {

View File

@ -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

View File

@ -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': {}
}) })

View File

@ -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')

View File

@ -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)

View File

@ -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
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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