Merge branch 'feature/65972-demos' into 'develop'

#65972 Доработать демки

See merge request ps/voka/voka-player-js!79
This commit is contained in:
Алексей Манаев
2025-07-31 08:31:53 +00:00
21 changed files with 519 additions and 6 deletions
+25
View File
@@ -14,10 +14,16 @@
<button onclick="changeQualityAuto()" type="button">AUTO QUALITY</button>
<button onclick="changeQualityLowest()" type="button">LOWEST QUALITY</button>
<button onclick="changeQualityBest()" type="button">BEST QUALITY</button>
<button onclick="setEngAudioTrack()" type="button">ENGLISH AUDIO</button>
<button onclick="setDubAudioTrack()" type="button">DUBBING AUDIO</button>
<button onclick="disableSubs()" type="button">DISABLE SUBS</button>
<button onclick="setDeSubs()" type="button">DEUTCH SUBS</button>
<button onclick="setEnSubs()" type="button">ENGLISH SUBS</button>
<h2>Logs</h2>
<div id="logs" class="logs"></div>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
log: true,
features: {
api: true,
drm: false,
@@ -98,6 +104,25 @@
player.setSelectedVideoQuality(quality.length - 1)
}
function setDubAudioTrack() {
player.setCurrentAudioTrack(1)
}
function setEngAudioTrack() {
player.setCurrentAudioTrack(0)
}
function disableSubs() {
player.setCurrentSubtitlesTrack(-1)
}
function setDeSubs() {
player.setCurrentSubtitlesTrack(0)
}
function setEnSubs() {
player.setCurrentSubtitlesTrack(1)
}
const fireEvents = [
'play',
+89
View File
@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
</head>
<body>
<h1>Hello world</h1>
<div id="my-video"></div>
<div class="btns bnts--audio"></div>
<div class="btns btns--subs"></div>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
features: {
api: true,
drm: false,
metrics: true
},
apiConfig: {
channelId: 'dash-audio-0aec531fc01',
clientId: null,
movieId: null,
episodeId: null,
newsId: null,
apiHost: 'localhost:8080',
},
controls: {
zoomButton: {
isVisible: true,
enable: true,
},
},
});
function setActiveAudio(index) {
player.setCurrentAudioTrack(index);
}
function setActiveSubtitle(index) {
player.setCurrentSubtitlesTrack(index);
}
function addAudioBtns() {
const list = player.getAudioTrackList()
const parent = document.querySelector('.btns.bnts--audio')
if (!parent || !list.length) return
list.forEach(element => {
parent.insertAdjacentHTML('beforeend',
`<button onclick="setActiveAudio(${element.index})">${element.label}</button>`
);
});
}
function addSubtitlesBtns() {
const list = player.getSubtitlesTrackList()
const parent = document.querySelector('.btns.btns--subs')
if (!parent || !list.length) return
parent.insertAdjacentHTML('beforeend',
`<button onclick="setActiveSubtitle(-1)">выкл</button>`
);
list.forEach(element => {
parent.insertAdjacentHTML('beforeend',
`<button onclick="setActiveSubtitle(${element.index})">${element.label}</button>`
);
});
}
player.addEventListener("canplay", () => {
addAudioBtns();
addSubtitlesBtns();
})
</script>
<style>
.btns {
padding: 10px 0;
display: flex;
align-items: center;
gap: 10px;
}
.btns button {
font-size: 24px;
}
</style>
</body>
</html>
+63
View File
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
</head>
<body>
<h1>Hello world</h1>
<p>
Демка показывает возможность переключения аудио дорожек на dash live
</p>
<p>
Свежий исходник (ссылку на поток) брать тут https://voka.tv/ru-RU/channels/black
</p>
<div id="my-video"/>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
features: {
api: true,
drm: false,
metrics: true
},
apiConfig: {
channelId: 'dash-live-audio-voka',
clientId: null,
movieId: null,
episodeId: null,
newsId: null,
apiHost: 'localhost:8080',
},
uiConfig: {
initAsLive: true
},
globalOpts: {
uiLanguage: 'ru'
},
streamOpts: {
autoplay: true
},
controls: {
zoomButton: {
isVisible: true,
enable: true,
},
},
});
var count = 0
var timer = setInterval(
() => {
console.log(player.getCurrentVideoInfo())
console.log(player.getNetworkBandwidth())
count++
if (count > 5) {
clearInterval(timer)
}
},
3000
)
</script>
</body>
</html>
+11
View File
@@ -8,8 +8,11 @@
<body>
<h1>Hello world</h1>
<div id="my-video"/>
<button onclick="setBeAudioTrack()" type="button">Be</button>
<button onclick="setRuAudioTrack()" type="button">Ru</button>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
log: true,
features: {
api: true,
drm: false,
@@ -51,6 +54,14 @@
},
3000
)
function setBeAudioTrack() {
player.setCurrentAudioTrack(0)
}
function setRuAudioTrack() {
player.setCurrentAudioTrack(1)
}
</script>
</body>
</html>
+64
View File
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
</head>
<body>
<h1>Hello world</h1>
<p>
Демка показывает возможность воспроизведения dash widevine live с потоком voka
</p>
<p>
Свежий исходник (ссылку на поток) брать тут https://voka.tv/ru-RU/channels/souz
</p>
<div id="my-video"/>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
log: true,
features: {
api: true,
drm: true,
metrics: true
},
apiConfig: {
channelId: 'dash-widevine-live-voka',
clientId: null,
movieId: null,
episodeId: null,
newsId: null,
apiHost: 'localhost:8080',
},
uiConfig: {
initAsLive: true
},
globalOpts: {
uiLanguage: 'ru'
},
streamOpts: {
autoplay: true
},
controls: {
zoomButton: {
isVisible: true,
enable: true,
},
},
});
var count = 0
var timer = setInterval(
() => {
console.log(player.getCurrentVideoInfo())
console.log(player.getNetworkBandwidth())
count++
if (count > 5) {
clearInterval(timer)
}
},
3000
)
</script>
</body>
</html>
@@ -8,6 +8,9 @@
</head>
<body>
<h1>Hello world</h1>
<p>
Демка показывает как скрывается плеер, если не передан URL для воспроизведения
</p>
<div id="my-video"></div>
<button onclick="controlBarShow()" type="button">SHOW CONTROL BAR</button>
<button onclick="controlBarHide()" type="button">HIDE CONTROL BAR</button>
+64
View File
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
</head>
<body>
<h1>Hello world</h1>
<p>
Демка показывает возможность воспроизведения hls widevine vod
</p>
<p>
Исходник https://hlsjs.video-dev.org/demo/?src=https%3A%2F%2Fstorage.googleapis.com%2Fshaka-demo-assets%2Fangel-one-widevine-hls%2Fhls.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==
</p>
<div id="my-video"/>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
log: true,
features: {
api: true,
drm: true,
metrics: true
},
apiConfig: {
channelId: 'hls-fairplay-vod',
clientId: null,
movieId: null,
episodeId: null,
newsId: null,
apiHost: 'localhost:8080',
},
uiConfig: {
initAsLive: true
},
globalOpts: {
uiLanguage: 'ru'
},
streamOpts: {
autoplay: true
},
controls: {
zoomButton: {
isVisible: true,
enable: true,
},
},
});
var count = 0
var timer = setInterval(
() => {
console.log(player.getCurrentVideoInfo())
console.log(player.getNetworkBandwidth())
count++
if (count > 5) {
clearInterval(timer)
}
},
3000
)
</script>
</body>
</html>
+64
View File
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
<script language="JavaScript" src="./distribution/vokaPlayer.global.js"></script>
</head>
<body>
<h1>Hello world</h1>
<p>
Демка показывает возможность воспроизведения hls widevine vod
</p>
<p>
Исходник https://hlsjs.video-dev.org/demo/?src=https%3A%2F%2Fstorage.googleapis.com%2Fshaka-demo-assets%2Fangel-one-widevine-hls%2Fhls.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==
</p>
<div id="my-video"/>
<script language="JavaScript">
var player = spbtvplayer('my-video', {
log: true,
features: {
api: true,
drm: true,
metrics: true
},
apiConfig: {
channelId: 'hls-widevine-vod',
clientId: null,
movieId: null,
episodeId: null,
newsId: null,
apiHost: 'localhost:8080',
},
uiConfig: {
initAsLive: true
},
globalOpts: {
uiLanguage: 'ru'
},
streamOpts: {
autoplay: true
},
controls: {
zoomButton: {
isVisible: true,
enable: true,
},
},
});
var count = 0
var timer = setInterval(
() => {
console.log(player.getCurrentVideoInfo())
console.log(player.getNetworkBandwidth())
count++
if (count > 5) {
clearInterval(timer)
}
},
3000
)
</script>
</body>
</html>
@@ -1,7 +1,7 @@
{
"data": {
"url": "https://cdn.bitmovin.com/content/assets/sintel/sintel.mpd",
"subtitles": "https://raw.githubusercontent.com/videojs/video.js/c7298d40a4632a6e9dfcd5a2f5cc3bbe92a78744/docs/examples/elephantsdream/captions.ru.vtt",
"url": "https://streaming-iptv.voka.tv/eyJvc19uYW1lIjoibWFjIG9zIiwidXNlcl91aWQiOiIzMDE4ZmM2Yi02YmY4LTQ4OGQtOGRhMi02YjZmNWFmMjFjNDQiLCJkYXRhY2VudGVyIjoiaW50IiwiZG9tYWluX25hbWUiOiJzdHJlYW1pbmctaXB0di52b2thLnR2IiwiZHJtIjoic3BidHZjYXMiLCJleHBpcmF0aW9uX2RhdGUiOiIyMDI1LTA3LTMxVDE3OjU4OjI0WiIsImlwX2FkZHJlc3MiOiIxODUuMTM1LjE1MC40MCIsInByb2plY3QiOiJ2b2thX3Byb2R1Y3Rpb24iLCJwcm90b2NvbCI6ImRhc2giLCJzZXNzaW9uX2lkIjoiZDgwYzI3NWEtYzgyMy00ZDBlLWJmZWMtMjc4OThmMDk2MTVmIiwic3RyZWFtX25hbWUiOiJKZzhlMzhLU0FMQkd3WmdCRmRUd2NnaWlMTjREUmQ2MTQiLCJzdHJlYW1fcGF0aCI6Ii92b2RfdjUvdmVsY29tIn0%3D/MCwCFDLqlcRbOWAPL1JtVK0aVFx8yLAbAhRPvbh4KWNsTtR1OzlVZ7n4jvdibA%3D%3D/vod_v5/velcom/Jg8e38KSALBGwZgBFdTwcgiiLN4DRd614.mpd?b_app_channel_id=ab4d0c69-f7f5-4293-b5a9-5769ab7e1939&b_app_id=voka_production&b_device_platform=mac%20os&b_device_uid=1d866e05-b0e5-e943-f49c-295ac85c20d7&b_stream_sid=d80c275a-c823-4d0e-bfec-27898f09615f&b_strmr_channel_id=Jg8e38KSALBGwZgBFdTwcgiiLN4DRd614",
"analytics_v2": {
"url": "https://juraldinio.com/analytics/",
"interval": 5000,
@@ -0,0 +1,16 @@
{
"data": {
"url": "https://cdn.bitmovin.com/content/assets/sintel/sintel.mpd",
"subtitles": "https://raw.githubusercontent.com/videojs/video.js/c7298d40a4632a6e9dfcd5a2f5cc3bbe92a78744/docs/examples/elephantsdream/captions.ru.vtt",
"analytics_v2": {
"url": "https://juraldinio.com/analytics/",
"interval": 5000,
"additional_parameters": {
"application_id": "42",
"user_id": "12321",
"resource_type": "video",
"watch_session_id": "100500"
}
}
}
}
@@ -0,0 +1,16 @@
{
"data": {
"url": "https://streaming-iptv.voka.tv/eyJvc19uYW1lIjoibWFjIG9zIiwidXNlcl91aWQiOiIzMDE4ZmM2Yi02YmY4LTQ4OGQtOGRhMi02YjZmNWFmMjFjNDQiLCJkYXRhY2VudGVyIjoiaW50IiwiZG9tYWluX25hbWUiOiJzdHJlYW1pbmctaXB0di52b2thLnR2IiwiZHJtIjoic3BidHZjYXMiLCJleHBpcmF0aW9uX2RhdGUiOiIyMDI1LTA3LTMxVDIwOjE2OjI3WiIsImlwX2FkZHJlc3MiOiIxODUuMTM1LjE1MC40MCIsInByb2plY3QiOiJ2b2thX3Byb2R1Y3Rpb24iLCJwcm90b2NvbCI6ImRhc2giLCJzZXNzaW9uX2lkIjoiN2JiMzc0MjctMTI5Ni00ZDRiLThiYjQtMzI0MzhjNDYzMzVmIiwic3RyZWFtX25hbWUiOiIzMDAxIiwic3RyZWFtX3BhdGgiOiIvaXBfdjUifQ%3D%3D/MCwCFHgVQ-7NXnl4esPKpubWQzSIy1FeAhQihHnFM0_8LSnoDPV7pe3xpSYlhg%3D%3D/ip_v5/3001.mpd?b_app_channel_id=d111d4a9-ef3e-4c1a-b8b8-06cb6800a136&b_app_id=voka_production&b_device_platform=mac%20os&b_device_uid=1d866e05-b0e5-e943-f49c-295ac85c20d7&b_stream_sid=7bb37427-1296-4d4b-8bb4-32438c46335f&b_strmr_channel_id=3001&stream_dvr_window=10800000000",
"subtitles": "https://raw.githubusercontent.com/videojs/video.js/c7298d40a4632a6e9dfcd5a2f5cc3bbe92a78744/docs/examples/elephantsdream/captions.ru.vtt",
"analytics_v2": {
"url": "https://juraldinio.com/analytics/",
"interval": 5000,
"additional_parameters": {
"application_id": "42",
"user_id": "12321",
"resource_type": "video",
"watch_session_id": "100500"
}
}
}
}
@@ -0,0 +1,20 @@
{
"data": {
"url": "https://streaming-iptv.voka.tv/eyJvc19uYW1lIjoibWFjIG9zIiwidXNlcl91aWQiOiIzMDE4ZmM2Yi02YmY4LTQ4OGQtOGRhMi02YjZmNWFmMjFjNDQiLCJkYXRhY2VudGVyIjoiaW50IiwiZG9tYWluX25hbWUiOiJzdHJlYW1pbmctaXB0di52b2thLnR2IiwiZHJtIjoid2lkZXZpbmUiLCJleHBpcmF0aW9uX2RhdGUiOiIyMDI1LTA3LTMxVDIwOjUxOjEzWiIsImlwX2FkZHJlc3MiOiIxODUuMTM1LjE1MC40MCIsInByb2plY3QiOiJ2b2thX3Byb2R1Y3Rpb24iLCJwcm90b2NvbCI6ImRhc2giLCJzZXNzaW9uX2lkIjoiM2MzYTkxMjMtY2VkZi00ODdmLWI4MzItZjhkYjNmNWZkMmY0Iiwic3RyZWFtX25hbWUiOiI1ODMiLCJzdHJlYW1fcGF0aCI6Ii9pcF92NSJ9/MCwCFAaa_NjyUSswHJxTYp3hATrVF-cFAhQFUugUrPqnUOYfpnkl5RuhIAcuSA%3D%3D/ip_v5/583.mpd?b_app_channel_id=7e8cedbe-5f18-4649-8468-dd5af597a670&b_app_id=voka_production&b_device_platform=mac%20os&b_device_uid=1d866e05-b0e5-e943-f49c-295ac85c20d7&b_stream_sid=3c3a9123-cedf-487f-b832-f8db3f5fd2f4&b_strmr_channel_id=583&stream_dvr_window=10800000000 ",
"drm": {
"type": "widevine",
"license_server": "https://drmproxy.voka.tv"
},
"subtitles": "https://raw.githubusercontent.com/videojs/video.js/c7298d40a4632a6e9dfcd5a2f5cc3bbe92a78744/docs/examples/elephantsdream/captions.ru.vtt",
"analytics_v2": {
"url": "https://juraldinio.com/analytics/",
"interval": 5000,
"additional_parameters": {
"application_id": "42",
"user_id": "12321",
"resource_type": "video",
"watch_session_id": "100500"
}
}
}
}
@@ -0,0 +1,21 @@
{
"data": {
"url": "https://codeeducation.akamaized.net/code/fullcycle/devops_20/01/01_introducao.mp4/fp/fairplay.m3u8",
"drm": {
"type": "fairplay",
"certificate_url": "https://codeeducation.akamaized.net/fairplay.cer",
"ksm_url": "https://fps.ezdrm.com/api/licenses/F6B15258-BC92-49EB-9CDF-DE9F121C13A5?customdata=MTQ0OmFyZ2VudGluYWx1aXpAZ21haWwuY29tOjY3MTE6Y291cnNlOmNvZGU="
},
"subtitles": "https://raw.githubusercontent.com/videojs/video.js/c7298d40a4632a6e9dfcd5a2f5cc3bbe92a78744/docs/examples/elephantsdream/captions.ru.vtt",
"analytics_v2": {
"url": "https://juraldinio.com/analytics/",
"interval": 5000,
"additional_parameters": {
"application_id": "42",
"user_id": "12321",
"resource_type": "video",
"watch_session_id": "100500"
}
}
}
}
@@ -0,0 +1,20 @@
{
"data": {
"url": "https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine-hls/hls.m3u8",
"drm": {
"type": "widevine",
"license_server": "https://cwip-shaka-proxy.appspot.com/no_auth"
},
"subtitles": "https://raw.githubusercontent.com/videojs/video.js/c7298d40a4632a6e9dfcd5a2f5cc3bbe92a78744/docs/examples/elephantsdream/captions.ru.vtt",
"analytics_v2": {
"url": "https://juraldinio.com/analytics/",
"interval": 5000,
"additional_parameters": {
"application_id": "42",
"user_id": "12321",
"resource_type": "video",
"watch_session_id": "100500"
}
}
}
}
@@ -126,7 +126,9 @@ class SubtitlesButton extends MenuButton {
this.items.forEach((child: SubtitlesItem) => child.selected(false))
this.tracks_.forEach((tr: any) => {
tr.mode = 'hidden'
tr.track.mode = 'hidden'
if (tr.track) {
tr.track.mode = 'hidden'
}
})
}
+27
View File
@@ -258,6 +258,32 @@ namespace VokaCorePlayer {
playableContent = {
sourceType: "application/vnd.apple.mpegurl",
}
if (!drm) break
switch (drm.type) {
case DRMType.WIDEVINE:
playableContent["drmSystems"] = {
'com.widevine.alpha': {
licenseUrl: drm.certificateUrl,
}
}
break
case DRMType.PLAYREADY:
playableContent["drmSystems"] = {
'com.microsoft.playready': {
licenseUrl: drm.certificateUrl,
}
}
break
// Подержка FP в hls.js
case DRMType.FAIRPLAY:
playableContent["drmSystems"] = {
'com.apple.fps': {
certificateUrl: drm.certificateUrl,
licenseUrl: drm.licenseUrl,
}
}
break
}
break
case VokaContentType.MP4:
playableContent = {
@@ -299,6 +325,7 @@ namespace VokaCorePlayer {
}
}
break
// Нативный FP (Safari & iOS)
case VokaContentType.FAIRPLAY:
if (drm != null && drm.type == DRMType.FAIRPLAY) {
playableContent = {
@@ -46,6 +46,8 @@ interface IVokaSource {
protection: AppleSourceProtection | null
webOSProtection: WebOSSourceProtection | null
tizenParams: TizenSourceParams | null
// hls.js DRM options (widevine, playready, fireplay)
drmSystems: any
}
type VokaOptionsType = { [key: string]: any }
@@ -10,6 +10,7 @@ export interface IHlsLoadContext {
url: string
isLive: boolean
isDVR: boolean
drmSystems?: any
forceStart: boolean
startLevel: number | undefined
@@ -22,6 +23,7 @@ export default class HlsLoadContext implements IHlsLoadContext {
public url = ''
public isLive = false
public isDVR = false
public drmSystems = null
public forceStart = false
public startLevel: number | undefined = undefined
@@ -167,7 +167,9 @@ export default class HlsProcessor {
timeoutRetry: null,
errorRetry: null
}
}
},
emeEnabled: !!data.drmSystems,
drmSystems: data.drmSystems
}
const hls = new Hls(config)
@@ -274,6 +276,7 @@ export default class HlsProcessor {
Hls.Events.ERROR,
(event: Events, data: ErrorData) => {
console.error('test error', data)
this.play()
this.errorHandlers.handle(
{ event, data },
@@ -397,7 +397,8 @@ class VokaHlsTech extends VokaTech.Tech {
manifest: Environment.shared().timeout.manifest,
track: Environment.shared().timeout.track,
chunk: Environment.shared().timeout.chunk
}
},
drmSystems: source.drmSystems
})
)
} else {
+2 -2
View File
@@ -298,9 +298,9 @@ namespace VokaApi {
certificateUrl: params['certificate_url'],
keyServerUrl: params['ksm_url']
} as IDRMConfig
} else if (type == 'playready' && params['license_server'] != null) {
} else if ((type == 'playready' || type == 'widevine') && params['license_server'] != null) {
return {
type: 'playready',
type: type,
certificateUrl: params['license_server'],
} as IDRMConfig
}