diff options
12 files changed, 88 insertions, 34 deletions
diff --git a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss index 0f0ac1979..2d43ffe40 100644 --- a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss +++ b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss | |||
@@ -6,6 +6,7 @@ | |||
6 | .playlist { | 6 | .playlist { |
7 | position: relative; | 7 | position: relative; |
8 | min-width: 200px; | 8 | min-width: 200px; |
9 | width: 25vw; | ||
9 | max-width: 470px; | 10 | max-width: 470px; |
10 | height: 66vh; | 11 | height: 66vh; |
11 | background-color: pvar(--mainBackgroundColor); | 12 | background-color: pvar(--mainBackgroundColor); |
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 d438facd3..e535ecb9c 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.scss +++ b/client/src/app/+videos/+video-watch/video-watch.component.scss | |||
@@ -4,15 +4,8 @@ | |||
4 | @use '_bootstrap-variables'; | 4 | @use '_bootstrap-variables'; |
5 | @use '_miniature' as *; | 5 | @use '_miniature' as *; |
6 | 6 | ||
7 | $video-height: 66vh; | 7 | $video-default-height: 66vh; |
8 | 8 | $video-theater-height: calc(100vh - #{$header-height} - #{$theater-bottom-space}); | |
9 | @function getPlayerHeight ($width) { | ||
10 | @return calc(#{$width} / #{$video-watch-player-factor}); | ||
11 | } | ||
12 | |||
13 | @function getPlayerWidth ($height) { | ||
14 | @return calc(#{$height} * #{$video-watch-player-factor}); | ||
15 | } | ||
16 | 9 | ||
17 | @mixin playlist-below-player { | 10 | @mixin playlist-below-player { |
18 | width: 100% !important; | 11 | width: 100% !important; |
@@ -38,20 +31,16 @@ $video-height: 66vh; | |||
38 | 31 | ||
39 | .root { | 32 | .root { |
40 | &.theater-enabled #video-wrapper { | 33 | &.theater-enabled #video-wrapper { |
41 | $height: calc(100vh - #{$header-height} - #{$theater-bottom-space}); | ||
42 | |||
43 | flex-direction: column; | 34 | flex-direction: column; |
44 | justify-content: center; | 35 | justify-content: center; |
45 | 36 | ||
46 | #videojs-wrapper { | 37 | #videojs-wrapper { |
47 | width: 100%; | 38 | width: 100%; |
48 | height: $height; | 39 | height: $video-theater-height; |
49 | } | 40 | } |
50 | 41 | ||
51 | ::ng-deep .video-js { | 42 | ::ng-deep .video-js { |
52 | height: $height; | 43 | --player-height: #{$video-theater-height}; |
53 | width: 100%; | ||
54 | max-width: initial; | ||
55 | } | 44 | } |
56 | 45 | ||
57 | my-video-watch-playlist ::ng-deep .playlist { | 46 | my-video-watch-playlist ::ng-deep .playlist { |
@@ -65,10 +54,24 @@ $video-height: 66vh; | |||
65 | display: flex; | 54 | display: flex; |
66 | justify-content: center; | 55 | justify-content: center; |
67 | 56 | ||
57 | #videojs-wrapper { | ||
58 | display: flex; | ||
59 | justify-content: center; | ||
60 | flex-grow: 1; | ||
61 | height: $video-default-height; | ||
62 | } | ||
63 | |||
68 | ::ng-deep .video-js { | 64 | ::ng-deep .video-js { |
65 | --player-height: #{$video-default-height}; | ||
66 | --player-portrait-mode: 0; | ||
67 | // Default player ratio, redefined by the player to automatically adapt player size | ||
68 | --player-ratio: #{math.div(16, 9)}; | ||
69 | |||
69 | width: 100%; | 70 | width: 100%; |
70 | max-width: getPlayerWidth($video-height); | 71 | height: var(--player-height); |
71 | height: $video-height; | 72 | |
73 | // Can be recalculated by the player depending on video ratio | ||
74 | max-width: calc(var(--player-height) * var(--player-ratio)); | ||
72 | 75 | ||
73 | // VideoJS create an inner video player | 76 | // VideoJS create an inner video player |
74 | video { | 77 | video { |
@@ -78,13 +81,6 @@ $video-height: 66vh; | |||
78 | } | 81 | } |
79 | } | 82 | } |
80 | 83 | ||
81 | #videojs-wrapper { | ||
82 | display: flex; | ||
83 | justify-content: center; | ||
84 | flex-grow: 1; | ||
85 | height: $video-height; | ||
86 | } | ||
87 | |||
88 | .remote-server-down { | 84 | .remote-server-down { |
89 | color: #fff; | 85 | color: #fff; |
90 | display: flex; | 86 | display: flex; |
@@ -253,12 +249,16 @@ my-video-comments { | |||
253 | 249 | ||
254 | @media screen and (max-width: 600px) { | 250 | @media screen and (max-width: 600px) { |
255 | #videojs-wrapper { | 251 | #videojs-wrapper { |
256 | height: getPlayerHeight(100vw) !important; | 252 | // Reset height |
253 | height: initial !important; | ||
257 | 254 | ||
258 | .remote-server-down, | 255 | .remote-server-down, |
259 | ::ng-deep .video-js { | 256 | ::ng-deep .video-js { |
260 | width: 100vw; | 257 | --player-portrait-mode: 1; |
261 | height: getPlayerHeight(100vw) !important; | 258 | |
259 | // Can be recalculated by the player depending on video ratio | ||
260 | height: calc(100vw / var(--player-ratio)) !important; | ||
261 | max-height: $video-theater-height; | ||
262 | } | 262 | } |
263 | } | 263 | } |
264 | 264 | ||
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 f109427cc..febb3c828 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts | |||
@@ -623,7 +623,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
623 | 623 | ||
624 | peertubeLink: () => false, | 624 | peertubeLink: () => false, |
625 | 625 | ||
626 | pluginsManager: this.pluginService.getPluginsManager() | 626 | pluginsManager: this.pluginService.getPluginsManager(), |
627 | |||
628 | autoPlayerRatio: { | ||
629 | cssRatioVariable: '--player-ratio', | ||
630 | cssPlayerPortraitModeVariable: '--player-portrait-mode' | ||
631 | } | ||
627 | } | 632 | } |
628 | } | 633 | } |
629 | 634 | ||
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts index 4da681a08..111b4645b 100644 --- a/client/src/assets/player/peertube-player.ts +++ b/client/src/assets/player/peertube-player.ts | |||
@@ -364,7 +364,9 @@ export class PeerTubePlayer { | |||
364 | videoUUID: () => this.currentLoadOptions.videoUUID, | 364 | videoUUID: () => this.currentLoadOptions.videoUUID, |
365 | subtitle: () => this.currentLoadOptions.subtitle, | 365 | subtitle: () => this.currentLoadOptions.subtitle, |
366 | 366 | ||
367 | poster: () => this.currentLoadOptions.poster | 367 | poster: () => this.currentLoadOptions.poster, |
368 | |||
369 | autoPlayerRatio: this.options.autoPlayerRatio | ||
368 | }, | 370 | }, |
369 | metrics: { | 371 | metrics: { |
370 | mode: () => this.currentLoadOptions.mode, | 372 | mode: () => this.currentLoadOptions.mode, |
diff --git a/client/src/assets/player/shared/metrics/metrics-plugin.ts b/client/src/assets/player/shared/metrics/metrics-plugin.ts index 0ad16338c..a581d7931 100644 --- a/client/src/assets/player/shared/metrics/metrics-plugin.ts +++ b/client/src/assets/player/shared/metrics/metrics-plugin.ts | |||
@@ -140,10 +140,10 @@ class MetricsPlugin extends Plugin { | |||
140 | 140 | ||
141 | private trackBytes () { | 141 | private trackBytes () { |
142 | this.player.on('network-info', (_event, data: PlayerNetworkInfo) => { | 142 | this.player.on('network-info', (_event, data: PlayerNetworkInfo) => { |
143 | this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)) | 143 | this.downloadedBytesHTTP += Math.max(Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)), 0) |
144 | this.downloadedBytesP2P += Math.round((data.p2p?.downloaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.downloaded || 0)) | 144 | this.downloadedBytesP2P += Math.max(Math.round((data.p2p?.downloaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.downloaded || 0)), 0) |
145 | 145 | ||
146 | this.uploadedBytesP2P += Math.round((data.p2p?.uploaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.uploaded || 0)) | 146 | this.uploadedBytesP2P += Math.max(Math.round((data.p2p?.uploaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.uploaded || 0)), 0) |
147 | 147 | ||
148 | this.p2pPeers = data.p2p?.peersP2POnly | 148 | this.p2pPeers = data.p2p?.peersP2POnly |
149 | this.p2pEnabled = !!data.p2p | 149 | this.p2pEnabled = !!data.p2p |
diff --git a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts index 1e47fe486..ee617ce8a 100644 --- a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts +++ b/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts | |||
@@ -119,6 +119,14 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
119 | this.runStats() | 119 | this.runStats() |
120 | 120 | ||
121 | this.hlsjs.on(Hlsjs.Events.LEVEL_SWITCHED, () => this.player.trigger('engine-resolution-change')) | 121 | this.hlsjs.on(Hlsjs.Events.LEVEL_SWITCHED, () => this.player.trigger('engine-resolution-change')) |
122 | |||
123 | this.hlsjs.on(Hlsjs.Events.MANIFEST_PARSED, (_event, data) => { | ||
124 | if (Array.isArray(data.levels) && data.levels.length > 1) { | ||
125 | const level = data.levels[0] | ||
126 | |||
127 | this.player.trigger('video-ratio-changed', { ratio: level.width / level.height }) | ||
128 | } | ||
129 | }) | ||
122 | } | 130 | } |
123 | 131 | ||
124 | private runStats () { | 132 | private runStats () { |
diff --git a/client/src/assets/player/shared/peertube/peertube-plugin.ts b/client/src/assets/player/shared/peertube/peertube-plugin.ts index cf866723c..7aeae2670 100644 --- a/client/src/assets/player/shared/peertube/peertube-plugin.ts +++ b/client/src/assets/player/shared/peertube/peertube-plugin.ts | |||
@@ -115,6 +115,8 @@ class PeerTubePlugin extends Plugin { | |||
115 | this.hideFatalError() | 115 | this.hideFatalError() |
116 | }) | 116 | }) |
117 | }) | 117 | }) |
118 | |||
119 | this.initOnRatioChange() | ||
118 | } | 120 | } |
119 | 121 | ||
120 | dispose () { | 122 | dispose () { |
@@ -210,6 +212,25 @@ class PeerTubePlugin extends Plugin { | |||
210 | this.runUserViewing() | 212 | this.runUserViewing() |
211 | } | 213 | } |
212 | 214 | ||
215 | private initOnRatioChange () { | ||
216 | if (!this.options.autoPlayerRatio) return | ||
217 | |||
218 | const defaultRatio = getComputedStyle(this.player.el()).getPropertyValue(this.options.autoPlayerRatio.cssRatioVariable) | ||
219 | |||
220 | this.player.on('video-ratio-changed', (_event, data: { ratio: number }) => { | ||
221 | const el = this.player.el() as HTMLElement | ||
222 | |||
223 | // In portrait screen mode, we allow player with bigger height size than width | ||
224 | const portraitMode = getComputedStyle(el).getPropertyValue(this.options.autoPlayerRatio.cssPlayerPortraitModeVariable) === '1' | ||
225 | |||
226 | const currentRatio = !portraitMode && data.ratio < 1 | ||
227 | ? defaultRatio | ||
228 | : data.ratio | ||
229 | |||
230 | el.style.setProperty('--player-ratio', currentRatio + '') | ||
231 | }) | ||
232 | } | ||
233 | |||
213 | // --------------------------------------------------------------------------- | 234 | // --------------------------------------------------------------------------- |
214 | 235 | ||
215 | private runUserViewing () { | 236 | private runUserViewing () { |
diff --git a/client/src/assets/player/shared/web-video/web-video-plugin.ts b/client/src/assets/player/shared/web-video/web-video-plugin.ts index 18d911108..8f4db0680 100644 --- a/client/src/assets/player/shared/web-video/web-video-plugin.ts +++ b/client/src/assets/player/shared/web-video/web-video-plugin.ts | |||
@@ -19,6 +19,7 @@ class WebVideoPlugin extends Plugin { | |||
19 | 19 | ||
20 | private onErrorHandler: () => void | 20 | private onErrorHandler: () => void |
21 | private onPlayHandler: () => void | 21 | private onPlayHandler: () => void |
22 | private onLoadedMetadata: () => void | ||
22 | 23 | ||
23 | constructor (player: videojs.Player, options?: WebVideoPluginOptions) { | 24 | constructor (player: videojs.Player, options?: WebVideoPluginOptions) { |
24 | super(player, options) | 25 | super(player, options) |
@@ -28,6 +29,12 @@ class WebVideoPlugin extends Plugin { | |||
28 | 29 | ||
29 | this.updateVideoFile({ videoFile: this.pickAverageVideoFile(), isUserResolutionChange: false }) | 30 | this.updateVideoFile({ videoFile: this.pickAverageVideoFile(), isUserResolutionChange: false }) |
30 | 31 | ||
32 | this.onLoadedMetadata = () => { | ||
33 | player.trigger('video-ratio-changed', { ratio: this.player.videoWidth() / this.player.videoHeight() }) | ||
34 | } | ||
35 | |||
36 | player.on('loadedmetadata', this.onLoadedMetadata) | ||
37 | |||
31 | player.ready(() => { | 38 | player.ready(() => { |
32 | this.buildQualities() | 39 | this.buildQualities() |
33 | 40 | ||
@@ -43,6 +50,7 @@ class WebVideoPlugin extends Plugin { | |||
43 | dispose () { | 50 | dispose () { |
44 | clearInterval(this.networkInfoInterval) | 51 | clearInterval(this.networkInfoInterval) |
45 | 52 | ||
53 | if (this.onLoadedMetadata) this.player.off('loadedmetadata', this.onLoadedMetadata) | ||
46 | if (this.onErrorHandler) this.player.off('error', this.onErrorHandler) | 54 | if (this.onErrorHandler) this.player.off('error', this.onErrorHandler) |
47 | if (this.onPlayHandler) this.player.off('canplay', this.onPlayHandler) | 55 | if (this.onPlayHandler) this.player.off('canplay', this.onPlayHandler) |
48 | 56 | ||
diff --git a/client/src/assets/player/types/peertube-player-options.ts b/client/src/assets/player/types/peertube-player-options.ts index 352f7d8dd..6fb2f7913 100644 --- a/client/src/assets/player/types/peertube-player-options.ts +++ b/client/src/assets/player/types/peertube-player-options.ts | |||
@@ -38,6 +38,11 @@ export type PeerTubePlayerContructorOptions = { | |||
38 | language: string | 38 | language: string |
39 | 39 | ||
40 | pluginsManager: PluginsManager | 40 | pluginsManager: PluginsManager |
41 | |||
42 | autoPlayerRatio?: { | ||
43 | cssRatioVariable: string | ||
44 | cssPlayerPortraitModeVariable: string | ||
45 | } | ||
41 | } | 46 | } |
42 | 47 | ||
43 | export type PeerTubePlayerLoadOptions = { | 48 | export type PeerTubePlayerLoadOptions = { |
diff --git a/client/src/assets/player/types/peertube-videojs-typings.ts b/client/src/assets/player/types/peertube-videojs-typings.ts index dae9e14c8..27fbda31d 100644 --- a/client/src/assets/player/types/peertube-videojs-typings.ts +++ b/client/src/assets/player/types/peertube-videojs-typings.ts | |||
@@ -104,6 +104,11 @@ type VideoJSStoryboard = { | |||
104 | } | 104 | } |
105 | 105 | ||
106 | type PeerTubePluginOptions = { | 106 | type PeerTubePluginOptions = { |
107 | autoPlayerRatio: { | ||
108 | cssRatioVariable: string | ||
109 | cssPlayerPortraitModeVariable: string | ||
110 | } | ||
111 | |||
107 | hasAutoplay: () => videojs.Autoplay | 112 | hasAutoplay: () => videojs.Autoplay |
108 | 113 | ||
109 | videoViewUrl: () => string | 114 | videoViewUrl: () => string |
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss index 43a005774..f414cf185 100644 --- a/client/src/sass/include/_variables.scss +++ b/client/src/sass/include/_variables.scss | |||
@@ -97,7 +97,6 @@ $activated-action-button-color: #212529; | |||
97 | $focus-box-shadow-form: 0 0 0 .2rem; | 97 | $focus-box-shadow-form: 0 0 0 .2rem; |
98 | $form-input-font-size: 15px; | 98 | $form-input-font-size: 15px; |
99 | 99 | ||
100 | $video-watch-player-factor: math.div(16, 9); | ||
101 | $video-watch-info-margin-left: 44px; | 100 | $video-watch-info-margin-left: 44px; |
102 | 101 | ||
103 | $primeng-breakpoint: 960px; | 102 | $primeng-breakpoint: 960px; |
diff --git a/packages/tests/src/api/notifications/notifications-api.ts b/packages/tests/src/api/notifications/notifications-api.ts index 1c7461553..f99b81e94 100644 --- a/packages/tests/src/api/notifications/notifications-api.ts +++ b/packages/tests/src/api/notifications/notifications-api.ts | |||
@@ -18,7 +18,7 @@ describe('Test notifications API', function () { | |||
18 | let emails: object[] = [] | 18 | let emails: object[] = [] |
19 | 19 | ||
20 | before(async function () { | 20 | before(async function () { |
21 | this.timeout(120000) | 21 | this.timeout(240000) |
22 | 22 | ||
23 | const res = await prepareNotificationsTest(1) | 23 | const res = await prepareNotificationsTest(1) |
24 | emails = res.emails | 24 | emails = res.emails |