aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.scss5
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts3
-rw-r--r--client/src/assets/player/images/theater.svg13
-rw-r--r--client/src/assets/player/peertube-player.ts9
-rw-r--r--client/src/assets/player/peertube-videojs-plugin.ts30
-rw-r--r--client/src/assets/player/theater-button.ts46
-rw-r--r--client/src/assets/player/utils.ts13
-rw-r--r--client/src/sass/include/_variables.scss2
-rw-r--r--client/src/sass/player/peertube-skin.scss25
-rw-r--r--client/src/standalone/videos/embed.ts3
10 files changed, 135 insertions, 14 deletions
diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss
index d1f840937..00e776a69 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.scss
+++ b/client/src/app/videos/+video-watch/video-watch.component.scss
@@ -21,6 +21,11 @@
21 position: relative !important; 21 position: relative !important;
22 } 22 }
23 } 23 }
24
25 /deep/ .video-js.vjs-theater-enabled {
26 width: 100%;
27 height: calc(100vh - #{$header-height} - #{$theater-bottom-space});
28 }
24} 29}
25 30
26#video-not-found { 31#video-not-found {
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index 0f4f5ce89..eefa43a73 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -368,7 +368,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
368 enableHotkeys: true, 368 enableHotkeys: true,
369 peertubeLink: false, 369 peertubeLink: false,
370 poster: this.video.previewUrl, 370 poster: this.video.previewUrl,
371 startTime 371 startTime,
372 theaterMode: true
372 }) 373 })
373 374
374 if (this.videojsLocaleLoaded === false) { 375 if (this.videojsLocaleLoaded === false) {
diff --git a/client/src/assets/player/images/theater.svg b/client/src/assets/player/images/theater.svg
new file mode 100644
index 000000000..d7086c214
--- /dev/null
+++ b/client/src/assets/player/images/theater.svg
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3 <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
4 <title>theater</title>
5 <defs></defs>
6 <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
7 <g id="Artboard-4" transform="translate(-576.000000, -159.000000)" stroke="#fff" stroke-width="2">
8 <g id="33" transform="translate(576.000000, 159.000000)">
9 <rect id="Rectangle-433" x="1" y="6" width="22" height="12"></rect>
10 </g>
11 </g>
12 </g>
13</svg>
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts
index eb75091de..afc8e0881 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/assets/player/peertube-player.ts
@@ -10,6 +10,7 @@ import './settings-menu-button'
10import './webtorrent-info-button' 10import './webtorrent-info-button'
11import './peertube-videojs-plugin' 11import './peertube-videojs-plugin'
12import './peertube-load-progress-bar' 12import './peertube-load-progress-bar'
13import './theater-button'
13import { videojsUntyped } from './peertube-videojs-typings' 14import { videojsUntyped } from './peertube-videojs-typings'
14import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' 15import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
15import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' 16import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
@@ -28,6 +29,7 @@ function getVideojsOptions (options: {
28 peertubeLink: boolean, 29 peertubeLink: boolean,
29 poster: string, 30 poster: string,
30 startTime: number 31 startTime: number
32 theaterMode: boolean
31}) { 33}) {
32 const videojsOptions = { 34 const videojsOptions = {
33 controls: true, 35 controls: true,
@@ -63,6 +65,7 @@ function getVideojsOptions (options: {
63 65
64function getControlBarChildren (options: { 66function getControlBarChildren (options: {
65 peertubeLink: boolean 67 peertubeLink: boolean
68 theaterMode: boolean
66}) { 69}) {
67 const children = { 70 const children = {
68 'playToggle': {}, 71 'playToggle': {},
@@ -105,6 +108,12 @@ function getControlBarChildren (options: {
105 }) 108 })
106 } 109 }
107 110
111 if (options.theaterMode === true) {
112 Object.assign(children, {
113 'theaterButton': {}
114 })
115 }
116
108 Object.assign(children, { 117 Object.assign(children, {
109 'fullscreenToggle': {} 118 'fullscreenToggle': {}
110 }) 119 })
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts
index 47288c842..d3ae7b137 100644
--- a/client/src/assets/player/peertube-videojs-plugin.ts
+++ b/client/src/assets/player/peertube-videojs-plugin.ts
@@ -55,6 +55,7 @@ class PeerTubePlugin extends Plugin {
55 private player: any 55 private player: any
56 private currentVideoFile: VideoFile 56 private currentVideoFile: VideoFile
57 private torrent: WebTorrent.Torrent 57 private torrent: WebTorrent.Torrent
58 private fakeRenderer
58 private autoResolution = true 59 private autoResolution = true
59 private isAutoResolutionObservation = false 60 private isAutoResolutionObservation = false
60 61
@@ -123,6 +124,8 @@ class PeerTubePlugin extends Plugin {
123 124
124 // Don't need to destroy renderer, video player will be destroyed 125 // Don't need to destroy renderer, video player will be destroyed
125 this.flushVideoFile(this.currentVideoFile, false) 126 this.flushVideoFile(this.currentVideoFile, false)
127
128 this.destroyFakeRenderer()
126 } 129 }
127 130
128 getCurrentResolutionId () { 131 getCurrentResolutionId () {
@@ -185,7 +188,6 @@ class PeerTubePlugin extends Plugin {
185 console.log('Adding ' + magnetOrTorrentUrl + '.') 188 console.log('Adding ' + magnetOrTorrentUrl + '.')
186 189
187 const oldTorrent = this.torrent 190 const oldTorrent = this.torrent
188 let fakeRenderer
189 const torrentOptions = { 191 const torrentOptions = {
190 store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), { 192 store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
191 max: 100 193 max: 100
@@ -205,7 +207,7 @@ class PeerTubePlugin extends Plugin {
205 if (options.delay) { 207 if (options.delay) {
206 const fakeVideoElem = document.createElement('video') 208 const fakeVideoElem = document.createElement('video')
207 renderVideo(torrent.files[0], fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => { 209 renderVideo(torrent.files[0], fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => {
208 fakeRenderer = renderer 210 this.fakeRenderer = renderer
209 211
210 if (err) console.error('Cannot render new torrent in fake video element.', err) 212 if (err) console.error('Cannot render new torrent in fake video element.', err)
211 213
@@ -217,16 +219,7 @@ class PeerTubePlugin extends Plugin {
217 219
218 // Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution) 220 // Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution)
219 this.addTorrentDelay = setTimeout(() => { 221 this.addTorrentDelay = setTimeout(() => {
220 if (fakeRenderer) { 222 this.destroyFakeRenderer()
221 if (fakeRenderer.destroy) {
222 try {
223 fakeRenderer.destroy()
224 } catch (err) {
225 console.log('Cannot destroy correctly fake renderer.', err)
226 }
227 }
228 fakeRenderer = undefined
229 }
230 223
231 const paused = this.player.paused() 224 const paused = this.player.paused()
232 225
@@ -567,6 +560,19 @@ class PeerTubePlugin extends Plugin {
567 return this.videoFiles[Math.floor(this.videoFiles.length / 2)] 560 return this.videoFiles[Math.floor(this.videoFiles.length / 2)]
568 } 561 }
569 562
563 private destroyFakeRenderer () {
564 if (this.fakeRenderer) {
565 if (this.fakeRenderer.destroy) {
566 try {
567 this.fakeRenderer.destroy()
568 } catch (err) {
569 console.log('Cannot destroy correctly fake renderer.', err)
570 }
571 }
572 this.fakeRenderer = undefined
573 }
574 }
575
570 // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657 576 // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657
571 private initSmoothProgressBar () { 577 private initSmoothProgressBar () {
572 const SeekBar = videojsUntyped.getComponent('SeekBar') 578 const SeekBar = videojsUntyped.getComponent('SeekBar')
diff --git a/client/src/assets/player/theater-button.ts b/client/src/assets/player/theater-button.ts
new file mode 100644
index 000000000..1d330e08f
--- /dev/null
+++ b/client/src/assets/player/theater-button.ts
@@ -0,0 +1,46 @@
1import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
2import { getStoredTheater, saveTheaterInStore } from './utils'
3
4const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button')
5class TheaterButton extends Button {
6
7 private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled'
8
9 constructor (player, options) {
10 super(player, options)
11
12 const enabled = getStoredTheater()
13 if (enabled === true) {
14 this.player_.addClass(TheaterButton.THEATER_MODE_CLASS)
15 this.handleTheaterChange()
16 }
17 }
18
19 buildCSSClass () {
20 return `vjs-theater-control ${super.buildCSSClass()}`
21 }
22
23 handleTheaterChange () {
24 if (this.isTheaterEnabled()) {
25 this.controlText('Normal mode')
26 } else {
27 this.controlText('Theater mode')
28 }
29
30 saveTheaterInStore(this.isTheaterEnabled())
31 }
32
33 handleClick () {
34 this.player_.toggleClass(TheaterButton.THEATER_MODE_CLASS)
35
36 this.handleTheaterChange()
37 }
38
39 private isTheaterEnabled () {
40 return this.player_.hasClass(TheaterButton.THEATER_MODE_CLASS)
41 }
42}
43
44TheaterButton.prototype.controlText_ = 'Theater mode'
45
46TheaterButton.registerComponent('TheaterButton', TheaterButton)
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts
index 4eaf53720..b7cd40aa2 100644
--- a/client/src/assets/player/utils.ts
+++ b/client/src/assets/player/utils.ts
@@ -51,6 +51,13 @@ function getAverageBandwidth () {
51 return undefined 51 return undefined
52} 52}
53 53
54function getStoredTheater () {
55 const value = getLocalStorage('theater-enabled')
56 if (value !== null && value !== undefined) return value === 'true'
57
58 return undefined
59}
60
54function saveVolumeInStore (value: number) { 61function saveVolumeInStore (value: number) {
55 return setLocalStorage('volume', value.toString()) 62 return setLocalStorage('volume', value.toString())
56} 63}
@@ -59,6 +66,10 @@ function saveMuteInStore (value: boolean) {
59 return setLocalStorage('mute', value.toString()) 66 return setLocalStorage('mute', value.toString())
60} 67}
61 68
69function saveTheaterInStore (enabled: boolean) {
70 return setLocalStorage('theater-enabled', enabled.toString())
71}
72
62function saveAverageBandwidth (value: number) { 73function saveAverageBandwidth (value: number) {
63 return setLocalStorage('average-bandwidth', value.toString()) 74 return setLocalStorage('average-bandwidth', value.toString())
64} 75}
@@ -133,6 +144,8 @@ export {
133 videoFileMaxByResolution, 144 videoFileMaxByResolution,
134 videoFileMinByResolution, 145 videoFileMinByResolution,
135 copyToClipboard, 146 copyToClipboard,
147 getStoredTheater,
148 saveTheaterInStore,
136 isMobile, 149 isMobile,
137 bytes 150 bytes
138} 151}
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss
index 95b4b166e..092f8ed24 100644
--- a/client/src/sass/include/_variables.scss
+++ b/client/src/sass/include/_variables.scss
@@ -31,3 +31,5 @@ $footer-border-color: $header-border-color;
31 31
32$video-thumbnail-height: 110px; 32$video-thumbnail-height: 110px;
33$video-thumbnail-width: 200px; 33$video-thumbnail-width: 200px;
34
35$theater-bottom-space: 85px;
diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/sass/player/peertube-skin.scss
index de6501962..e60a854d4 100644
--- a/client/src/sass/player/peertube-skin.scss
+++ b/client/src/sass/player/peertube-skin.scss
@@ -135,6 +135,7 @@
135 .vjs-resolution-control, 135 .vjs-resolution-control,
136 .vjs-fullscreen-control, 136 .vjs-fullscreen-control,
137 .vjs-peertube-link, 137 .vjs-peertube-link,
138 .vjs-theater-control,
138 .vjs-settings 139 .vjs-settings
139 { 140 {
140 color: $primary-foreground-color !important; 141 color: $primary-foreground-color !important;
@@ -394,6 +395,26 @@
394 padding: 0 5px; 395 padding: 0 5px;
395 } 396 }
396 397
398 .vjs-theater-control {
399 @include disable-outline;
400
401 width: 37px;
402 margin-right: 1px;
403
404 .vjs-icon-placeholder {
405 display: inline-block;
406 width: 22px;
407 height: 22px;
408 vertical-align: middle;
409 background: url('#{$assets-path}/player/images/theater.svg') no-repeat;
410 background-size: contain;
411
412 &::before {
413 content: '';
414 }
415 }
416 }
417
397 .vjs-fullscreen-control { 418 .vjs-fullscreen-control {
398 @include disable-outline; 419 @include disable-outline;
399 420
@@ -440,6 +461,10 @@
440 } 461 }
441 462
442 @media screen and (max-width: 750px) { 463 @media screen and (max-width: 750px) {
464 .vjs-theater-control {
465 display: none;
466 }
467
443 .vjs-dock-text { 468 .vjs-dock-text {
444 font-size: 16px; 469 font-size: 16px;
445 } 470 }
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index e28d964de..bf0eb484e 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -99,7 +99,8 @@ loadLocale(window.location.origin, videojs, navigator.language)
99 enableHotkeys: true, 99 enableHotkeys: true,
100 peertubeLink: true, 100 peertubeLink: true,
101 poster: window.location.origin + videoInfo.previewPath, 101 poster: window.location.origin + videoInfo.previewPath,
102 startTime 102 startTime,
103 theaterMode: false
103 }) 104 })
104 videojs(videoContainerId, videojsOptions, function () { 105 videojs(videoContainerId, videojsOptions, function () {
105 const player = this 106 const player = this