PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 4.8.2
WpStream – Live Streaming, Video on Demand, Pay Per View v4.8.2
4.14.1 4.14.0 4.13.2 4.13.1 4.13 4.12.5 4.12.4 4.12.3 4.12.2 4.12.1 4.12 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5 4.5.1 4.5.11 4.5.11.1 4.5.11.2 4.5.11.4 4.5.11.5 4.5.11.6 All 181 releases
wpstream / public / js / wpstream-player.js

wpstream-player.js in WpStream – Live Streaming, Video on Demand, Pay Per View 4.8.2, at public/js/wpstream-player.js

1,465 lines 42.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 * To change this license header, choose License Headers in Project Properties.
3 * To change this template file, choose Tools | Templates
4 * and open the template in the editor.
5 * player,'.$live_event_uri_final.','.$live_conect_views.'
6 */
7
8 window.WebSocket = window.WebSocket || window.MozWebSocket;
9 if (!window.WebSocket) {
10 console.log("Sorry, but your browser does not support WebSockets");
11 }
12
13 function wpstream_player_initialize(settings) {
14 const player = new WpstreamPlayer(settings);
15 }
16
17 class WpstreamPlayer {
18 // id;
19 // trailerUrl;
20 // contentUrl;
21 // statsUri;
22 // autoplay;
23 // ruler = 0; //0 - basic; 1 - ajax; 2 - ws
24 // state = -1;
25 //-1 - unknown
26 // 0 - stopped
27 // 1 - notstarted
28 // 2 - started
29 // 4 - init
30 // 5 - paused
31 // 6 - startup
32 // 7 - onair
33 // 9 - ended
34 // 10 - finished
35
36 // liveConnect;
37 // wrapper;
38 // counter;
39 // chat;
40
41 constructor(settings) {
42 console.log("[]WpstreamPlayer: ", settings);
43 this.settings = settings;
44 this.id = settings.videoElementId;
45 this.trailerUrl = settings.trailerUrl;
46 this.contentUrl = settings.contentUrl;
47 this.statsUri = settings.statsUri;
48 this.autoplay = settings.autoplay;
49 this.playTrailerButton = jQuery(`#${settings.playTrailerButtonElementId}`);
50 this.muteTrailerButton = jQuery(`#${settings.muteTrailerButtonElementId}`);
51 this.unmuteTrailerButton = jQuery(
52 `#${settings.unmuteTrailerButtonElementId}`
53 );
54 this.titleOverlay = document.getElementById(settings.titleOverlayElementId);
55 this.liveConnect = new LiveConnect(this);
56 this.wrapper = jQuery("#wpstream_live_player_wrapper" + this.id);
57 console.log("wrapper: ", this.wrapper);
58 this.channelId = this.wrapper.attr("data-product-id");
59 console.log("channelId: ", this.channelId);
60 this.playback = new WpstreamPlayback(this, this.id, this.autoplay);
61 this.counter = new LiveCounter(this.wrapper, this.id);
62 this.liveMessage = new WpstreamLiveMessage(this.wrapper, this.id);
63 this.chat = new WpstreamChat();
64 this.setRuler(1);
65
66
67 let player = this.playback.player;
68 console.log("player: ", player);
69 let playerElement = player.el();
70 if (this.titleOverlay){
71 playerElement.appendChild(this.titleOverlay);
72 }
73 // console.log("playerElement: ", playerElement);
74 let playerParentElement = playerElement.parentNode;
75
76 if (
77 playerParentElement.classList.contains(
78 "wpstream_simple_player_shortcode_wrapper"
79 )
80 ) {
81 settings.trailerUrl = null;
82 }
83
84
85 if (settings.trailerUrl) {
86 const owner = this;
87 this.playTrailerButton.on("click", function () {
88 console.log("playTrailer()");
89 owner.playTrailerButton.hide();
90 owner.playback.playTrailer(owner.trailerUrl, true);
91 });
92 this.muteTrailerButton.on("click", function () {
93 owner.playback.player.muted(true);
94 });
95 this.unmuteTrailerButton.on("click", function () {
96 owner.playback.player.muted(false);
97 });
98 }
99 this.playTrailerButton.hide();
100 }
101
102 setRuler(ruler) {
103 console.log("setRuler: " + ruler);
104 let oldRuler = this.ruler;
105 console.log("oldRuler: ", oldRuler);
106 this.ruler = ruler;
107 switch (ruler) {
108 case 1:
109 if (oldRuler != 1) {
110 this.getDynamicSettings();
111 }
112 clearTimeout(this.retrieveDynamicSettingsTimeout);
113 let self = this;
114 this.retrieveDynamicSettingsTimeout = setTimeout(
115 () => self.getDynamicSettings(),
116 30 * 1000
117 );
118 break;
119 case 2:
120 clearTimeout(this.retrieveDynamicSettingsTimeout);
121 break;
122 }
123 }
124
125 getDynamicSettings() {
126 console.log("getDynamicSettings()");
127 let ajaxurl = wpstream_player_vars.admin_url + "admin-ajax.php";
128 let owner = this;
129 jQuery.ajax({
130 type: "POST",
131 url: ajaxurl,
132 dataType: "json",
133 data: {
134 action: "wpstream_player_check_status",
135 channel_id: this.channelId,
136 },
137 success: function (data) {
138 console.log("dynamicSettings: ", data);
139 if (data == 0) {
140 owner.setState("stopped");
141 } else if (data.started == "no") {
142 owner.setState("notstarted");
143 owner.chat.disconnect();
144 } else if (data.started == "yes") {
145 let liveConnectUri = data.live_conect_views;
146 owner.liveConnect.setup(liveConnectUri);
147 let contentUrl = data.event_uri;
148 owner.setState("started");
149 owner.setContentSrc(contentUrl);
150 owner.chat.connect(data.chat_url);
151 }
152 },
153 error: function (error) {
154 console.log("dynamicSettingsError: ", error);
155 },
156 });
157 if (this.ruler <= 1) {
158 this.setRuler(1);
159 }
160 }
161
162 setContentSrc(uri) {
163 this.playback.setContentSrc(uri);
164 }
165
166 setState(state) {
167 console.log("setState: ", state);
168 const oldState = this.state;
169 console.log("oldState: ", oldState);
170 this.state = state;
171
172 if (
173 this.trailerUrl &&
174 state != "onair" &&
175 state != "started" &&
176 state != "startup"
177 ) {
178 this.playback.playTrailer(this.trailerUrl);
179 }
180
181 this.liveMessage.show();
182 switch (state) {
183 case "stopped":
184 case "notstarted":
185 case "starting":
186 this.liveMessage.showMessage('stopped');
187 this.playback.pauseContent();
188 break;
189 case "started":
190 this.liveMessage.hide();
191 break;
192 case "init":
193 case "paused":
194 this.liveMessage.showMessage(state);
195 this.playback.pauseContent();
196 break;
197 case "ended":
198 this.liveMessage.showMessage(state);
199 this.playback.pauseContent(true);
200 break;
201 case "startup":
202 this.liveMessage.showMessage(state);
203 if (oldState != "onair") {
204 this.playback.pauseContent();
205 }
206 break;
207 case "onair":
208 this.liveMessage.hide();
209 this.playback.playContent();
210 break;
211 }
212 }
213
214 showHideMuteTrailerButtons() {
215 console.log("showHideMuteTrailerButtons()");
216 console.log("playingTrailer: ", this.playback.playingTrailer);
217 console.log("muted: ", this.playback.player.muted());
218 if (this.playback.playingTrailer) {
219 if (this.playback.player.muted()) {
220 this.muteTrailerButton.hide();
221 this.unmuteTrailerButton.show();
222 } else {
223 this.muteTrailerButton.show();
224 this.unmuteTrailerButton.hide();
225 }
226 } else {
227 this.muteTrailerButton.hide();
228 this.unmuteTrailerButton.hide();
229 }
230 }
231
232 onLiveConnectActive(isActive) {
233 console.log("onLiveConnectActive: ", isActive);
234 this.setRuler(isActive ? 2 : 1);
235 if (!isActive) {
236 this.counter.hide();
237 }
238 }
239
240 updateViewerCount(count) {
241 console.log("updateViewerCount: ", count);
242 this.counter.setCount(count);
243 }
244
245 updatePending(place){
246 console.log("updatePending: ", place);
247 this.counter.showPending(place);
248 }
249
250 showTitleOverlay(show = true) {
251 if (this.titleOverlay){
252 this.titleOverlay.style.opacity = show ? '1' : '0';
253 }
254 }
255 }
256
257 class WpstreamPlayback {
258 // player;
259 // timeQueue = [];
260 // master;
261 // paused = false;
262 // played = false;
263
264 constructor(master, id, autoplay) {
265 this.timeQueue = [];
266 this.paused = false;
267 this.played = false;
268 this.contentSrc = null;
269 this.trailerState = "notstarted";
270 this.playingTrailer = false;
271 this.master = master;
272 this.setupBasePlayer(id, autoplay);
273 this.runWatchdog();
274 this.qoe = new Qoe(master.liveConnect.sendQoeData, master.liveConnect);
275 }
276
277 setupBasePlayer(id, autoplay) {
278 console.log("setupBasePlayer: ", id, autoplay);
279 let contentUrl = this.master.contentUrl;
280 console.log("contentUrl: ", contentUrl);
281 let llhls = isLlHls(contentUrl);
282 console.log("llhls: ", llhls);
283 this.player = videojs("wpstream-video" + id, {
284 html5: {
285 vhs: {
286 useBandwidthFromLocalStorage: true,
287 limitRenditionByPlayerDimensions: false,
288 useDevicePixelRatio: true,
289 overrideNative: !videojs.browser.IS_SAFARI,
290 cacheEncryptionKeys: true,
291 llhls,
292 },
293 },
294 errorDisplay: false,
295 autoplay: autoplay,
296 preload: "auto",
297 // muted : true
298 });
299
300 this.applyTheme(wpstream_player_vars.wpstream_player_theme)
301
302 if ( typeof this.player.logo === 'function' && wpstream_player_vars.playerLogoSettings ) {
303 this.player.logo({
304 image: wpstream_player_vars.playerLogoSettings.imageUrl,
305 position: wpstream_player_vars.playerLogoSettings.position,
306 width: 100,
307 height: 'auto',
308 opacity: parseFloat(wpstream_player_vars.playerLogoSettings.opacity)/100,
309 padding: 10,
310 });
311 }
312
313 if (this.master.settings.theaterModeButtons) {
314 const Button = videojs.getComponent("Button");
315 const owner = this;
316
317 class TheaterModeEnterButton extends Button {
318 constructor(player, options) {
319 super(player, options);
320 this.controlText("Switch to Theater Mode");
321 this.addClass(
322 owner.master.settings.theaterModeButtons.enterTheaterModeButton.skin
323 );
324 }
325 handleClick() {
326 owner.theaterModeEnterButton.hide();
327 owner.theaterModeLeaveButton.show();
328 console.log("entering Theater Mode...");
329 eval(
330 owner.master.settings.theaterModeButtons.enterTheaterModeButton
331 .callback
332 );
333 }
334 }
335 class TheaterModeLeaveButton extends Button {
336 constructor(player, options) {
337 super(player, options);
338 this.controlText("Switch to Normal Mode");
339 this.addClass(
340 owner.master.settings.theaterModeButtons.leaveTheaterModeButton.skin
341 );
342 }
343 handleClick() {
344 owner.theaterModeEnterButton.show();
345 owner.theaterModeLeaveButton.hide();
346 console.log("leaving Theater Mode...");
347 eval(
348 owner.master.settings.theaterModeButtons.leaveTheaterModeButton
349 .callback
350 );
351 }
352 }
353
354 videojs.registerComponent(
355 "TheaterModeEnterButton",
356 TheaterModeEnterButton
357 );
358 videojs.registerComponent(
359 "TheaterModeLeaveButton",
360 TheaterModeLeaveButton
361 );
362 this.theaterModeEnterButton = owner.player
363 .getChild("controlBar")
364 .addChild("TheaterModeEnterButton", {}, 17);
365 this.theaterModeLeaveButton = owner.player
366 .getChild("controlBar")
367 .addChild("TheaterModeLeaveButton", {}, 18);
368 this.theaterModeLeaveButton.hide();
369 }
370
371 // this.player.controls(false);
372 this.player.bigPlayButton.hide();
373 // player.controlBar.progressControl.hide();
374 const owner = this;
375
376 this.player.on('useractive', function() {
377 owner.master.showTitleOverlay();
378 });
379
380 this.player.on('userinactive', function() {
381 owner.master.showTitleOverlay(false);
382 });
383
384 this.player.on("play", function (event) {
385 console.log("Play");
386
387 if (this.userActive()) {
388 owner.master.showTitleOverlay();
389 }
390
391 owner.played = true;
392 console.log("src: ", owner.player.currentSrc());
393 console.log("playingTrailer: ", owner.playingTrailer);
394 if (owner.playingTrailer) {
395 console.log("trailerState: ", owner.trailerState);
396 if (owner.trailerState == "attempted") {
397 owner.trailerState = "playing";
398 owner.master.liveMessage.showAtBottom(true);
399 }
400 showDomElements('playing_trailer', owner.player.el());
401 } else {
402 showDomElements('playing_content', owner.player.el());
403 }
404 owner.master.playTrailerButton.hide();
405 owner.master.showHideMuteTrailerButtons();
406 });
407 this.player.on("pause", function (event) {
408 console.log("Pause");
409 });
410 this.player.on("ended", () => {
411 console.log("Ended");
412 console.log("playingTrailer: ", this.playingTrailer);
413 if (this.playingTrailer) {
414 showDomElements('idle', owner.player.el());
415 owner.stopTrailer();
416 } else {
417 console.log("content ended");
418 this.player.controls(false);
419 this.player.hasStarted(false);
420 }
421 this.master.showHideMuteTrailerButtons();
422 });
423 this.player.on("durationchange", () => {
424 const duration = this.player.duration();
425 console.log("durationchange: ", duration);
426 if (duration > 0 && duration < Infinity) {
427 this.player.controls(false);
428 }
429 });
430 this.player.on("error", (error) => {
431 console.log("error: ", error);
432 });
433 this.player.on("volumechange", () => {
434 console.log("muted: ", this.player.muted());
435 this.master.showHideMuteTrailerButtons();
436 });
437
438 console.log("src: ", this.player.currentSrc());
439 // setTimeout(() => {
440 // this.player.bigPlayButton.show();
441 // }, 2000);
442
443 this.player.on("play", () => {
444 if (!this.playingTrailer) this.qoe.play();
445 });
446 this.player.on("pause", () => {
447 if (!this.playingTrailer) this.qoe.pause();
448 });
449 this.player.on("waiting", () => {
450 if (!this.playingTrailer) this.qoe.waiting();
451 });
452 this.player.on("playing", () => {
453 if (!this.playingTrailer)this.qoe.playing();
454 });
455 this.player.on("loadeddata", () => {
456 if (!this.playingTrailer)this.qoe.loadeddata();
457 });
458 this.player.on("resolutionchange", () => {
459 if (!this.playingTrailer)this.qoe.resolutionchange();
460 });
461 this.player.on("ended", () => {
462 if (!this.playingTrailer)this.qoe.ended();
463 });
464 this.player.on("error", () => {
465 if (!this.playingTrailer) this.qoe.error();
466 });
467 }
468
469 applyTheme(themeName) {
470 const themes = ['vjs-theme-city', 'vjs-theme-forest', 'vjs-theme-sunset', 'vjs-theme-sea'];
471 themes.forEach(theme => {
472 this.player.removeClass(theme);
473 })
474
475 this.player.addClass(`vjs-theme-${themeName}`);
476 }
477
478 initThemeSelector() {
479 const Button = videojs.getComponent('Button');
480 const owner = this;
481
482 }
483
484 playTrailer(src, click) {
485 console.log("### playTrailer: ", src, click);
486 console.log("trailerState: ", this.trailerState);
487 // if (this.trailerState == 'notstarted' || this.trailerState == 'attempted'){
488
489 if (this.trailerState == "notstarted" && !click) {
490 this.master.playTrailerButton.show();
491 }
492
493 if (this.trailerState == "notstarted" || click) {
494 this.playingTrailer = true;
495 const player = this.player;
496 player.controls(false);
497 player.src({ src });
498 if (click) {
499 player.play();
500 // showDomElements('playing_trailer'); //probably not needed
501 }
502 this.trailerState = "attempted";
503 }
504 }
505
506 stopTrailer() {
507 console.log("stopTrailer()");
508 console.log("trailerState: ", this.trailerState);
509 if (this.trailerState == "playing") {
510 console.log("trailer has ended");
511 this.trailerState = "ended";
512 this.master.liveMessage.showAtBottom(false);
513 this.player.hasStarted(false);
514 }
515 this.playingTrailer = false;
516 }
517
518 setContentSrc(src, force) {
519 console.log("### setContentSrc: ", src, force);
520 console.log("currentSrc: ", this.player.currentSrc());
521 console.log("paused: ", this.player.paused());
522 console.log("currentTime: ", this.player.currentTime());
523 this.playingTrailer = false;
524 this.contentSrc = src;
525
526 const owner = this;
527 clearTimeout(this.setSrcTimeout);
528 this.setSrcTimeout = setTimeout(
529 () => {
530 console.log("setting src...");
531 // src = src != null ? src : owner.player.currentSrc()
532 // owner.player.src({
533 // src,
534 // type: "application/x-mpegURL",
535 // llhls: isLlHls(src)
536 // });
537 // owner.playContent(force);
538 },
539 force ? 1 : 2000
540 );
541
542 // this.player.controlBar.show();
543 // this.player.loadingSpinner.show();
544 this.player.controls(true);
545 // this.player.muted(true);
546 // this.player.play();
547 }
548
549 playContent(forced) {
550 console.log("playContent() ", forced);
551 this.paused = false;
552 this.stopTrailer();
553 this.playingTrailer = false;
554 this.master.playTrailerButton.hide();
555 this.player.bigPlayButton.show();
556 clearTimeout(this.setSrcTimeout);
557 console.log("player.paused: ", this.player.paused());
558 console.log("currentTime: ", this.player.currentTime());
559 console.log("objectivelyPlayingContent: ", this.objectivelyPlayingContent);
560
561 // if (this.player.paused() || forced || this.player.currentTime() === 0){
562 if (!this.objectivelyPlayingContent || forced) {
563 this.player.src({
564 src: this.contentSrc,
565 type: "application/x-mpegURL",
566 llhls: isLlHls(this.contentSrc),
567 });
568 console.log("autoplay: ", this.player.autoplay());
569 // this.player.currentTime(0);
570 console.log("played: ", this.played);
571 if (this.played) {
572 var promise = this.player.play();
573 // console.log("promise: ", promise);
574 let player = this.player;
575 if (promise !== undefined) {
576 promise
577 .then(function () {
578 console.log("Autoplay started ;)");
579 })
580 .catch(function (error) {
581 console.log("Autoplay did not work ", error);
582 });
583 }
584 console.log("no promise");
585 }
586 }
587 this.player.controlBar.show();
588 this.player.loadingSpinner.show();
589 this.player.controls(true);
590 }
591
592 pauseContent(stop) {
593 console.log("pauseContent()");
594 this.paused = true;
595 clearTimeout(this.setSrcTimeout);
596 console.log("playingTrailer: ", this.playingTrailer);
597 if (!this.playingTrailer) {
598 console.log("paused: ", this.player.paused());
599 this.player.pause();
600 console.log("currentTime: ", this.player.currentTime());
601 this.player.controlBar.hide();
602 this.player.loadingSpinner.hide();
603 this.player.controls(false);
604 if (stop) {
605 this.player.hasStarted(false);
606 }
607 }
608 }
609
610 runWatchdog() {
611 //console.log("runWatchdog()");
612 const currentTime = this.player.currentTime();
613 this.timeQueue.push(currentTime);
614
615 var objectivelyPlayingContent = false;
616 if (currentTime > 0 && !this.playingTrailer) {
617 const queueLength = this.timeQueue.length;
618 if (queueLength > 1) {
619 if (this.timeQueue[queueLength - 1] > this.timeQueue[queueLength - 2]) {
620 objectivelyPlayingContent = true;
621 }
622 }
623 }
624 this.objectivelyPlayingContent = objectivelyPlayingContent;
625
626 if (this.timeQueue.length > 25) {
627 this.timeQueue.shift();
628 if (this.timeQueue[0] === this.timeQueue[this.timeQueue.length - 1]) {
629 console.log(
630 "queue: ",
631 this.timeQueue[0],
632 this.timeQueue[this.timeQueue.length - 1]
633 );
634 console.log("paused: ", this.paused);
635 console.log("ruler: ", this.master.ruler);
636 console.log("state: ", this.master.state);
637 console.log("player paused: ", this.player.paused());
638 console.log("currentTime: ", this.player.currentTime());
639
640 if (this.master.ruler == 2) {
641 if (!this.player.paused()) {
642 this.playContent(true);
643 }
644 } else if (this.master.state > 1) {
645 if (!this.player.paused() || this.player.currentTime() === 0) {
646 this.playContent(true);
647 }
648 }
649 this.timeQueue = [];
650 }
651 }
652 let self = this;
653 setTimeout(() => self.runWatchdog(), 1 * 1000);
654 }
655 }
656
657 function showDomElements(state, target){
658 console.log("showDomElements: ", state, target);
659 switch (state){
660 case 'idle':
661 // jQuery(".wpstream_hide_on_trailer").show();
662 showHideNearby(target, ".wpstream_hide_on_trailer");
663 // jQuery(".wpstream_hide_on_play").show();
664 showHideNearby(target, ".wpstream_hide_on_play");
665 // jQuery(".wpstream_bundble_title_details h1 ").show();
666 showHideNearby(target, ".wpstream_bundble_title_details h1 ");
667 // jQuery(".wpstream_bundble_title_details .wpstream-product-description").show();
668 showHideNearby(target, ".wpstream_bundble_title_details .wpstream-product-description");
669 // jQuery(".wpstream_bundble_title_details .wpstream-product-categories-wrapper").show();
670 showHideNearby(target, ".wpstream_bundble_title_details .wpstream-product-categories-wrapper");
671 // jQuery(".wpstream_video_on_demand_play_trailer").show();
672 showHideNearby(target, ".wpstream_video_on_demand_play_trailer");
673 // jQuery(".wpstream_video_on_demand_unmute_trailer").hide();
674 showHideNearby(target, ".wpstream_video_on_demand_unmute_trailer", false);
675 // jQuery(".vjs-wpstream").removeClass("wpstream_theme_player_has_trailer");
676 addRemoveClassNearby(target, '.vjs-wpstream', 'wpstream_theme_player_has_trailer', false)
677 break;
678 case 'playing_trailer':
679 // jQuery(".wpstream_hide_on_trailer").hide();
680 showHideNearby(target, ".wpstream_hide_on_trailer", false);
681 // jQuery(".wpstream_hide_on_play").show();
682 showHideNearby(target, ".wpstream_hide_on_play");
683 // jQuery(".wpstream_bundble_title_details h1 ").hide();
684 showHideNearby(target, ".wpstream_bundble_title_details", false);
685 // jQuery(".wpstream_bundble_title_details .wpstream-product-description").hide();
686 showHideNearby(target, ".wpstream_bundble_title_details .wpstream-product-description", false);
687 // jQuery(".wpstream_bundble_title_details .wpstream-product-categories-wrapper").hide();
688 showHideNearby(target, ".wpstream_bundble_title_details .wpstream-product-categories-wrapper", false);
689 // jQuery(".vjs-wpstream").addClass("wpstream_theme_player_has_trailer");
690 addRemoveClassNearby(target, '.vjs-wpstream', 'wpstream_theme_player_has_trailer')
691 break;
692 case 'playing_content':
693 // jQuery(".wpstream_hide_on_trailer").hide();
694 showHideNearby(target, ".wpstream_hide_on_trailer", false);
695 // jQuery(".wpstream_hide_on_play").hide();
696 showHideNearby(target, ".wpstream_hide_on_play", false);
697 // jQuery(".vjs-wpstream").removeClass("wpstream_theme_player_has_trailer");
698 addRemoveClassNearby(target, '.vjs-wpstream', 'wpstream_theme_player_has_trailer', false)
699 break;
700 }
701 }
702
703 function showHideNearby(target, targetClass, show = true) {
704 var method = show ? 'show' : 'hide';
705 var nearbyElements = findNearbyElements(target, targetClass);
706 nearbyElements.each(function() {
707 jQuery(this)[method]();
708 });
709 }
710
711 function addRemoveClassNearby(target, targetClass, className, add = true) {
712 var method = add ? 'addClass' : 'removeClass';
713 var nearbyElements = findNearbyElements(target, targetClass);
714 nearbyElements.each(function() {
715 jQuery(this)[method](className);
716 });
717 }
718
719 function findNearbyElements(target, targetClass) {
720 var $target = jQuery(target);
721 var nearbyElements = $target.parents().slice(0, 4).find(targetClass);
722 // .add($target.closest('.container').find('.' + targetClass));
723 return nearbyElements;
724 }
725
726
727 function randomString32() {
728 return Array.from({ length: 32 }, () =>
729 Math.random().toString(36)[2]
730 ).join('');
731 }
732
733 class Qoe {
734 constructor(callback, callbackScope) {
735 // console.log("Qoe: ", callback, callbackScope);
736 this.callback = callback;
737 this.callbackScope = callbackScope;
738 }
739
740 play() {
741 // console.log("----qoe play");
742 this.reportCurrentSession();
743 if (this.reportInterval){
744 clearInterval(this.reportInterval);
745 this.reportInterval = null;
746 }
747 this.reportInterval = setInterval(() => {
748 this.reportCurrentSession()
749 }, 60 * 1000);
750 this.currentSession = randomString32();
751 this.rebufferCount = 0;
752 this.startupTime = 0;
753 this.totalPlaybackTime = 0;
754 this.totalRebufferTime = 0;
755 this.lastRebufferStartTimestamp = null;
756 this.playTimestamp = performance.now();
757 }
758
759 pause(){
760 // console.log("----qoe pause");
761 this.waiting();
762 }
763
764 ended(){
765 // console.log("----qoe ended");
766 this.waiting();
767 }
768
769 playing(){
770 // console.log("----qoe playing ", document.hidden);
771 // console.log("playTimestamp: ", this.playTimestamp);
772 // console.log("lastRebufferStartTimestamp: ", this.lastRebufferStartTimestamp);
773 if (this.playTimestamp){
774 this.startupTime = performance.now() - this.playTimestamp;
775 // console.log("startupTime: ", this.startupTime / 1000);
776 this.playTimestamp = null;
777 }
778 if (this.lastRebufferStartTimestamp) {
779 let rebufferTime = performance.now() - this.lastRebufferStartTimestamp;
780 // console.log(" rebufferTime: ", (rebufferTime / 1000).toFixed(2));
781 if (rebufferTime < 60 * 1000){ //discard unrealistically long rebuffers
782 if (rebufferTime > 500){ //do not count short rebuffers
783 this.rebufferCount ++;
784 }
785 this.totalRebufferTime += rebufferTime;
786 }
787 this.lastRebufferStartTimestamp = null;
788 }
789 this.lastPlayingTimestamp = performance.now();
790 }
791
792 waiting(){
793 // console.log("----qoe waiting", document.hidden);
794 // console.log("playTimestamp: ", this.playTimestamp);
795 // console.log("lastPlayingTimestamp: ", this.lastPlayingTimestamp);
796 // console.log("lastRebufferStartTimestamp: ", this.lastRebufferStartTimestamp);
797
798 if (this.lastPlayingTimestamp){
799 let playingTime = performance.now() - this.lastPlayingTimestamp;
800 this.lastPlayingTimestamp = null;
801 // console.log(" playingTime: ", (playingTime / 1000).toFixed(2));
802 this.totalPlaybackTime += playingTime;
803 // console.log("totalPlaybackTime: ", this.totalPlaybackTime);
804 }
805
806 if (this.playTimestamp){ //it's the first time it buffers
807 // do nothing
808 }
809 else if (!this.lastRebufferStartTimestamp && !document.hidden) {
810 // console.log("rebufferCount: ", this.rebufferCount);
811 this.lastRebufferStartTimestamp = performance.now();
812 }
813 }
814
815 loadeddata(){
816 // console.log("qoe loadeddata")
817 }
818
819 resolutionchange(){
820 // console.log("qoe resolutionchange")
821 }
822
823 error(){
824 // console.log("qoe error")
825 }
826
827 reportCurrentSession(){
828 // console.log("----reportCurrentSession: ");
829 // console.log("totalPlaybackTime: ", this.totalPlaybackTime);
830 // console.log("lastPlayingTimestamp: ", this.lastPlayingTimestamp);
831 if (this.totalPlaybackTime > 0 || this.lastPlayingTimestamp){
832 let totalPlaybackTime = this.totalPlaybackTime;
833 // console.log("totalPlaybackTime: ", totalPlaybackTime);
834 if (this.lastPlayingTimestamp){
835 totalPlaybackTime += performance.now() - this.lastPlayingTimestamp;
836 }
837 // console.log("totalPlaybackTime: ", totalPlaybackTime);
838
839 if (!this.lastReportedPlaybackTime || this.lastReportedPlaybackTime != totalPlaybackTime){
840 let report = {
841 startupTime: this.startupTime,
842 totalPlaybackTime: totalPlaybackTime,
843 rebufferCount: this.rebufferCount,
844 totalRebufferTime: this.totalRebufferTime,
845 session: this.currentSession,
846 }
847 console.log("report: ", report);
848 // console.log("callback: ", this.callback)
849 this.callback.call(this.callbackScope, report);
850 this.lastReportedPlaybackTime = totalPlaybackTime;
851 }
852 }
853 }
854 }
855
856 class WpstreamChat {
857 // connected = '';
858
859 constructor() {
860 this.connected = "";
861 }
862
863 connect(url) {
864 this.connected = "yes";
865 if (typeof connect === "function") {
866 connect(url);
867 }
868 }
869
870 disconnect() {
871 if (typeof showChat === "function" && this.connected === "yes") {
872 showChat("info", null, wpstream_player_vars.chat_not_connected);
873 this.connected = "no";
874 }
875 }
876 }
877
878 class WpstreamLiveMessage {
879 // element;
880 // msg;
881 // originalMessage;
882 // customMessage;
883 // state = -1; // -1 - unknown; 0 - hidden; 1 - showing original msg; 3 - showing paused msg; 5 - showing custom msg
884
885 static customMessageStates = [
886 "stopped",
887 "init",
888 "paused",
889 "startup",
890 "ended",
891 ];
892 bottom = false;
893
894 constructor(wrapper, id) {
895 this.state = "none";
896 this.element = wrapper.find(".wpstream_not_live_mess");
897 this.msg = wrapper.find(".wpstream_not_live_mess_mess");
898 this.originalMessage = this.msg.html();
899 console.log("originalMessage: ", this.originalMessage);
900 var playerElement = jQuery("#wpstream-video" + id);
901 this.element.appendTo(playerElement);
902 }
903
904 setCustomMessage(message){
905 this.customMessage = message;
906 this.showMessage(this.state);
907 }
908
909 showMessage(state) {
910 // console.log("showMessage: ", state);
911 var label;
912 if (
913 this.customMessage &&
914 WpstreamLiveMessage.customMessageStates.includes(state)
915 ) {
916 label = this.customMessage;
917 } else {
918 label = wpstream_player_vars[`wpstream_player_state_${state}_msg`];
919 }
920 this.msg.text(label);
921 this.msg.addClass(`wpstream_player_state_${state}_class`);
922 // don't show if label is empty or spaces
923 if (!/^\s*$/.test(label)) this.show();
924 else this.hide();
925 this.state = state;
926 }
927
928 showOriginalMessage() {
929 this.msg.html(this.originalMessage);
930 this.show();
931 this.state = "original";
932 }
933
934 showAtBottom(show) {
935 console.log("showAtBottom: ", show);
936 this.bottom = show;
937 this.element[0].style.top = this.bottom ? "80%" : "31%";
938
939 if (this.state == "stopped" || this.state == "original") {
940 this.showStoppedMessage();
941 }
942 }
943
944 showStoppedMessage() {
945 console.log("element: ", this.element);
946 if (this.bottom) {
947 this.showMessage("stopped");
948 } else {
949 this.showOriginalMessage();
950 }
951 }
952
953 //public
954 hide() {
955 this.element.hide();
956 this.state = 0;
957 }
958
959 //private
960 show() {
961 this.element.show();
962 }
963 }
964
965 class LiveCounter {
966 // element;
967 constructor(wrapper, id) {
968 console.log("[]LiveCounter: ", wrapper, id);
969 this.element = wrapper.find(".wpestream_live_counting");
970 this.element.css("background-color", "rgb(174 69 69 / 90%)");
971
972 const data = this.element?.data?.() || {};
973 console.log("showviewercount:", data.showviewercount);
974 this.showCounter = (data.showviewercount !== undefined && data.showviewercount !== null)
975 ? data.showviewercount.toString() === "1"
976 : false;
977 console.log("showCounter:", this.showCounter);
978
979 //var playerElement = wrapper.find('.wpstream-video' + id);
980 var playerElement = jQuery("#wpstream-video" + id);
981 console.log("playerElement: ", playerElement);
982 this.element.appendTo(playerElement);
983 this.hide();
984 }
985
986 show() {
987 this.element.show();
988 }
989
990 hide() {
991 this.element.hide();
992 }
993
994 setCount(count) {
995 if (this.showCounter){
996 this.element.html(count + " Viewers");
997 this.show();
998 }
999 else {
1000 this.hide();
1001 }
1002 }
1003 showPending(place){
1004 this.element.html(`Max viewers reached. Please wait for ${place} to leave.`);
1005 this.show();
1006 }
1007 }
1008
1009 class LiveConnect {
1010 // master;
1011 // wsUri;
1012 // ws;
1013 // connectCount = 0;
1014 // connected = false;
1015 // pendingConnect = false;
1016
1017 constructor(master) {
1018 this.connectCount = 0;
1019 this.connected = false;
1020 this.pendingConnect = false;
1021 this.master = master;
1022 }
1023
1024 setup(wsUri) {
1025 console.log("setup: ", wsUri);
1026 this.close();
1027 this.wsUri = wsUri;
1028 this.connect();
1029 }
1030
1031 close() {
1032 if (this.ws != null) {
1033 this.ws.close();
1034 }
1035 this.ws = null;
1036 }
1037
1038 sendQoeData(data){
1039 // console.log("sendQoeData: ", data);
1040 if (this.ws && this.ws.readyState === WebSocket.OPEN){
1041 const message = {type:'qoe', data}
1042 this.ws.send(JSON.stringify(message));
1043 }
1044 }
1045
1046 connect() {
1047 let connectAttempt = ++this.connectCount;
1048 console.log("connect() ", connectAttempt);
1049 this.pendingConnect = true;
1050 try {
1051 this.ws = new WebSocket(this.wsUri);
1052 let owner = this;
1053 this.ws.onopen = function () {
1054 console.log("connected. ", connectAttempt);
1055 owner.pendingConnect = false;
1056 owner.master.onLiveConnectActive(true);
1057 //socket_connection.send(`{"type":"register","data":"${now}"}`);
1058 };
1059 this.ws.onclose = function () {
1060 console.log("onclose.. ", connectAttempt);
1061 owner.master.onLiveConnectActive(false);
1062 };
1063 this.ws.onerror = function (error) {
1064 console.log("onerror: ", connectAttempt, error);
1065 owner.master.onLiveConnectActive(false);
1066 };
1067 this.ws.onmessage = function (message) {
1068 console.log("onmessage: ", connectAttempt, message.data);
1069 owner.processMessage(message.data);
1070 };
1071 } catch (error) {
1072 console.log(error);
1073 this.master.onLiveConnectActive(false);
1074 }
1075 }
1076
1077 processMessage(msg) {
1078 console.log("processMessage: ", msg);
1079 var json;
1080 try {
1081 json = JSON.parse(msg);
1082 } catch (e) {
1083 console.log("Invalid JSON: ", msg);
1084 return;
1085 }
1086 if (json.type) {
1087 switch (json.type) {
1088 case "viewerCount":
1089 this.master.updateViewerCount(json.data);
1090 break;
1091 case "pending":
1092 this.master.updatePending(json.data);
1093 break;
1094 case "onair":
1095 if (json.info) {
1096 this.master.setState(json.info.broadcasting);
1097 } else {
1098 this.master.setState(json.data ? "onair" : "paused");
1099 }
1100 break;
1101 case "status":
1102 this.master.liveMessage.setCustomMessage(json.data);
1103 break;
1104 default:
1105 console.log("invalid type: ", json.type);
1106 }
1107 }
1108 }
1109 }
1110
1111 function wpstream_read_websocket_info(
1112 event_id,
1113 player,
1114 player_wrapper,
1115 socket_wss_live_conect_views_uri,
1116 event_uri
1117 ) {
1118 console.log(
1119 "wpstream_read_websocket_info: ",
1120 event_id,
1121 player,
1122 player_wrapper,
1123 socket_wss_live_conect_views_uri,
1124 event_uri
1125 );
1126 console.log("sldpPlayer: ", sldpPlayer);
1127 if (sldpPlayer != null) {
1128 var chat = new WpstreamChat();
1129 chat.connect(socket_wss_live_conect_views_uri);
1130 }
1131 }
1132
1133 jQuery(document).ready(function ($) {
1134 console.log("ready!");
1135 var event_id;
1136 var player_wrapper;
1137 jQuery(".wpstream_live_player_wrapper").each(function () {
1138 console.log("wrapper: ", this, $(this));
1139 if ($(this).hasClass("wpstream_low_latency")) {
1140 return;
1141 }
1142 event_id = jQuery(this).attr("data-product-id");
1143 player_wrapper = jQuery(this);
1144
1145 //wpstream_check_player_status_ticker(player_wrapper,event_id);
1146 });
1147 });
1148
1149 var sldpPlayer;
1150
1151 function initPlayer(playerID, low_latency_uri, muted, autoplay) {
1152 console.log("initPlayer: ", low_latency_uri);
1153 var is_muted = false;
1154 var is_autoplay = true;
1155 if (muted === "muted") {
1156 is_muted = true;
1157 }
1158
1159 if (autoplay !== "autoplay") {
1160 is_autoplay = false;
1161 }
1162
1163 console.log("is_muted " + is_muted + "/ " + is_autoplay);
1164
1165 loadScriptIfNeeded('https://cdn.jsdelivr.net/npm/ovenplayer/dist/ovenplayer.js')
1166 .then(() => {
1167 let player = OvenPlayer.create(playerID, {
1168 autoStart: is_autoplay,
1169 autoFallback: false,
1170 mute: is_muted,
1171 sources: [
1172 {
1173 type: "webrtc",
1174 file: low_latency_uri,
1175 },
1176 ],
1177 hlsConfig: {
1178 liveSyncDuration: 1.5,
1179 liveMaxLatencyDuration: 3,
1180 maxLiveSyncPlaybackRate: 1.5,
1181 },
1182 webrtcConfig: {
1183 timeoutMaxRetry: 100,
1184 connectionTimeout: 10000,
1185 },
1186 });
1187 })
1188 .catch((error) => {
1189 console.error('Error loading the script:', error);
1190 });
1191
1192
1193 }
1194
1195 function removePlayer() {
1196 sldpPlayer.destroy();
1197 }
1198
1199 function loadScriptIfNeeded(scriptUrl) {
1200 return new Promise((resolve, reject) => {
1201 // Check if the script is already loaded
1202 if (document.querySelector(`script[src="${scriptUrl}"]`)) {
1203 console.log(`Script already loaded: ${scriptUrl}`);
1204 resolve(); // Resolve immediately if the script is already loaded
1205 return;
1206 }
1207
1208 // Create and append the script if not loaded
1209 const script = document.createElement('script');
1210 script.src = scriptUrl;
1211 script.type = 'text/javascript';
1212 script.async = true;
1213
1214 script.onload = () => {
1215 console.log(`Script loaded: ${scriptUrl}`);
1216 resolve();
1217 };
1218
1219 script.onerror = () => {
1220 console.error(`Failed to load script: ${scriptUrl}`);
1221 reject(new Error(`Failed to load script: ${scriptUrl}`));
1222 };
1223
1224 document.head.appendChild(script);
1225 });
1226 }
1227
1228 // {
1229 // videoElementId
1230 // trailerUrl
1231 // videoUrl
1232 // autoplay
1233 // muted
1234 // playTrailerButtonElementId
1235 // playVideoButtonElementId
1236 // }
1237 function wpstream_player_initialize_vod(settings) {
1238 console.log("wpstream_player_initialize_vod: ", settings);
1239 var playing = settings.trailerUrl ? "trailer" : "content";
1240
1241 const playTrailerButton = jQuery(`#${settings.playTrailerButtonElementId}`);
1242 const playVideoButton = jQuery(`#${settings.playVideoButtonElementId}`);
1243 const muteTrailerButton = jQuery(`#${settings.muteTrailerButtonElementId}`);
1244 const unmuteTrailerButton = jQuery(
1245 `#${settings.unmuteTrailerButtonElementId}`
1246 );
1247 const titleOverlay = document.getElementById(settings.titleOverlayElementId);
1248
1249 muteTrailerButton.hide();
1250 unmuteTrailerButton.hide();
1251
1252 if (!settings.trailerUrl) {
1253 playTrailerButton.hide();
1254 }
1255 if (!settings.videoUrl) {
1256 playVideoButton.hide();
1257 }
1258
1259 const initialSrc = settings.trailerUrl
1260 ? getSrc(settings.trailerUrl)
1261 : getSrc(settings.videoUrl);
1262 console.log("initialSrc: ", initialSrc);
1263
1264 const player = videojs(settings.videoElementId);
1265 player.preload("auto");
1266 player.playsinline(true);
1267 player.controls(!settings.trailerUrl);
1268 player.autoplay(settings.autoplay);
1269 player.muted(settings.muted);
1270
1271 if ( typeof player.logo === 'function' && settings.playerLogoSettings ) {
1272 player.logo(settings.playerLogoSettings);
1273 }
1274
1275 const originalPoster = player.poster();
1276
1277 player.src({ ...initialSrc, autoplay: true, muted: true });
1278 if (titleOverlay){
1279 player.el().appendChild(titleOverlay);
1280 }
1281
1282 if (settings.theaterModeButtons) {
1283 const Button = videojs.getComponent("Button");
1284 const owner = this;
1285
1286 class TheaterModeEnterButton extends Button {
1287 constructor(player, options) {
1288 super(player, options);
1289 this.controlText("Switch to Theater Mode");
1290 this.addClass(settings.theaterModeButtons.enterTheaterModeButton.skin);
1291 }
1292 handleClick() {
1293 owner.theaterModeEnterButton.hide();
1294 owner.theaterModeLeaveButton.show();
1295 console.log("entering Theater Mode...");
1296 eval(settings.theaterModeButtons.enterTheaterModeButton.callback);
1297 }
1298 }
1299 class TheaterModeLeaveButton extends Button {
1300 constructor(player, options) {
1301 super(player, options);
1302 this.controlText("Switch to Normal Mode");
1303 this.addClass(settings.theaterModeButtons.leaveTheaterModeButton.skin);
1304 }
1305 handleClick() {
1306 owner.theaterModeEnterButton.show();
1307 owner.theaterModeLeaveButton.hide();
1308 console.log("leaving Theater Mode...");
1309 eval(settings.theaterModeButtons.leaveTheaterModeButton.callback);
1310 }
1311 }
1312
1313 videojs.registerComponent("TheaterModeEnterButton", TheaterModeEnterButton);
1314 videojs.registerComponent("TheaterModeLeaveButton", TheaterModeLeaveButton);
1315 this.theaterModeEnterButton = player
1316 .getChild("controlBar")
1317 .addChild("TheaterModeEnterButton", {}, 17);
1318 this.theaterModeLeaveButton = player
1319 .getChild("controlBar")
1320 .addChild("TheaterModeLeaveButton", {}, 18);
1321 this.theaterModeLeaveButton.hide();
1322 }
1323
1324 player.on("play", () => {
1325 console.log("play()");
1326 playTrailerButton.hide();
1327 if (player.userActive()) {
1328 showTitleOverlay();
1329 }
1330 console.log("playing: ", playing);
1331 if (playing == "trailer") {
1332 player.poster(null);
1333 player.controls(false);
1334 showDomElements('playing_trailer', player.el());
1335 } else {
1336 playVideoButton.hide();
1337 player.controls(true);
1338 showDomElements('playing_content', player.el())
1339 }
1340 showHideMuteButtons();
1341 });
1342
1343 player.on("ended", () => {
1344 console.log("ended");
1345 if (playing == "trailer") {
1346 console.log("trailer has ended");
1347 if (settings.videoUrl) {
1348 playing = "content";
1349 player.controls(true);
1350 player.autoplay(false);
1351 player.muted(false);
1352 player.poster(originalPoster);
1353 player.src(getSrc(settings.videoUrl));
1354 } else {
1355 player.hasStarted(false);
1356 }
1357 player.bigPlayButton.hide();
1358 playTrailerButton.show();
1359 showHideMuteButtons();
1360 showDomElements('idle', player.el())
1361 } else {
1362 console.log("video has ended");
1363 }
1364 });
1365
1366 player.on("volumechange", () => {
1367 console.log("muted: ", player.muted());
1368 // console.log("paused: ", player.paused());
1369 if (!player.paused()) {
1370 showHideMuteButtons();
1371 }
1372 });
1373
1374 function showHideMuteButtons() {
1375 console.log("showHideMuteButtons()");
1376 if (playing == "trailer") {
1377 if (player.muted()) {
1378 muteTrailerButton.hide();
1379 unmuteTrailerButton.show();
1380 } else {
1381 muteTrailerButton.show();
1382 unmuteTrailerButton.hide();
1383 }
1384 } else {
1385 muteTrailerButton.hide();
1386 unmuteTrailerButton.hide();
1387 }
1388 }
1389
1390 function showTitleOverlay(show = true) {
1391 if (titleOverlay){
1392 titleOverlay.style.opacity = show ? '1' : '0';
1393 }
1394 }
1395
1396 player.on("error", () => {
1397 console.log("error()");
1398 if (playing == "trailer") {
1399 console.log("trailer failed");
1400 playTrailerButton.hide();
1401 if (videoUrl) {
1402 playing = "content";
1403 player.controls(true);
1404 player.src(getSrc(settings.videoUrl));
1405 }
1406 }
1407 });
1408
1409 player.on('useractive', function() {
1410 showTitleOverlay();
1411 });
1412
1413 player.on('userinactive', function() {
1414 showTitleOverlay(false);
1415 });
1416
1417 playTrailerButton.on("click", function () {
1418 console.log("playTrailer()");
1419
1420 if (playing != "trailer") {
1421 playing = "trailer";
1422 player.src(settings.trailerUrl);
1423 }
1424 player.play();
1425 });
1426
1427 muteTrailerButton.on("click", function () {
1428 if (playing == "trailer") {
1429 console.log("muteTrailer()");
1430 player.muted(true);
1431 }
1432 });
1433
1434 unmuteTrailerButton.on("click", function () {
1435 if (playing == "trailer") {
1436 console.log("unmuteTrailer()");
1437 player.muted(false);
1438 }
1439 });
1440
1441 playVideoButton.on("click", function () {
1442 console.log("playVideo");
1443 if (!settings.videoUrl) return;
1444 if (playing == "trailer") {
1445 playing = "content";
1446 player.controls(true);
1447 player.muted(false);
1448 player.src(getSrc(settings.videoUrl));
1449 }
1450
1451 player.play();
1452 });
1453 }
1454
1455 function getSrc(url) {
1456 return {
1457 src: url,
1458 type: url.endsWith(".m3u8") ? "application/x-mpegURL" : url.includes("www.youtube") || url.includes("youtu.be") ? "video/youtube" : null,
1459 };
1460 }
1461
1462 function isLlHls(url) {
1463 return /ll[a-z]+\.m3u8/.test(url);
1464 }
1465