Automatically adapt player ratio
This commit is contained in:
parent
276f5fa24f
commit
8e4fba97b2
|
@ -6,6 +6,7 @@
|
||||||
.playlist {
|
.playlist {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
width: 25vw;
|
||||||
max-width: 470px;
|
max-width: 470px;
|
||||||
height: 66vh;
|
height: 66vh;
|
||||||
background-color: pvar(--mainBackgroundColor);
|
background-color: pvar(--mainBackgroundColor);
|
||||||
|
|
|
@ -4,15 +4,8 @@
|
||||||
@use '_bootstrap-variables';
|
@use '_bootstrap-variables';
|
||||||
@use '_miniature' as *;
|
@use '_miniature' as *;
|
||||||
|
|
||||||
$video-height: 66vh;
|
$video-default-height: 66vh;
|
||||||
|
$video-theater-height: calc(100vh - #{$header-height} - #{$theater-bottom-space});
|
||||||
@function getPlayerHeight ($width) {
|
|
||||||
@return calc(#{$width} / #{$video-watch-player-factor});
|
|
||||||
}
|
|
||||||
|
|
||||||
@function getPlayerWidth ($height) {
|
|
||||||
@return calc(#{$height} * #{$video-watch-player-factor});
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin playlist-below-player {
|
@mixin playlist-below-player {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
@ -38,20 +31,16 @@ $video-height: 66vh;
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
&.theater-enabled #video-wrapper {
|
&.theater-enabled #video-wrapper {
|
||||||
$height: calc(100vh - #{$header-height} - #{$theater-bottom-space});
|
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
#videojs-wrapper {
|
#videojs-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: $height;
|
height: $video-theater-height;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep .video-js {
|
::ng-deep .video-js {
|
||||||
height: $height;
|
--player-height: #{$video-theater-height};
|
||||||
width: 100%;
|
|
||||||
max-width: initial;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my-video-watch-playlist ::ng-deep .playlist {
|
my-video-watch-playlist ::ng-deep .playlist {
|
||||||
|
@ -65,10 +54,24 @@ $video-height: 66vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
#videojs-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
height: $video-default-height;
|
||||||
|
}
|
||||||
|
|
||||||
::ng-deep .video-js {
|
::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%;
|
width: 100%;
|
||||||
max-width: getPlayerWidth($video-height);
|
height: var(--player-height);
|
||||||
height: $video-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
|
// VideoJS create an inner video player
|
||||||
video {
|
video {
|
||||||
|
@ -78,13 +81,6 @@ $video-height: 66vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#videojs-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-grow: 1;
|
|
||||||
height: $video-height;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remote-server-down {
|
.remote-server-down {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -253,12 +249,16 @@ my-video-comments {
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
#videojs-wrapper {
|
#videojs-wrapper {
|
||||||
height: getPlayerHeight(100vw) !important;
|
// Reset height
|
||||||
|
height: initial !important;
|
||||||
|
|
||||||
.remote-server-down,
|
.remote-server-down,
|
||||||
::ng-deep .video-js {
|
::ng-deep .video-js {
|
||||||
width: 100vw;
|
--player-portrait-mode: 1;
|
||||||
height: getPlayerHeight(100vw) !important;
|
|
||||||
|
// Can be recalculated by the player depending on video ratio
|
||||||
|
height: calc(100vw / var(--player-ratio)) !important;
|
||||||
|
max-height: $video-theater-height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -623,7 +623,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
peertubeLink: () => false,
|
peertubeLink: () => false,
|
||||||
|
|
||||||
pluginsManager: this.pluginService.getPluginsManager()
|
pluginsManager: this.pluginService.getPluginsManager(),
|
||||||
|
|
||||||
|
autoPlayerRatio: {
|
||||||
|
cssRatioVariable: '--player-ratio',
|
||||||
|
cssPlayerPortraitModeVariable: '--player-portrait-mode'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -364,7 +364,9 @@ export class PeerTubePlayer {
|
||||||
videoUUID: () => this.currentLoadOptions.videoUUID,
|
videoUUID: () => this.currentLoadOptions.videoUUID,
|
||||||
subtitle: () => this.currentLoadOptions.subtitle,
|
subtitle: () => this.currentLoadOptions.subtitle,
|
||||||
|
|
||||||
poster: () => this.currentLoadOptions.poster
|
poster: () => this.currentLoadOptions.poster,
|
||||||
|
|
||||||
|
autoPlayerRatio: this.options.autoPlayerRatio
|
||||||
},
|
},
|
||||||
metrics: {
|
metrics: {
|
||||||
mode: () => this.currentLoadOptions.mode,
|
mode: () => this.currentLoadOptions.mode,
|
||||||
|
|
|
@ -140,10 +140,10 @@ class MetricsPlugin extends Plugin {
|
||||||
|
|
||||||
private trackBytes () {
|
private trackBytes () {
|
||||||
this.player.on('network-info', (_event, data: PlayerNetworkInfo) => {
|
this.player.on('network-info', (_event, data: PlayerNetworkInfo) => {
|
||||||
this.downloadedBytesHTTP += Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0))
|
this.downloadedBytesHTTP += Math.max(Math.round(data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0)), 0)
|
||||||
this.downloadedBytesP2P += Math.round((data.p2p?.downloaded || 0) - (this.lastPlayerNetworkInfo?.p2p?.downloaded || 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.p2pPeers = data.p2p?.peersP2POnly
|
||||||
this.p2pEnabled = !!data.p2p
|
this.p2pEnabled = !!data.p2p
|
||||||
|
|
|
@ -119,6 +119,14 @@ class P2pMediaLoaderPlugin extends Plugin {
|
||||||
this.runStats()
|
this.runStats()
|
||||||
|
|
||||||
this.hlsjs.on(Hlsjs.Events.LEVEL_SWITCHED, () => this.player.trigger('engine-resolution-change'))
|
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 () {
|
private runStats () {
|
||||||
|
|
|
@ -115,6 +115,8 @@ class PeerTubePlugin extends Plugin {
|
||||||
this.hideFatalError()
|
this.hideFatalError()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.initOnRatioChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose () {
|
dispose () {
|
||||||
|
@ -210,6 +212,25 @@ class PeerTubePlugin extends Plugin {
|
||||||
this.runUserViewing()
|
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 () {
|
private runUserViewing () {
|
||||||
|
|
|
@ -19,6 +19,7 @@ class WebVideoPlugin extends Plugin {
|
||||||
|
|
||||||
private onErrorHandler: () => void
|
private onErrorHandler: () => void
|
||||||
private onPlayHandler: () => void
|
private onPlayHandler: () => void
|
||||||
|
private onLoadedMetadata: () => void
|
||||||
|
|
||||||
constructor (player: videojs.Player, options?: WebVideoPluginOptions) {
|
constructor (player: videojs.Player, options?: WebVideoPluginOptions) {
|
||||||
super(player, options)
|
super(player, options)
|
||||||
|
@ -28,6 +29,12 @@ class WebVideoPlugin extends Plugin {
|
||||||
|
|
||||||
this.updateVideoFile({ videoFile: this.pickAverageVideoFile(), isUserResolutionChange: false })
|
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(() => {
|
player.ready(() => {
|
||||||
this.buildQualities()
|
this.buildQualities()
|
||||||
|
|
||||||
|
@ -43,6 +50,7 @@ class WebVideoPlugin extends Plugin {
|
||||||
dispose () {
|
dispose () {
|
||||||
clearInterval(this.networkInfoInterval)
|
clearInterval(this.networkInfoInterval)
|
||||||
|
|
||||||
|
if (this.onLoadedMetadata) this.player.off('loadedmetadata', this.onLoadedMetadata)
|
||||||
if (this.onErrorHandler) this.player.off('error', this.onErrorHandler)
|
if (this.onErrorHandler) this.player.off('error', this.onErrorHandler)
|
||||||
if (this.onPlayHandler) this.player.off('canplay', this.onPlayHandler)
|
if (this.onPlayHandler) this.player.off('canplay', this.onPlayHandler)
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,11 @@ export type PeerTubePlayerContructorOptions = {
|
||||||
language: string
|
language: string
|
||||||
|
|
||||||
pluginsManager: PluginsManager
|
pluginsManager: PluginsManager
|
||||||
|
|
||||||
|
autoPlayerRatio?: {
|
||||||
|
cssRatioVariable: string
|
||||||
|
cssPlayerPortraitModeVariable: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PeerTubePlayerLoadOptions = {
|
export type PeerTubePlayerLoadOptions = {
|
||||||
|
|
|
@ -104,6 +104,11 @@ type VideoJSStoryboard = {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PeerTubePluginOptions = {
|
type PeerTubePluginOptions = {
|
||||||
|
autoPlayerRatio: {
|
||||||
|
cssRatioVariable: string
|
||||||
|
cssPlayerPortraitModeVariable: string
|
||||||
|
}
|
||||||
|
|
||||||
hasAutoplay: () => videojs.Autoplay
|
hasAutoplay: () => videojs.Autoplay
|
||||||
|
|
||||||
videoViewUrl: () => string
|
videoViewUrl: () => string
|
||||||
|
|
|
@ -97,7 +97,6 @@ $activated-action-button-color: #212529;
|
||||||
$focus-box-shadow-form: 0 0 0 .2rem;
|
$focus-box-shadow-form: 0 0 0 .2rem;
|
||||||
$form-input-font-size: 15px;
|
$form-input-font-size: 15px;
|
||||||
|
|
||||||
$video-watch-player-factor: math.div(16, 9);
|
|
||||||
$video-watch-info-margin-left: 44px;
|
$video-watch-info-margin-left: 44px;
|
||||||
|
|
||||||
$primeng-breakpoint: 960px;
|
$primeng-breakpoint: 960px;
|
||||||
|
|
|
@ -18,7 +18,7 @@ describe('Test notifications API', function () {
|
||||||
let emails: object[] = []
|
let emails: object[] = []
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(120000)
|
this.timeout(240000)
|
||||||
|
|
||||||
const res = await prepareNotificationsTest(1)
|
const res = await prepareNotificationsTest(1)
|
||||||
emails = res.emails
|
emails = res.emails
|
||||||
|
|
Loading…
Reference in New Issue