From 8e4fba97b26090e0c77ee9591058cd34ef9d2f55 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 18 Aug 2023 09:48:45 +0200 Subject: [PATCH] Automatically adapt player ratio --- .../video-watch-playlist.component.scss | 1 + .../+video-watch/video-watch.component.scss | 54 +++++++++---------- .../+video-watch/video-watch.component.ts | 7 ++- client/src/assets/player/peertube-player.ts | 4 +- .../player/shared/metrics/metrics-plugin.ts | 6 +-- .../p2p-media-loader-plugin.ts | 8 +++ .../player/shared/peertube/peertube-plugin.ts | 21 ++++++++ .../shared/web-video/web-video-plugin.ts | 8 +++ .../player/types/peertube-player-options.ts | 5 ++ .../player/types/peertube-videojs-typings.ts | 5 ++ client/src/sass/include/_variables.scss | 1 - .../api/notifications/notifications-api.ts | 2 +- 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 @@ .playlist { position: relative; min-width: 200px; + width: 25vw; max-width: 470px; height: 66vh; 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 @@ @use '_bootstrap-variables'; @use '_miniature' as *; -$video-height: 66vh; - -@function getPlayerHeight ($width) { - @return calc(#{$width} / #{$video-watch-player-factor}); -} - -@function getPlayerWidth ($height) { - @return calc(#{$height} * #{$video-watch-player-factor}); -} +$video-default-height: 66vh; +$video-theater-height: calc(100vh - #{$header-height} - #{$theater-bottom-space}); @mixin playlist-below-player { width: 100% !important; @@ -38,20 +31,16 @@ $video-height: 66vh; .root { &.theater-enabled #video-wrapper { - $height: calc(100vh - #{$header-height} - #{$theater-bottom-space}); - flex-direction: column; justify-content: center; #videojs-wrapper { width: 100%; - height: $height; + height: $video-theater-height; } ::ng-deep .video-js { - height: $height; - width: 100%; - max-width: initial; + --player-height: #{$video-theater-height}; } my-video-watch-playlist ::ng-deep .playlist { @@ -65,10 +54,24 @@ $video-height: 66vh; display: flex; justify-content: center; + #videojs-wrapper { + display: flex; + justify-content: center; + flex-grow: 1; + height: $video-default-height; + } + ::ng-deep .video-js { + --player-height: #{$video-default-height}; + --player-portrait-mode: 0; + // Default player ratio, redefined by the player to automatically adapt player size + --player-ratio: #{math.div(16, 9)}; + width: 100%; - max-width: getPlayerWidth($video-height); - height: $video-height; + height: var(--player-height); + + // Can be recalculated by the player depending on video ratio + max-width: calc(var(--player-height) * var(--player-ratio)); // VideoJS create an inner video player video { @@ -78,13 +81,6 @@ $video-height: 66vh; } } -#videojs-wrapper { - display: flex; - justify-content: center; - flex-grow: 1; - height: $video-height; -} - .remote-server-down { color: #fff; display: flex; @@ -253,12 +249,16 @@ my-video-comments { @media screen and (max-width: 600px) { #videojs-wrapper { - height: getPlayerHeight(100vw) !important; + // Reset height + height: initial !important; .remote-server-down, ::ng-deep .video-js { - width: 100vw; - height: getPlayerHeight(100vw) !important; + --player-portrait-mode: 1; + + // Can be recalculated by the player depending on video ratio + height: calc(100vw / var(--player-ratio)) !important; + max-height: $video-theater-height; } } 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 { peertubeLink: () => false, - pluginsManager: this.pluginService.getPluginsManager() + pluginsManager: this.pluginService.getPluginsManager(), + + autoPlayerRatio: { + cssRatioVariable: '--player-ratio', + cssPlayerPortraitModeVariable: '--player-portrait-mode' + } } } 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 { videoUUID: () => this.currentLoadOptions.videoUUID, subtitle: () => this.currentLoadOptions.subtitle, - poster: () => this.currentLoadOptions.poster + poster: () => this.currentLoadOptions.poster, + + autoPlayerRatio: this.options.autoPlayerRatio }, metrics: { 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 { private trackBytes () { this.player.on('network-info', (_event, data: PlayerNetworkInfo) => { - this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)) - this.downloadedBytesP2P += Math.round((data.p2p?.downloaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.downloaded || 0)) + this.downloadedBytesHTTP += Math.max(Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)), 0) + this.downloadedBytesP2P += Math.max(Math.round((data.p2p?.downloaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.downloaded || 0)), 0) - this.uploadedBytesP2P += Math.round((data.p2p?.uploaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.uploaded || 0)) + this.uploadedBytesP2P += Math.max(Math.round((data.p2p?.uploaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.uploaded || 0)), 0) this.p2pPeers = data.p2p?.peersP2POnly 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 { this.runStats() this.hlsjs.on(Hlsjs.Events.LEVEL_SWITCHED, () => this.player.trigger('engine-resolution-change')) + + this.hlsjs.on(Hlsjs.Events.MANIFEST_PARSED, (_event, data) => { + if (Array.isArray(data.levels) && data.levels.length > 1) { + const level = data.levels[0] + + this.player.trigger('video-ratio-changed', { ratio: level.width / level.height }) + } + }) } 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 { this.hideFatalError() }) }) + + this.initOnRatioChange() } dispose () { @@ -210,6 +212,25 @@ class PeerTubePlugin extends Plugin { this.runUserViewing() } + private initOnRatioChange () { + if (!this.options.autoPlayerRatio) return + + const defaultRatio = getComputedStyle(this.player.el()).getPropertyValue(this.options.autoPlayerRatio.cssRatioVariable) + + this.player.on('video-ratio-changed', (_event, data: { ratio: number }) => { + const el = this.player.el() as HTMLElement + + // In portrait screen mode, we allow player with bigger height size than width + const portraitMode = getComputedStyle(el).getPropertyValue(this.options.autoPlayerRatio.cssPlayerPortraitModeVariable) === '1' + + const currentRatio = !portraitMode && data.ratio < 1 + ? defaultRatio + : data.ratio + + el.style.setProperty('--player-ratio', currentRatio + '') + }) + } + // --------------------------------------------------------------------------- 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 { private onErrorHandler: () => void private onPlayHandler: () => void + private onLoadedMetadata: () => void constructor (player: videojs.Player, options?: WebVideoPluginOptions) { super(player, options) @@ -28,6 +29,12 @@ class WebVideoPlugin extends Plugin { this.updateVideoFile({ videoFile: this.pickAverageVideoFile(), isUserResolutionChange: false }) + this.onLoadedMetadata = () => { + player.trigger('video-ratio-changed', { ratio: this.player.videoWidth() / this.player.videoHeight() }) + } + + player.on('loadedmetadata', this.onLoadedMetadata) + player.ready(() => { this.buildQualities() @@ -43,6 +50,7 @@ class WebVideoPlugin extends Plugin { dispose () { clearInterval(this.networkInfoInterval) + if (this.onLoadedMetadata) this.player.off('loadedmetadata', this.onLoadedMetadata) if (this.onErrorHandler) this.player.off('error', this.onErrorHandler) if (this.onPlayHandler) this.player.off('canplay', this.onPlayHandler) 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 = { language: string pluginsManager: PluginsManager + + autoPlayerRatio?: { + cssRatioVariable: string + cssPlayerPortraitModeVariable: string + } } 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 = { } type PeerTubePluginOptions = { + autoPlayerRatio: { + cssRatioVariable: string + cssPlayerPortraitModeVariable: string + } + hasAutoplay: () => videojs.Autoplay 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; $focus-box-shadow-form: 0 0 0 .2rem; $form-input-font-size: 15px; -$video-watch-player-factor: math.div(16, 9); $video-watch-info-margin-left: 44px; $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 () { let emails: object[] = [] before(async function () { - this.timeout(120000) + this.timeout(240000) const res = await prepareNotificationsTest(1) emails = res.emails