.playlist {
position: relative;
min-width: 200px;
+ width: 25vw;
max-width: 470px;
height: 66vh;
background-color: pvar(--mainBackgroundColor);
@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;
.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 {
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 {
}
}
-#videojs-wrapper {
- display: flex;
- justify-content: center;
- flex-grow: 1;
- height: $video-height;
-}
-
.remote-server-down {
color: #fff;
display: flex;
@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;
}
}
peertubeLink: () => false,
- pluginsManager: this.pluginService.getPluginsManager()
+ pluginsManager: this.pluginService.getPluginsManager(),
+
+ autoPlayerRatio: {
+ cssRatioVariable: '--player-ratio',
+ cssPlayerPortraitModeVariable: '--player-portrait-mode'
+ }
}
}
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,
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
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 () {
this.hideFatalError()
})
})
+
+ this.initOnRatioChange()
}
dispose () {
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 onErrorHandler: () => void
private onPlayHandler: () => void
+ private onLoadedMetadata: () => void
constructor (player: videojs.Player, options?: WebVideoPluginOptions) {
super(player, options)
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()
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)
language: string
pluginsManager: PluginsManager
+
+ autoPlayerRatio?: {
+ cssRatioVariable: string
+ cssPlayerPortraitModeVariable: string
+ }
}
export type PeerTubePlayerLoadOptions = {
}
type PeerTubePluginOptions = {
+ autoPlayerRatio: {
+ cssRatioVariable: string
+ cssPlayerPortraitModeVariable: string
+ }
+
hasAutoplay: () => videojs.Autoplay
videoViewUrl: () => string
$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;
let emails: object[] = []
before(async function () {
- this.timeout(120000)
+ this.timeout(240000)
const res = await prepareNotificationsTest(1)
emails = res.emails