63297 - draft player implementation
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
.DS_Store
|
||||
.idea
|
||||
distribution
|
||||
node_modules
|
||||
|
||||
@@ -5,6 +5,7 @@ FROM arm64v8/node:23.6.1-alpine3.21 AS arm
|
||||
WORKDIR /usr/voka
|
||||
|
||||
COPY package.json .
|
||||
COPY package-lock.json .
|
||||
COPY develop.sh .
|
||||
|
||||
RUN <<EOF
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
docker build -t voka-player .
|
||||
```
|
||||
|
||||
Обязательно перед запуском докера создать директорию `node_modules`!
|
||||
Ни в коем случае не вносить в нее какие-либо изменения.
|
||||
Директория реплицируется на хост машину для удобства.
|
||||
|
||||
Далее требуется запустить докер композ.
|
||||
|
||||
```
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello world3</h1>
|
||||
<h1>Hello world</h1>
|
||||
<div id="my-video"/>
|
||||
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
|
||||
</body>
|
||||
|
||||
+10
-4
@@ -1,5 +1,3 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
server:
|
||||
image: docker.io/library/voka-player
|
||||
@@ -10,6 +8,14 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- $PWD:/usr/voka
|
||||
- /usr/voka/node_modules
|
||||
- node_modules:/usr/voka/node_modules
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8080:8080"
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: none
|
||||
o: bind
|
||||
device: $PWD/node_modules
|
||||
Generated
+73
@@ -17,6 +17,7 @@
|
||||
"express": "^4.21.2",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-preset-env": "^10.1.3",
|
||||
"ts-bus": "^2.3.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsup": "^8.3.6",
|
||||
"typescript": "^5.7.3",
|
||||
@@ -2970,6 +2971,12 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter2": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz",
|
||||
"integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
@@ -3360,6 +3367,13 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
@@ -3393,6 +3407,19 @@
|
||||
"integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
@@ -4511,6 +4538,18 @@
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"license": "MIT",
|
||||
@@ -4564,6 +4603,28 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
@@ -5562,6 +5623,18 @@
|
||||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-bus": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-bus/-/ts-bus-2.3.1.tgz",
|
||||
"integrity": "sha512-ZoiVKzctxeJvQ0ZB7Fc/wpbEEA5NEjdZWebisXk8raFfEFigDmwl1fKTcr+jNRfEcwFl1QJ4oiirxGR0YnPq1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eventemitter2": "^5.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-interface-checker": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"express": "^4.21.2",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-preset-env": "^10.1.3",
|
||||
"ts-bus": "^2.3.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsup": "^8.3.6",
|
||||
"typescript": "^5.7.3",
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import videojs from 'video.js'
|
||||
import { VideoJsPlayer, VideoJsPlayerOptions } from '@types/video.js'
|
||||
import { EventBus } from 'ts-bus'
|
||||
import { IVokaPlayer } from '@/public/IVokaPlayer'
|
||||
import { AutoplayChecker } from '@/internal/utils/AutoplayChecker'
|
||||
import * as languages from '@/languages.json'
|
||||
|
||||
type PlayerReadyHandler = (player: IVokaPlayer) => void
|
||||
|
||||
const playbackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]
|
||||
|
||||
export class VokaPlayerImpl implements IVokaPlayer {
|
||||
|
||||
private player!: VideoJsPlayer
|
||||
private autoPlaySupported!: boolean
|
||||
private readonly stateEmitter: EventBus
|
||||
|
||||
// Constructor
|
||||
constructor(element: HTMLElement, callback?: PlayerReadyHandler/*, options?: ICreationOptions*/) {
|
||||
const readyCallback = typeof callback === 'undefined' ? null : callback
|
||||
this.stateEmitter = new EventBus()
|
||||
/*this.stateEmitter.subscribe(
|
||||
playerStateChange,
|
||||
(data) => (this.state_ = data.payload.value)
|
||||
)*/
|
||||
|
||||
/*if (options) {
|
||||
window.vokaEnvironment = options
|
||||
}*/
|
||||
|
||||
AutoplayChecker.isAutoplaySupported((supported) => {
|
||||
this.setupPlayer(element, supported, readyCallback)
|
||||
})
|
||||
}
|
||||
|
||||
private setupPlayer(
|
||||
element: HTMLElement,
|
||||
autoPlaySupported: boolean,
|
||||
callback: PlayerReadyHandler | null
|
||||
) {
|
||||
|
||||
this.autoPlaySupported = autoPlaySupported
|
||||
videojs.log.level('debug')
|
||||
const options = this.initOptions()
|
||||
const player = videojs(element, options, () => {
|
||||
if (callback != null) {
|
||||
callback(this)
|
||||
}
|
||||
|
||||
this.player.play()
|
||||
// try load content just right after complete initialization.
|
||||
/*this.stateEmitter.publish(
|
||||
playerStateChange({ value: Initialized })
|
||||
)*/
|
||||
})
|
||||
|
||||
player.addClass('video-js')
|
||||
|
||||
/*if (userAgent.getDevice().type === DEVICE.MOBILE) {
|
||||
player.addClass('vjs-mobile')
|
||||
}*/
|
||||
|
||||
// Sign to events.
|
||||
this.setupAttachListeners(player)
|
||||
this.player = player
|
||||
}
|
||||
|
||||
private initOptions(): VideoJsPlayerOptions {
|
||||
// Required player's plugins.
|
||||
const plugins: Record<string, any> = { }
|
||||
//plugins.vokaQualityPlugin = {}
|
||||
//plugins.vokaStatisticsPlugin = {}
|
||||
//plugins.vokaAdvertisementPlugin = {}
|
||||
//plugins.vokaCaptionsPlugin = {}
|
||||
|
||||
const childrenComponents = [
|
||||
// Non-visual component, not in UI layer list.
|
||||
'mediaLoader' // Required loader, that load tech list!
|
||||
]
|
||||
|
||||
const skinChildren = [
|
||||
'resizeManager',
|
||||
'LoadingSpinner',
|
||||
'PosterImage',
|
||||
'RestrictionBox',
|
||||
'liveTracker',
|
||||
'textTrackDisplay'
|
||||
]
|
||||
|
||||
// Settings for player.
|
||||
return {
|
||||
controls: true, // Show controls.
|
||||
techOrder: [
|
||||
/*'VokaEmptyTech',
|
||||
'VokaAppleTech',
|
||||
'VokaMp4Tech',
|
||||
'VokaHlsTech',
|
||||
'VokaDashTech'*/
|
||||
'html5'
|
||||
], // Order for teches important.
|
||||
plugins, // Attached plugins for player.
|
||||
languages,
|
||||
language: 'ru',
|
||||
children: childrenComponents,
|
||||
poster: null,
|
||||
responsive: true,
|
||||
breakpoints: {
|
||||
tiny: undefined,
|
||||
xsmall: undefined,
|
||||
small: 559,
|
||||
medium: 1002,
|
||||
large: undefined,
|
||||
xlarge: undefined,
|
||||
huge: Infinity
|
||||
},
|
||||
playbackRates,
|
||||
sources: [
|
||||
{src: "//vjs.zencdn.net/v/oceans.mp4", type: "video/mp4"}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private setupAttachListeners(player: VideoJsPlayer) {
|
||||
// Добавляем листенеры здесь
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Check to see if the object is a DOM Element.
|
||||
*
|
||||
* @param {*} element The object to check.
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isDomElement(element: any): boolean {
|
||||
return Boolean(
|
||||
element &&
|
||||
element.nodeType === 1 &&
|
||||
'nodeName' in element &&
|
||||
element.ownerDocument &&
|
||||
element.ownerDocument.defaultView
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"ru": {
|
||||
"Play": "Смотреть",
|
||||
"Pause": "Пауза",
|
||||
"Replay": "Повторить",
|
||||
"Settings": "Настройки",
|
||||
"Fullscreen": "Развернуть",
|
||||
"Non-Fullscreen": "Свернуть",
|
||||
"Mute": "Отключить звук",
|
||||
"Unmute": "Включить звук",
|
||||
"Speed": "Скорость",
|
||||
"Subtitles": "Субтитры",
|
||||
"Off": "Выкл.",
|
||||
"Normal": "Обычная",
|
||||
"Auto": "Авто",
|
||||
"Quality": "Качество",
|
||||
"Error": "Ошибка",
|
||||
"Playback-error": "Ошибка проигрывания",
|
||||
"Seconds-short": "Cек"
|
||||
},
|
||||
"en": {
|
||||
"Play": "Play",
|
||||
"Pause": "Pause",
|
||||
"Replay": "Repeat",
|
||||
"Settings": "Settings",
|
||||
"Fullscreen": "Full screen",
|
||||
"Non-Fullscreen": "Exit full screen",
|
||||
"Mute": "Mute",
|
||||
"Unmute": "Unmute",
|
||||
"Speed": "Speed",
|
||||
"Subtitles": "Subtitles",
|
||||
"Off": "Off",
|
||||
"Normal": "Normal",
|
||||
"Auto": "Auto",
|
||||
"Quality": "Quality",
|
||||
"Error": "Error",
|
||||
"Playback-error": "Playback error",
|
||||
"Seconds-short": "Sec"
|
||||
}
|
||||
}
|
||||
+11
-10
@@ -1,11 +1,12 @@
|
||||
import videojs from 'video.js';
|
||||
import { VokaPlayer } from '@/public/VokaPlayer'
|
||||
import { IVokaPlayer } from '@/public/IVokaPlayer'
|
||||
|
||||
const player = videojs('my-video', {
|
||||
controls: true,
|
||||
autoplay: false,
|
||||
preload: 'auto'
|
||||
});
|
||||
|
||||
player.ready(() => {
|
||||
console.log('Your Video.js player is ready?!!');
|
||||
});
|
||||
console.log(VokaPlayer.version)
|
||||
const playerPromise = VokaPlayer.create('my-video')
|
||||
playerPromise
|
||||
.then((player) => {
|
||||
console.log(player)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ILogger } from '@/public/logger/ILogger'
|
||||
import { LogLevel } from '@/public/logger/Logger'
|
||||
|
||||
export interface ICreationOptions {
|
||||
// Включен ли дебаг режим
|
||||
debug?: boolean
|
||||
logger?: ILogger
|
||||
logLevel?: LogLevel
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
export enum VokaPlayerEvent {
|
||||
'DurationChange' = 'durationchange',
|
||||
'TimeUpdate' = 'timeupdate',
|
||||
'Pause' = 'pause',
|
||||
'Play' = 'play',
|
||||
'Playing' = 'playing',
|
||||
'Error' = 'error',
|
||||
'Ended' = 'ended',
|
||||
'VolumeChange' = 'volumechange',
|
||||
'LoadedMetaData' = 'loadedmetadata',
|
||||
'LoadStart' = 'loadstart',
|
||||
'LoadedData' = 'loadeddata',
|
||||
'FullscreenChange' = 'fullscreenchange',
|
||||
'RateChange' = 'ratechange',
|
||||
'Seeking' = 'seeking',
|
||||
'Seeked' = 'seeked',
|
||||
'Log' = 'log',
|
||||
'Waiting' = 'waiting',
|
||||
'CanPlay' = 'canplay',
|
||||
'CanPlayThrough' = 'canplaythrough',
|
||||
'QualitiesParsed' = 'qualitiesparsed',
|
||||
'QualityChange' = 'qualitychange'
|
||||
}
|
||||
|
||||
/*
|
||||
destroyed - object was destroyed
|
||||
sourceAttached - new stream source was set
|
||||
canplay - player is ready to play video
|
||||
play - video playback started/resumed
|
||||
pause - video playback paused
|
||||
ended - video playback finished (played until end)
|
||||
error - video playback error
|
||||
timeupdate - current stream position changed
|
||||
timeshiftUpdate - timeshift availability changed
|
||||
volumechange - audio volume changed
|
||||
bufferLengthUpdate - buffer length changed
|
||||
bufferingUpdate - buffering state changed
|
||||
qualityChange - current video quality changed
|
||||
trackChange - current audio/subtitles track changed
|
||||
zoomButtonChange - update visibility of zoom button
|
||||
zoomModeChange - update state of zoom mode
|
||||
timeNotify - reached stream/wall-clock position configured in timeNotify section of options
|
||||
adRequested - before ad loading is initiated
|
||||
adStarted - ad block started
|
||||
adFinished - ad block finished successfully
|
||||
adError - ad finished with error
|
||||
adItemStarted - one ad in ad block started
|
||||
adItemFinished - one ad in ad block finished successfully
|
||||
adItemError - one ad in ad block finished with error
|
||||
adImpression - ad impression happened
|
||||
disableAdsClick - user clicked disable ads button
|
||||
logoClick - user clicked on logo button
|
||||
controlbarShow - control bar is shown
|
||||
controlbarHide - control bar is hidden
|
||||
toolboxStartSel - toolbox start selection button was clicked
|
||||
toolboxEndSel - toolbox end selection button was clicked
|
||||
toolboxProcessSel - toolbox process selection button was clicked
|
||||
* */
|
||||
|
||||
export interface IVokaPlayer {
|
||||
/// addEventListener - add listener of specific event
|
||||
on(event: VokaPlayerEvent, callback: Function): void
|
||||
/// removeEventListener - remove listener of event
|
||||
off(event: VokaPlayerEvent, callback?: Function): void
|
||||
/// start/resume playing
|
||||
play(): Promise<void>
|
||||
/// pause playing
|
||||
pause(): Promise<void>
|
||||
stop(): Promise<void>
|
||||
}
|
||||
|
||||
/*
|
||||
load(url: string, options?: ILoadOptions): Promise<void>
|
||||
loadWithProvider(
|
||||
provider: IAPIProvider,
|
||||
options?: ILoadOptions
|
||||
): Promise<void>
|
||||
setCurrentTime(value: number): Promise<void>
|
||||
setVolume(value: number): Promise<void>
|
||||
setPlaybackRate(value: PlaybackRate): Promise<void>
|
||||
setViewType(value: string): Promise<void>
|
||||
setQuality(value: Quality): Promise<void>*/
|
||||
|
||||
/*
|
||||
* afterInitialize - register callback function that will be called after player is initialized (it will be called immediately if player is already initialized)
|
||||
* isInitialized - check if player is initialized
|
||||
* getProtocol - get supported streaming protocol name
|
||||
* getDrmSystem - get supported drm system name
|
||||
* isHlsSupported - check if HLS protocol is supported
|
||||
* getVideoCodecs - get list of supported video codecs for dash protocol (only among those that were enabled in config)
|
||||
* attachSource - set stream url and stream options
|
||||
* getPaused - get paused state
|
||||
* getIsLive - get live streaming flag
|
||||
* seek - seek stream to specific position, in seconds
|
||||
* getCurrentTime - get current stream position, in seconds
|
||||
* getDuration - get current stream duration, in seconds
|
||||
* getAbsoluteCurrentTime - get current utc unixtime for live streams
|
||||
* getAbsoluteTimeRange - get utc start/end range for live streams
|
||||
* getTimeshiftAvailable - check if timeshift is available
|
||||
* getVideoQualityList - get array with information about available video qualities
|
||||
* getSelectedVideoQuality - get index of currently selected video quality (-1 for auto)
|
||||
* getPlayingVideoQuality - get index of currently playing video quality (-1 if unknown)
|
||||
* setSelectedVideoQuality - set index of video quality to play (-1 for auto)
|
||||
* getAudioTrackList - get array of available audio tracks
|
||||
* getCurrentAudioTrack - get index of currently selected audio track
|
||||
* setCurrentAudioTrack - set index of audio track to play
|
||||
* getSubtitlesTrackList - get array of available subtitles tracks
|
||||
* getCurrentSubtitlesTrack - get index of currently selected subtitles track (-1 for disabled)
|
||||
* setCurrentSubtitlesTrack - set index of subtitles track to display (-1 to disable)
|
||||
* setSelectionStartPos - mark current position as selection start
|
||||
* setSelectionEndPos - mark current position as selection end
|
||||
* getSelectionRange - get currently selected range
|
||||
* getZoomButtonVisible - get zoom button visibility
|
||||
* getZoomModeEnabled - check if zoom mode is enabled
|
||||
* setZoomModeEnabled - enable/disable zoom mode (boolean argument)
|
||||
* setVolume - set audio volume
|
||||
* getVolume - get audio volume
|
||||
* mute - mute audio
|
||||
* unmute - unmute audio
|
||||
* getMuted - get muted state
|
||||
* getBufferLength - get length in seconds of buffered data
|
||||
* getNetworkBandwidth - get current network bandwidth in kbit/s
|
||||
* getBufferingState - wheither or not playback is stalled due to buffering
|
||||
* getCurrentVideoInfo - get information about currently playing video track
|
||||
* getControlbarVisible - get visibility state of control bar
|
||||
* getAdIsPlaying - player is currently loading/playing ads
|
||||
* cancelAdPlayback - cancel currently playing advertisement(s)
|
||||
* destroy - destroy "player" object
|
||||
*/
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ICreationOptions } from './@types'
|
||||
import { IVokaPlayer } from './IVokaPlayer'
|
||||
import { VokaPlayerImpl } from '@/internal/player/VokaPlayerImpl'
|
||||
import { LogLevel, Logger } from '@/public/logger/Logger'
|
||||
import { ConsoleLogger } from '@/public/logger/ConsoleLogger'
|
||||
import { isDomElement } from '../internal/utils/functions'
|
||||
|
||||
/*
|
||||
* player = spbtvplayer('some_id', {});
|
||||
player.afterInitialize(readyFunc);
|
||||
|
||||
function readyFunc() {
|
||||
}
|
||||
* */
|
||||
|
||||
export class VokaPlayer {
|
||||
|
||||
static readonly version = '0.0.1'
|
||||
|
||||
public static create(
|
||||
element: HTMLElement | string,
|
||||
options?: ICreationOptions
|
||||
): Promise<IVokaPlayer> {
|
||||
|
||||
let elem = element
|
||||
// Если указанный элемент - строка, ищем html-элемент по id
|
||||
if (typeof document !== 'undefined' && typeof elem === 'string') {
|
||||
elem = document.getElementById(elem) as HTMLElement
|
||||
}
|
||||
|
||||
// Если не валидный DOM-элемент
|
||||
if (!isDomElement(elem)) {
|
||||
return Promise.reject(
|
||||
new TypeError('You must pass either a valid element or a valid id.')
|
||||
)
|
||||
}
|
||||
|
||||
if (options && options.debug) {
|
||||
const logger = options.logger ? options.logger : new ConsoleLogger()
|
||||
const logLevel = options.logLevel ? options.logLevel : LogLevel.Debug
|
||||
Logger.getInstance().setHandler(logger, logLevel)
|
||||
}
|
||||
|
||||
// Если элемент - iframe
|
||||
if ((elem as HTMLElement).nodeName == 'IFRAME') {
|
||||
return Promise.reject(
|
||||
new TypeError('Can not use iframe as player container.')
|
||||
)
|
||||
}
|
||||
|
||||
return new Promise<IVokaPlayer>((resolve) => {
|
||||
new VokaPlayerImpl(elem, (player) => {
|
||||
resolve(player)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { ILogger } from '@/public/logger/ILogger'
|
||||
|
||||
export class ConsoleLogger implements ILogger {
|
||||
debug(message: string): void {
|
||||
console.debug(message)
|
||||
}
|
||||
|
||||
error(message: string): void {
|
||||
console.error(message)
|
||||
}
|
||||
|
||||
info(message: string): void {
|
||||
console.info(message)
|
||||
}
|
||||
|
||||
warning(message: string): void {
|
||||
console.warn(message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface ILogger {
|
||||
debug(message: string): void
|
||||
info(message: string): void
|
||||
warning(message: string): void
|
||||
error(message: string): void
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { ILogger } from './ILogger'
|
||||
|
||||
export enum LogLevel {
|
||||
'Debug' = 'debug',
|
||||
'Info' = 'info',
|
||||
'Warning' = 'warning',
|
||||
'Error' = 'error'
|
||||
}
|
||||
|
||||
export class Logger {
|
||||
private handler?: ILogger
|
||||
private logLevel: LogLevel
|
||||
private static instance: Logger
|
||||
|
||||
private constructor() {
|
||||
this.handler = undefined
|
||||
}
|
||||
|
||||
static getInstance(): Logger {
|
||||
if (!Logger.instance) {
|
||||
Logger.instance = new Logger()
|
||||
}
|
||||
return Logger.instance
|
||||
}
|
||||
|
||||
setHandler(logger: ILogger, logLevel: LogLevel): void {
|
||||
this.handler = logger
|
||||
this.logLevel = logLevel
|
||||
|
||||
window.addEventListener('message', (e: MessageEvent) => {
|
||||
try {
|
||||
if (!e.data) return
|
||||
if (typeof e.data !== 'string') return
|
||||
const pmData = JSON.parse(e.data)
|
||||
if (pmData.type === 'player:log') {
|
||||
if (!this.checkLevel(pmData?.data?.level)) return
|
||||
// @ts-ignore
|
||||
this.handler[pmData?.data?.level](pmData?.data?.message)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
debug(message: string): void {
|
||||
if (!this.checkLevel(LogLevel.Debug)) return
|
||||
this.handler?.debug(message)
|
||||
}
|
||||
|
||||
error(message: string): void {
|
||||
if (!this.checkLevel(LogLevel.Error)) return
|
||||
this.handler?.error(message)
|
||||
}
|
||||
|
||||
info(message: string): void {
|
||||
if (!this.checkLevel(LogLevel.Info)) return
|
||||
this.handler?.info(message)
|
||||
}
|
||||
|
||||
warning(message: string): void {
|
||||
if (!this.checkLevel(LogLevel.Warning)) return
|
||||
this.handler?.warning(message)
|
||||
}
|
||||
|
||||
private checkLevel(logLevel: LogLevel): boolean {
|
||||
const levels = Object.values(LogLevel)
|
||||
const availableLevelIndex = levels.findIndex((value: LogLevel) => {
|
||||
return value === this.logLevel
|
||||
})
|
||||
const checkedLevelIndex = levels.findIndex((value: LogLevel) => {
|
||||
return value === logLevel
|
||||
})
|
||||
|
||||
return checkedLevelIndex >= availableLevelIndex
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
"lib": [
|
||||
"es2016",
|
||||
"dom"
|
||||
|
||||
Reference in New Issue
Block a user