#63523 Выбор размера плеера

This commit is contained in:
Ксения Петрова
2025-05-22 09:38:20 +00:00
committed by Юрий Шикин
parent 76209f2c7c
commit 10ef949e9e
9 changed files with 186 additions and 6 deletions
+7
View File
@@ -131,4 +131,11 @@ volume: {
{
selection: true,
}
```
**enableDocumentPictureInPicture** - включает картинку в картинке, если она доступна для браузера
```js
{
enableDocumentPictureInPicture: true,
}
```
+5 -3
View File
@@ -15,10 +15,12 @@
appearance: none;
}
.voka-control .voka-button {
height: 100%;
padding: 0;
.voka-button {
cursor: pointer;
&.voka-disabled {
opacity: 0.5;
}
}
.voka-control .voka-svg-container:hover svg path {
+13
View File
@@ -0,0 +1,13 @@
.vjs-pip-window {
margin: 0;
background: black;
.video-js {
width: 100vw;
height: 100vh;
aspect-ratio: auto;
}
.voka-selection-wrapper,
.voka-bottom-panel {
display: none;
}
}
+2
View File
@@ -38,6 +38,8 @@
@use "../scss/components/audio";
@use "../scss/components/selection";
@use "../scss/components/timeline";
@use "../scss/components/pip";
::-moz-selection {background: rgba(0,0,0,0);}
::selection {background: rgba(0,0,0,0);}
+2 -1
View File
@@ -10,6 +10,7 @@ import '@/components/control-bar/ZoomButton'
import '@/components/control-bar/subtitles/SubtitlesButton'
import '@/components/control-bar/quality-control/QualityButton'
import '@/components/control-bar/audio-control/AudioButton'
import '@/components/control-bar/PictureInPictureToggle'
/**
* Container of main controls.
@@ -21,7 +22,7 @@ class BottomPanel extends ClickableComponent {
let controls = !!options.playerOptions.controls
const _options = {
...options,
children: ['PlayToggle', 'StartOver', 'VolumePanel', 'ProgressControl', 'PlaybackRateButton', 'ZoomButton', 'SubtitlesButton', 'QualityButton', 'AudioButton', 'FullscreenToggle']
children: ['PlayToggle', 'StartOver', 'VolumePanel', 'ProgressControl', 'PlaybackRateButton', 'ZoomButton', 'SubtitlesButton', 'QualityButton', 'AudioButton', 'PictureInPictureToggle', 'FullscreenToggle']
}
super(player, _options)
@@ -0,0 +1,143 @@
import videojs, { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js'
import document from 'global/document'
import window from 'global/window'
import { SvgType } from '@/constants/VokaSvg'
import Button from '@/components/Button.ts'
import { TooltipPosition } from '../ClickableComponent'
const Component = videojs.getComponent('component')
const Browser = videojs.browser
class PictureInPictureToggle extends Button {
videoEl: any
constructor(player: VideoJsPlayer, options: VideoJsPlayerOptions) {
const options_ = {
...options,
svg: SvgType.PICTURE_IN_PICTURE
}
super(player, options_)
this.on(player, ['enterpictureinpicture', 'leavepictureinpicture'], (e) =>
this.handlePiPEnabledChange(e)
)
this.on(player, ['disablepictureinpicturechanged', 'loadedmetadata'], (e) =>
this.handlePiPEnabledChange(e)
)
this.on(
player,
['loadedmetadata', 'audioonlymodechange', 'audiopostermodechange'],
() => this.handlePiPAudioModeChange()
)
this.on(player, ['play'], (e) => this.handlePiPEnabledChange(e))
this.controlText('Picture-in-Picture', this.el(), TooltipPosition.topLeft)
this.disable()
}
buildCSSClass() {
return `voka-picture-in-picture-control vjs-hidden ${super.buildCSSClass()}`
}
/**
* Displays or hides the button depending on the audio mode detection.
* Exits picture-in-picture if it is enabled when switching to audio mode.
*/
handlePiPAudioModeChange() {
// This audio detection will not detect HLS or DASH audio-only streams because there was no reliable way to detect them at the time
const isSourceAudio = this.player_.currentType().substring(0, 5) === 'audio'
const isAudioMode =
isSourceAudio ||
this.player_.audioPosterMode() ||
this.player_.audioOnlyMode()
if (!isAudioMode) {
this.show()
return
}
if (this.player_.isInPictureInPicture()) {
this.player_.exitPictureInPicture()
}
this.hide()
}
/**
* Enabled if
* - `player.options().enableDocumentPictureInPicture` is true and
* window.documentPictureInPicture is available; or
* - `player.disablePictureInPicture()` is false and
* element.requestPictureInPicture is available; or
* - (for safari) The videoEl contains webkitSupportsPresentationMode,
* which supports picture-in-picture mode.
*/
checkPiPSupport() {
this.videoEl = this.player_?.tech({ IWillNotUseThisInPlugins: true })?.el()
return (
(document.pictureInPictureEnabled &&
this.player_.disablePictureInPicture() === false) ||
(this.player_.options_.playerOptions.enableDocumentPictureInPicture &&
'documentPictureInPicture' in window) ||
(this.videoEl &&
this.videoEl.webkitSupportsPresentationMode &&
this.videoEl.webkitSupportsPresentationMode('picture-in-picture') &&
typeof this.videoEl.webkitSetPresentationMode === 'function')
)
}
/**
* Enables or disables button based on availability of a Picture-In-Picture mode.
*/
handlePiPEnabledChange() {
if (this.checkPiPSupport()) {
this.enable()
} else {
this.disable()
}
}
/**
* This gets called when an `PictureInPictureToggle` is "clicked". See
*/
handleClick(event) {
if (Browser.IS_SAFARI) {
this.handleClickForSafari()
return
}
if (!this.player_.isInPictureInPicture()) {
this.player_.requestPictureInPicture()
} else {
this.player_.exitPictureInPicture()
}
}
handleClickForSafari() {
if (this.checkPiPSupport()) {
this.videoEl.webkitSetPresentationMode(
this.videoEl.webkitPresentationMode === 'picture-in-picture'
? 'inline'
: 'picture-in-picture'
)
}
}
/**
* Show the `Component`s element if it is hidden by removing the
* 'vjs-hidden' class name from it only in browsers that support the Picture-in-Picture API.
*/
show() {
// Does not allow to display the pictureInPictureToggle in browsers that do not support the Picture-in-Picture API, e.g. Firefox.
if (typeof document.exitPictureInPicture !== 'function') {
return
}
super.show()
}
}
Component.registerComponent('PictureInPictureToggle', PictureInPictureToggle)
export default PictureInPictureToggle
+9
View File
@@ -17,6 +17,7 @@ export const SvgType = {
VOLUME_LOW: 'volume-low',
VOLUME_MID: 'volume-mid',
VOLUME_HIGH: 'volume-high',
PICTURE_IN_PICTURE: 'picture_in_picture',
}
export default class VokaSvg {
@@ -58,6 +59,8 @@ export default class VokaSvg {
return VokaSvg.volumeMid()
case SvgType.VOLUME_HIGH:
return VokaSvg.volumeHigh()
case SvgType.PICTURE_IN_PICTURE:
return VokaSvg.pictureInPictureButton()
default:
console.warn('Unknown SvgType received!')
@@ -189,6 +192,12 @@ export default class VokaSvg {
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.1 36C6.8 36 5 34.1 5 31.9V22.9C5 20.7 6.8 18.8 9.1 18.8H15.2L29.4 9.1V45.8L15 36H9.1ZM40 43C39.7 43.3 39.4 43.4 38.9 43.4C38.5 43.4 38.1 43.3 37.8 43C37.2 42.4 37.2 41.5 37.8 40.9C40.8 37.9 43 35.3 43 28.3C43 23 41.2 19.1 37.3 15.1C36.7 14.5 36.7 13.6 37.3 13C37.9 12.4 38.8 12.4 39.4 13C43.9 17.5 46 22.1 46 28.2C46.1 36.4 43.3 39.7 40 43ZM36.1 39.3C35.8 39.6 35.5 39.7 35 39.7C34.6 39.7 34.2 39.6 33.9 39.3C33.3 38.7 33.3 37.8 33.9 37.2C36.9 34.2 37.3 29.9 37.3 28.3C37.3 25.7 36.1 21.8 33.9 19.6C33.3 19 33.3 18.1 33.9 17.5C34.5 16.9 35.4 16.9 36 17.5C38.8 20.3 40.3 25.1 40.3 28.3C40.3 30.3 39.9 35.4 36.1 39.3Z" fill="currentColor"/>
<path d="M44.7999 45.1C44.4999 45.4 44.1999 45.5 43.6999 45.5C43.2999 45.5 42.8999 45.4 42.5999 45.1C41.9999 44.5 41.9999 43.6 42.5999 43C45.5999 40 48 35.2 48 28.2C48 22.9 45.3 15.6 41.4 11.6C40.8 11 40.8 10.1 41.4 9.50005C42 8.90005 42.9 8.90005 43.5 9.50005C48 14 51 21.9 51 28C51.1 36.2 48.0999 41.8 44.7999 45.1Z" fill="currentColor"/>
</svg>
`
}
static pictureInPictureButton() {
return `<svg width="55" height="55" viewBox="0 0 55 55" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40 25.6667H25.3333V36.6575H40V25.6667ZM47.3333 40.3333V14.63C47.3333 12.6133 45.6833 11 43.6667 11H10.6667C8.65 11 7 12.6133 7 14.63V40.3333C7 42.35 8.65 44 10.6667 44H43.6667C45.6833 44 47.3333 42.35 47.3333 40.3333ZM43.6667 40.37H10.6667V14.6117H43.6667V40.37Z" fill="currentColor"/>
</svg>
`
}
}
+1
View File
@@ -280,6 +280,7 @@ export class VokaPlayerCore {
// return `https://streaming.voka.tv/vod_preview/velcom/4W17sRxFu8eCAps3kdTxJrFk7d46DNmum_320x180.jpeg?preview_pos=${percent}`;
},
},
enableDocumentPictureInPicture: true,
}
}
+4 -2
View File
@@ -24,7 +24,8 @@
"Zoom": "Кадрирование",
"Process Selection": "Обработать выделение",
"Selection End": "Конец выделения",
"Selection Start": "Начало выделения"
"Selection Start": "Начало выделения",
"Picture-in-Picture": "Картинка в картинке"
},
"en": {
"Play": "Play",
@@ -51,6 +52,7 @@
"Zoom": "Zoom",
"Process Selection": "Process Selection",
"Selection End": "Selection End",
"Selection Start": "Selection Start"
"Selection Start": "Selection Start",
"Picture-in-Picture": "Picture-in-Picture"
}
}