Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/ui/video-player/src/ |
Upload File : |
/* eslint-disable @bitrix24/bitrix24-rules/no-native-dom-methods */ import { Dom, Type, Event, Reflection, Loc, type JsonObject } from 'main.core'; import { BaseEvent } from 'main.core.events'; import { videojs } from 'ui.video-js'; import { GlobalSettings } from './global-settings'; import { PlayerManager } from './player-manager'; let langSetup = false; videojs.hook('beforesetup', (videoEl, options) => { Dom.addClass(videoEl, 'ui-video-player ui-icon-set__scope'); if (videoEl.tagName.toLowerCase() === 'audio') { Dom.addClass(videoEl, 'vjs-audio-only-mode'); } if (langSetup === false) { videojs.addLanguage('video-player', { Play: Loc.getMessage('VIDEO_PLAYER_PLAY'), Pause: Loc.getMessage('VIDEO_PLAYER_PAUSE'), Replay: Loc.getMessage('VIDEO_PLAYER_REPLAY'), 'Current Time': Loc.getMessage('VIDEO_PLAYER_CURRENT_TIME'), Duration: Loc.getMessage('VIDEO_PLAYER_DURATION'), 'Remaining Time': Loc.getMessage('VIDEO_PLAYER_REMAINING_TIME'), Loaded: Loc.getMessage('VIDEO_PLAYER_LOADED'), Progress: Loc.getMessage('VIDEO_PLAYER_PROGRESS'), 'Progress Bar': Loc.getMessage('VIDEO_PLAYER_PROGRESS_BAR'), Fullscreen: Loc.getMessage('VIDEO_PLAYER_FULLSCREEN'), 'Exit Fullscreen': Loc.getMessage('VIDEO_PLAYER_EXIT_FULLSCREEN'), Mute: Loc.getMessage('VIDEO_PLAYER_MUTE'), Unmute: Loc.getMessage('VIDEO_PLAYER_UNMUTE'), 'Playback Rate': Loc.getMessage('VIDEO_PLAYER_PLAYBACK_RATE'), 'Volume Level': Loc.getMessage('VIDEO_PLAYER_VOLUME_LEVEL'), 'You aborted the media playback': Loc.getMessage('VIDEO_PLAYER_ABORTED_PLAYBACK'), 'A network error caused the media download to fail part-way.': Loc.getMessage('VIDEO_PLAYER_NETWORK_ERROR'), 'The media could not be loaded, either because the server or network failed or because the format is not supported.': Loc.getMessage('VIDEO_PLAYER_FORMAT_NOT_SUPPORTED'), 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.': Loc.getMessage('VIDEO_PLAYER_PLAYBACK_WAS_ABORTED'), 'No compatible source was found for this media.': Loc.getMessage('VIDEO_PLAYER_NO_COMPATIBLE_SOURCE'), 'The media is encrypted and we do not have the keys to decrypt it.': Loc.getMessage('VIDEO_PLAYER_MEDIA_IS_ENCRYPTED'), 'Play Video': Loc.getMessage('VIDEO_PLAYER_PLAY_VIDEO'), 'Exit Picture-in-Picture': Loc.getMessage('VIDEO_PLAYER_EXIT_PICTURE_IN_PICTURE'), 'Picture-in-Picture': Loc.getMessage('VIDEO_PLAYER_PICTURE_IN_PICTURE'), }); langSetup = true; } return options; }); export class Player { id: string = null; muted: boolean = false; hasStarted: boolean = false; vjsPlayer: boolean = null; isAudio: boolean = false; static #globalSettings = new GlobalSettings('bx-video-player-settings'); constructor(id, params) { this.id = id; this.#fillParameters(params); PlayerManager.addPlayer(this); this.#fireEvent('onCreate'); } isReady(): boolean { // eslint-disable-next-line no-underscore-dangle return this.vjsPlayer && this.vjsPlayer.isReady_; } play(): void { this.setPlayedState(); this.hasStarted = true; try { this.vjsPlayer.play(); } catch { // fail silently } this.#fireEvent('onPlay'); } pause(): void { try { this.vjsPlayer.pause(); } catch { // fail silently } this.#fireEvent('onPause'); } toggle(): void { if (this.isPlaying()) { this.pause(); } else { this.play(); } } isPlaying(): boolean { if (this.vjsPlayer) { return this.isReady() && !this.vjsPlayer.paused(); } return false; } isEnded(): boolean { if (this.vjsPlayer) { return this.vjsPlayer.ended(); } return false; } setPlayedState(): void { const storageHash = this.#getStorageHash(); const localStorage = Reflection.getClass('BX.localStorage'); if (localStorage) { localStorage.set(storageHash, 'played', 14 * 24 * 3600); } } isPlayed(): boolean { const storageHash = this.#getStorageHash(); /** @type {BX.localStorage} */ const localStorage = Reflection.getClass('BX.localStorage'); if (localStorage) { return localStorage.get(storageHash) === 'played'; } return true; } #getStorageHash(): string { let storageHash = this.id; if (Type.isArrayFilled(this.params.sources) && this.params.sources[0].src) { storageHash = this.params.sources[0].src; } return `player_${storageHash}`; } getElement(): HTMLElement | null { return document.getElementById(this.id); } createElement(): HTMLElement | null { let node = this.getElement(); if (node) { return node; } if (!this.id) { return null; } let tagName = 'video'; const classes = ['video-js', 'ui-video-player', 'ui-icon-set__scope']; if (this.isAudio) { tagName = 'audio'; classes.push('vjs-audio-only-mode'); } let className = classes.join(' '); if (this.skin) { className += ` ${this.skin}`; } const attrs = { id: this.id, className, width: this.width, height: this.height, controls: true, }; if (this.muted) { attrs.muted = true; } node = Dom.create(tagName, { attrs }); if (Type.isArrayFilled(this.params.sources)) { for (const source of this.params.sources) { if (!source.src || !source.type) { continue; } const sourceTag = Dom.create('source', { attrs: { src: source.src, type: source.type, }, }); Dom.append(sourceTag, node); } } return node; } #fillParameters(options: JsonObject) { const defaults = this.#getDefaultOptions(); const params = Type.isPlainObject(options) ? { ...defaults, ...options } : defaults; if (Type.isArrayFilled(params.techOrder)) { // Compatibility params.techOrder = params.techOrder.filter((tech: string) => tech !== 'flash'); } this.autostart = params.autostart || false; if (params.playbackRate) { params.playbackRate = parseFloat(params.playbackRate); if (params.playbackRate !== 1) { if (params.playbackRate <= 0) { params.playbackRate = 1; } if (params.playbackRate > 3) { params.playbackRate = 3; } } if (params.playbackRate !== 1) { this.playbackRate = params.playbackRate; } } this.volume = BX.Type.isNumber(params.volume) ? params.volume : null; this.startTime = params.startTime || 0; this.onInit = params.onInit; this.lazyload = params.lazyload; this.skin = params.skin || ''; this.isAudio = params.isAudio || false; if (this.isAudio) { params.width = params.width || 400; params.height = params.height || 30; params.audioOnlyMode = true; } else { params.width = Math.max(params.width || 560, 400); params.height = Math.max(params.height || 315, 130); } this.width = params.width; this.height = params.height; this.duration = params.duration || null; this.muted = params.muted || false; this.params = params; } #getDefaultOptions(): JsonObject { return { controls: true, playbackRates: [0.5, 1, 1.25, 1.5, 1.75, 2], language: 'video-player', userActions: { click: this.#handleClick.bind(this), hotkeys: this.#handleKeyDown.bind(this), }, }; } setSource(source): void { if (!source) { return; } this.vjsPlayer.src(source); this.#fireEvent('onSetSource'); } getSource(): string { return this.vjsPlayer.src(); } init(): void { if (this.vjsPlayer !== null) { return; } this.#fireEvent('onBeforeInit'); this.vjsPlayer = videojs(this.id, this.params); if (this.isAudio) { this.#hideAudioControls(); this.#setInitialVolume(); } this.vjsPlayer.one('loadedmetadata', (event) => { if (!this.isAudio && !(this.vjsPlayer.videoWidth() > 0 && this.vjsPlayer.videoHeight() > 0)) { // Throw an error if a video doesn't have dimensions event.stopPropagation(); event.stopImmediatePropagation(); setTimeout(() => { this.vjsPlayer.error(4); }, 0); } else if (this.duration > 0) { this.vjsPlayer.duration(this.duration); } }); this.vjsPlayer.on('fullscreenchange', () => { this.vjsPlayer.focus(); }); this.#proxyEvents(); this.vjsPlayer.ready(() => { const controlBar = this.vjsPlayer.getChild('ControlBar'); const playbackButton = controlBar.getChild('PlaybackRateMenuButton'); if (playbackButton) { // eslint-disable-next-line no-underscore-dangle videojs.off(playbackButton.menuButton_.el(), 'mouseenter'); videojs.off(playbackButton.el(), 'mouseleave'); } this.vjsPlayer.one('play', this.#handlePlayOnce.bind(this)); if (Type.isFunction(this.onInit)) { this.onInit(this); } this.#fireEvent('onAfterInit'); }); if (this.autostart && !this.lazyload) { this.vjsPlayer.one('canplay', () => { if (!this.hasStarted) { this.play(); } }); } } isInited(): boolean { return this.vjsPlayer !== null; } getEventList(): Array<string> { return [ 'Player:onBeforeInit', 'Player:onAfterInit', 'Player:onCreate', 'Player:onSetSource', 'Player:onKeyDown', 'Player:onPlay', 'Player:onPause', 'Player:onClick', 'Player:onError', 'Player:onEnded', 'Player:onEnterPictureInPicture', 'Player:onLeavePictureInPicture', ]; } mute(mute: boolean | undefined): boolean { return this.vjsPlayer?.muted(mute); } isMuted(): boolean { return this.vjsPlayer?.muted(); } focus(): void { this.vjsPlayer?.focus(); } moveBackward(skipTime: number): void { const currentVideoTime = this.vjsPlayer.currentTime(); const liveTracker = this.vjsPlayer.liveTracker; const seekableStart = liveTracker && liveTracker.isLive() && liveTracker.seekableStart(); let newTime = 0; if (seekableStart && (currentVideoTime - skipTime <= seekableStart)) { newTime = seekableStart; } else if (currentVideoTime >= skipTime) { newTime = currentVideoTime - skipTime; } this.vjsPlayer.currentTime(newTime); } moveForward(skipTime: number): void { if (!Type.isNumber(this.vjsPlayer.duration())) { return; } const currentVideoTime = this.vjsPlayer.currentTime(); const liveTracker = this.vjsPlayer.liveTracker; const duration = (liveTracker && liveTracker.isLive()) ? liveTracker.seekableEnd() : this.vjsPlayer.duration(); const newTime = currentVideoTime + skipTime <= duration ? currentVideoTime + skipTime : duration; this.vjsPlayer.currentTime(newTime); } increasePlaybackRate(): void { const playbackRates: Number[] = this.vjsPlayer.playbackRates(); const currentPlayback = this.vjsPlayer.playbackRate(); const nextPlayback = playbackRates.find((value) => { return value > currentPlayback; }); if (nextPlayback) { this.vjsPlayer.playbackRate(nextPlayback); } } decreasePlaybackRate(): void { const playbackRates = [...this.vjsPlayer.playbackRates()].reverse(); const currentPlayback = this.vjsPlayer.playbackRate(); const prevPlayback = playbackRates.find((value) => { return value < currentPlayback; }); if (prevPlayback) { this.vjsPlayer.playbackRate(prevPlayback); } } #hideAudioControls(): void { this.vjsPlayer.removeChild('BigPlayButton'); this.vjsPlayer.removeChild('TextTrackSettings'); this.vjsPlayer.removeChild('PosterImage'); this.vjsPlayer.controlBar.removeChild('FullscreenToggle'); this.vjsPlayer.controlBar.removeChild('PictureInPictureToggle'); this.vjsPlayer.controlBar.removeChild('ChaptersButton'); this.vjsPlayer.controlBar.removeChild('DescriptionsButton'); if (this.skin === 'vjs-audio-wave-skin' || this.skin === 'vjs-viewer-audio-player-skin') { this.vjsPlayer.removeChild('VolumePanel'); this.vjsPlayer.controlBar.removeChild('VolumePanel'); this.vjsPlayer.controlBar.removeChild('CurrentTimeDisplay'); this.vjsPlayer.controlBar.removeChild('PlaybackRateMenuButton'); } } #handlePlayOnce(): void { if (this.playbackRate !== 1) { this.vjsPlayer.playbackRate(this.playbackRate); } this.#setInitialVolume(); if (this.startTime > 0) { try { this.vjsPlayer.currentTime(this.startTime); } catch { // Fail silently } } this.vjsPlayer.on('volumechange', () => { this.constructor.#globalSettings.set('volume', this.vjsPlayer.volume()); }); } #setInitialVolume(): void { const hasVolumePanel = !BX.Type.isNil(this.vjsPlayer.controlBar.getChild('VolumePanel')); if (hasVolumePanel) { const volume = this.volume === null ? this.constructor.#globalSettings.get('volume', 0.8) : this.volume; this.vjsPlayer.volume(volume); } else { const volume = this.volume === null ? 0.8 : this.volume; this.vjsPlayer.volume(volume); } } #handleClick(event: MouseEvent): void { this.toggle(); event.preventDefault(); event.stopPropagation(); } #handleKeyDown(event: KeyboardEvent): void { const beforeKeyDownEvent = new BaseEvent({ event }); this.#fireEvent('onBeforeKeyDown', beforeKeyDownEvent); if (beforeKeyDownEvent.isDefaultPrevented()) { return; } switch (event.code) { case 'KeyK': case 'Space': { this.toggle(); event.preventDefault(); event.stopPropagation(); break; } case 'KeyF': { if (!this.isAudio) { if (this.vjsPlayer.isFullscreen()) { this.vjsPlayer.exitFullscreen(); } else { this.vjsPlayer.requestFullscreen(); } event.preventDefault(); event.stopPropagation(); } break; } case 'KeyJ': { this.moveBackward(10); event.preventDefault(); event.stopPropagation(); break; } case 'KeyL': { this.moveForward(10); event.preventDefault(); event.stopPropagation(); break; } case 'ArrowLeft': { this.moveBackward(5); event.preventDefault(); event.stopPropagation(); break; } case 'ArrowRight': { this.moveForward(5); event.preventDefault(); event.stopPropagation(); break; } case 'KeyM': { if (this.isMuted()) { this.mute(false); } else { this.mute(true); } event.preventDefault(); event.stopPropagation(); break; } case 'Comma': { this.decreasePlaybackRate(); event.preventDefault(); event.stopPropagation(); break; } case 'Period': { this.increasePlaybackRate(); event.preventDefault(); event.stopPropagation(); break; } default: { // nothing } } this.#fireEvent('onKeyDown', new BaseEvent({ event })); } #fireEvent(eventName: string, event): void { if (Type.isStringFilled(eventName)) { const fullName = `Player:${eventName}`; const compatEvent = event || new BaseEvent(); compatEvent.setCompatData([this, fullName]); Event.EventEmitter.emit(this, fullName, compatEvent); } } #proxyEvents() { this.vjsPlayer.on('play', () => { this.#fireEvent('onPlay'); this.hasStarted = true; }); this.vjsPlayer.on('pause', () => { this.#fireEvent('onPause'); }); this.vjsPlayer.on('click', () => { this.#fireEvent('onClick'); }); this.vjsPlayer.on('ended', () => { this.#fireEvent('onEnded'); }); this.vjsPlayer.on('loadedmetadata', () => { this.#fireEvent('onLoadedMetadata'); }); this.vjsPlayer.on('error', () => { this.#fireEvent('onError'); }); this.vjsPlayer.on('enterpictureinpicture', () => { this.#fireEvent('onEnterPictureInPicture'); }); this.vjsPlayer.on('leavepictureinpicture', () => { const event = new BaseEvent(); this.#fireEvent('onLeavePictureInPicture', event); if (!event.isDefaultPrevented()) { const visible = PlayerManager.isVisibleOnScreen(this.id, 1); if (!visible) { this.pause(); } } }); } destroy() { PlayerManager.removePlayer(this); if (this.vjsPlayer !== null) { this.vjsPlayer.dispose(); } this.vjsPlayer = null; } }