PageSourceSearch

https://cdn.iol.pt/js/utils/JW8/iol.player_2.4.3.js

js iol.pt collected 2026-09-24 08:27:24 UTC 57,490 bytes, 1,436 lines download raw bytes

1(function($, window, document, undefined) {
2  var JW_IOL_Version = "2.4.2";
3  var cssURL = `https://cdn.iol.pt/js/utils/JW8/assets/style/iol.player.min.css?v${JW_IOL_Version}`;
4  var jwplayerURL = "https://content.jwplatform.com/libraries/giBojDlP.js";
5  var noPubProducts = [13,14];
6
7  // Default Options for JW8
8  var defaultPlayerOptions = {
9    /* IOL Variables */
10    video: undefined, // Array of JSON videos object
11    imageId: undefined, // ID or IDs(array) of the video thumbnail
12    imageUrl: undefined, // URL or URLS(array) of the video thumbnail
13    smartToken: undefined, // SmartTop token or tokens(array) of the videos
14    hasAdvertising: true, // By default has advertising
15    waitForConsent: true, // By default wait for consent
16    pub: undefined, // Advertising Segmentation
17    sharingLink: "", // Sets the sharing link
18    embedPlatform: undefined, // Indicates the type of YOUTUBE|INSTAGRAM|FACEBOOK|INCONTENT VIDEO
19    playerPlatform: "WEB", // Available values WEB|AMP|IA|APP
20    shouldSendEvents: true, // Define if we want to register the events on the Google Analytics
21    pageContentType: "", // Defines the page where the player is contained (VIDEO, ARTICLE, ...)
22    project: "", // Defines the project Name (tvi24, selfie, ...)
23    playOnViewable: false, // Start playing when visible
24    videoRedirect: true,
25    relatedRSS: "",
26
27    /* JWPlayer Variables https://developer.jwplayer.com/jw-player/docs/developer-guide/customization/configuration-reference/#setup */
28    /*** Media ***/
29    file: "", //URL to a single video file, audio file, or live stream to play. Can also be c
29onfigured inside of a sources array
30    image: "", //URL to a poster image to display before playback starts.
31    title: "", //The title of your video or audio item
32    description: "", //A description of your video or audio item
33
34    /*** Behavior ***/
35    mute: false, //Configures if the player should be muted during playback
36    autostart: false, //Whether the player will attempt to begin playback automatically when a page is loaded. Set to 'viewable' to have player autostart if 50% is viewable.
37    nextupoffset: "85%", //Configures when the Next Up card displays during playback. A positive value is an offset from the start of the video. A negative number is an offset from the end of the video
38    repeat: false, //Configures if the player should loop content after a playlist completes
39    abouttext: "", //Custom text to display in the right-click menu
40    aboutlink: "", //Custom URL to link to when clicking the right-click menu
41    playbackRateControls: false, //Whether to display a settings menu to adjust playback speed. If true, the pre-defined options available in the menu are 0.5x, 1x, 1.25x, 1.5x, and 2x. An array can be passed to customize the menu options using playbackRates. Note: This feature is not currently supported in Android with HLS streams.
42    playbackRates: [0.25, 0.75, 1, 1.25], //Custom playback rate options to display in the settings menu.
43
44    /*** Appearance ***/
45    controls: true, //Whether to display the video controls (control bar and display icons)
46    localization: {}, //Changes text for the player in certain locations
47    aspectratio: "16:9", //Maintains proportions when width is a percentage. Will not be used if the player is a static size. Must be entered in ratio "x:y" format.
48    height: 360, //The desired height of your video player (In pixels). Can be omitted when aspectratio is configured
49    width: "100%", //The desired height of your video player (In pixels or percentage)
50    displaytitle: false, //Configures if the title of a media file should be displayed
51    displaydescription: false, //Configures if the description title of a media file should be displayed
52    stretching: "uniform", //Resize images and video to fit player dimensions. "uniform"/"exactfit"/"fill"/"none"
53    nextUpDisplay: true, //Configures whether the Next Up modal is displayed
54    qualityLabels: {}, //By default, the JW Player will set video quality levels using information from the manifest files. Use this configuration option to apply a custom quality label to a desired bandwidth in kbps, works for HLS and DASH. For example: "qualityLabels":{"2500":"High","1000":"Medium"}
55
56    /*** Rendering and Loading ***/
57    preload: "auto", //Tells the player if content should be loaded prior to playback. "none"/"metadata"/"auto"
58    flashplayer: "//ssl.p.jwpcdn.com/player/v/8.3.0/jwplayer.flash.swf", //Specifies an alternate directory of jwplayer.flash.swf
59    hlsjsdefault: true,
60
61    /*** Cast ***/
62    //"cast": {}, 				//Enable casting from directly within the video.
63
64    /*** Skin ***/
65    skin: {
66      //Color can be specified as a hex value, RGBA color value, or color name
67      controlbar: {
68        text: "#F2F2F2", //Color can be specified as a hex value, RGBA color value, or color name
69        icons: "rgba(255,255,255,0.8)", //The default, inactive color of all icons in the control bar. This option also controls the color of the play, pause, and replay icons in the inactive and complete states.
70        iconsActive: "#FFFFFF", //The color of hovered or selected icons in the control bar.
71        background: "rgba(54, 55, 56, 0.5)" //The background color of the control bar and the volume slider. The default background is transparent.
72      },
73      timeslider: {
74        rail: "rgba(0,0,0,0.6)", //The color of the base of the timeslider, known as the rail.
75        progress: "#4f13c6" //The color of the bar in the time slider filled in from the beginning of the video through the current position.
76      },
77      menus: {
78        text: "rgba(255, 255, 255, 0.8)", //The color of inactive, default text in menus and the Next Up overlay.
79        textActive: "#FFFFFF", //The color of hovered or selected text in menus.
80        background: "rgba(54, 55, 56, 0.7)" //The background color of menus and the Next Up overlay.
81      },
82      tooltips: {
83        text: "#000000", //The text color of tooltips.
84        background: "rgba(199, 194, 194, 0.94)" //The background color of tooltips.
85      },
86
87      /* IOL Variables */
88      playlist: {
89        background: "#222222", //The background color for the playlist wrapper
90        text: "#F2F2F2", //The text color
91        playing: "#E8E8E8", //The color for the "A TOCAR"
92        playingShadow: "#252525", //The shadow for the "A TOCAR"
93        duration: "#E8E8E8", //The text color for the duration
94        durationBackground: "rgba(0,0,0,.6)", //The background color for the duration
95        durationShadow: "#252525", //The shadow for the duration
96        scroll: "#7DB5E9" //The scroll bar color
97      }
98    },
99
100    /*** Logo ***/
101    logo: {
102      file: "", //The URL of an external JPG, PNG or GIF image to be used as watermark (e.g. /assets/logo.png). We recommend using 24 bit PNG images with transparency
103      hide: true, //When this option is set to true, the logo will automatically show and hide along with the other player controls
104      link: "", //The URL to visit when the watermark image is clicked. Clicking a logo will have no affect unless this is configured
105      margin: "10", //The distance, in pixels, of the logo from the edges of the display
106      position: "top-right" //This sets the corner in which to display the watermark.
107    },
108
109    /*** Sharing ***/
110    sharing: {
111      //This options block controls a settings submenu with social sharing options: copy embed code, copy video link and share video to social networks.
112      sites: ["facebook", "twitter", "googleplus", "email", "interest", "linkedin"]
113    },
114
115    /*** Google Analytics ***/
116    ga: {}, //This options block configures the built-in integration with Google Analytics.
117
118    intl: {
119      pt: {
120        nextUp: "A seguir"
121      }
122    },
123
124    /*** Callbacks for the events ***/
125    onReady: function() {},
126    onPlay: function() {},
127    onFirstPlay: function() {},
128    onPause: function() {},
129    onIdle: function() {},
130    onComplete: function() {},
131    onError: function(event) {},
132    onSeek: function(event) {},
133    onTime: function(event) {},
134    onPlaylistComplete: function(event) {},
135    onPlaylistItem: function(event) {},
136    onAdPlay: function(event) {},
137    onAdImpression: function(event) {},
138    onAdComplete: function(event) {},
139    onAdPause: function(event) {},
140    onVisualQuality: function(event) {},
141    onViewable: function(event) {},
142    onTime: function(event) {}
143  };
144
145  /**
146   * Adds the function iolplayer to the JQuery prototype
147   * @param {object} playerOptions
148   */
149  $.fn.iolplayer = function(playerOptions) {
150    //API access
151    if (typeof playerOptions === "string") {
152      var args = arguments;
153      var result;
154
155      this.each(function() {
156        var instance = $.data(this, "iolplayer");
157
158        // check if a valid instance and if public method exists
159        if (instance instanceof IOLPlayer && typeof instance[playerOptions] === "function") {
160          //Call API Method for the instance, with the args passed to this function call
161          result = instance[playerOptions].apply(instance, Array.prototype.slice.call(args, 1));
162        }
163      });
164
165      return result !== undefined ? result : this;
166    }
167
168    //Validates the player options
169    var msg = isAValidPlayer(playerOptions);
170    if (typeof playerOptions === "object" && !msg) {
171      //Workaround for iOS due to NonioBar error
172      var ua = window.navigator.userAgent;
173      var iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
174      var webkit = !!ua.match(/WebKit/i);
175      var iOSSafari = iOS && webkit && !ua.match(/CriOS/i);
176
177      if (iOSSafari) {
178        var _this = this;
179        window.setTimeout(function() {
180          $(_this).data("iolplayer", new IOLPlayer(_this, playerOptions));
181        }, 1000);
182      } else {
183        $(this).data("iolplayer", new IOLPlayer(this, playerOptions));
184      }
185    } else {
186      if (!playerOptions) {
187        console.log("JW: Player Options are empty.");
188        //this.sendMonitoringErrorEvent("Validating Options", { "message": "JW: Player Options are empty." });
189        $(this).data("iolplayer-error", "JW: Player Options are empty.");
190      }
191
192      //this.sendMonitoringErrorEvent("Validating Options", { "message": `JW: ${msg}` });
193      $(this).data("iolplayer-error", "JW: " + msg);
194    }
195  };
196
197  /**
198   * Valides the player options
199   * Currently validates the video property and sets the mute to true if the autostart option is true
200   * @param {object} playerOptions
201   */
202  function isAValidPlayer(playerOptions) {
203    if (!playerOptions.video || playerOptions.video.length == 0) {
204      return "No sources available";
205    }
206
207    if (playerOptions.autostart && playerOptions.autostart === 'true') {
208      playerOptions.mute = true;
209    }
210
211    return;
212  }
213
214  /**
215   * Creates a IOLPlayer object
216   * @param {string} elem
217   * @param {object} playerOptions
218   */
219  var IOLPlayer = function(elem, playerOptions) {
220    this.iolJWPlayer = {};
221    $("head").append(`<link rel="stylesheet" type="text/css" href="${cssURL}">`);
222
223    /* Registering the HTML element that contains the player */
224    this.iolJWPlayer.playerElement = $(elem);
225
226    /* Merging the default player options with the choosen options */
227    this.iolJWPlayer.options = $.extend(true, {}, defaultPlayerOptions, playerOptions);
228
229    /* Setting default imageUrl */
230    if (this.iolJWPlayer.options.imageId && !this.iolJWPlayer.options.imageUrl) {
231      var screenWidth = window.innerWidth >= 1024 ? 1300 : window.innerWidth * 2;
232      this.iolJWPlayer.options.imageWidth = Number.isInteger(this.iolJWPlayer.options.width)
233        ? this.iolJWPlayer.options.width
234        : screenWidth;
235      this.iolJWPlayer.options.imageUrl =
236        "https://www.iol.pt/multimedia/oratvi/multimedia/imagem/id/" +
237        this.iolJWPlayer.options.imageId +
238        "/" +
239        this.iolJWPlayer.options.imageWidth;
240    }
241
242    if (["nit", "embed"].includes(this.iolJWPlayer.options.project.toLowerCase())) {
243      this.initIOLPlayer();
244      return;
245    }
246
247    var u = this.getUser();
248
249    this.iolJWPlayer.options.hasAdvertising = this.shouldPlayAds(u);
250
251    var _this = this;
252    this.canAccessToMultimedia(function() {
253      _this.validateCookie(u);
254    });
255  };
256
257  /**
258   * Defines the IOLPlayer Object
259   */
260  IOLPlayer.prototype = {
261    validateCookie: function(u) {
262      /* Check if the token cookie exists */
263      var tk = $.cookie("jwiol");
264
265      if (tk) {
266        var tk_i = $.cookie("jwiol_i");
267
268        if (tk_i !== u["i"]) {
269          tk = "";
270        }
271      }
272
273      if (!tk) {
274        var _this = this;
275        var reqUrl =
276          this.iolJWPlayer.options.project.toLowerCase() === "beachcam"
277            ? `https://services.iol.pt/matrix?userId=${_this.iolJWPlayer.user.uname}`
278            : `https://services.iol.pt/matrix?userId=${_this.iolJWPlayer.user.uname}`;
279
280        $.ajax({
281          url: reqUrl,
282          async: false,
283          contentType: "text/plain",
284          success: function(data) {
285            _this.iolJWPlayer.playerTK = `?wmsAuthSign=${data}`;
286            var creationDate = new Date();
287            var expirationDate = new Date();
288            expirationDate.setTime(expirationDate.getTime() + 20 * 3600 * 1000);
289            /* Create token cookie and creation token cookie*/
290            $.cookie("jwiol", data, {
291              expires: expirationDate,
292              domain: "iol.pt",
293              path: "/"
294            });
295            $.cookie("jwiol_i", u["i"], {
296              expires: expirationDate,
297              domain: "iol.pt",
298              path: "/"
299            });
300            $.cookie("jwiol_c", creationDate, {
301              expires: expirationDate,
302              domain: "iol.pt",
303              path: "/"
304            });
305            _this.initIOLPlayer();
306          },
307          error: function(data) {
308            //_this.sendMonitoringErrorEvent("Matrix Options", { message: data.statusText });
309          }
310        });
311      } else {
312        this.iolJWPlayer.playerTK = `?wmsAuthSign=${tk}`;
313        this.initIOLPlayer();
314      }
315    },
316
317    canAccessToMultimedia: function(callback) {
318      if (this.iolJWPlayer.options.video[0].liveType.toLowerCase() === "onlive") {
319        callback();
320        return;
321      }
322
323      if (!this.iolJWPlayer.user) this.getUser();
324
325      var videoType = this.iolJWPlayer.options.video[0].liveType.toLowerCase() === "vod" ? "vod" : "live";
326      var user = this.iolJWPlayer.options.user ? this.iolJWPlayer.options.user : this.iolJWPlayer.user.uid;
327      var _this = this;
328
329      $.ajax({
330        url: `https://services.iol.pt/direitos/rights/${videoType}?id=${this.iolJWPlayer.options.video[0].id}&host=${this.iolJWPlayer.options.project}`,
331        type: "GET",
332        dataType: "json",
333        headers: {
334          userid: user
335        },
336        error: function(jqXHR, textStatus, errorThrown) {
337          var data = jqXHR.responseJSON;
338          if (data && data.code) {
339            var errorMsg = "Lamentamos mas ocorreu um erro.";
340            var errorImg = "https://cdn.iol.pt/js/utils/JW8/assets/img/error_smile.jpg";
341            var errorCode = "(000)";
342
343            switch (data.code) {
344              case "100":
345                errorMsg =
346                  "Lamentamos mas n&atilde;o existem direitos de transmiss&atilde;o via internet no pa&iacute;s onde se encontra.";
347                errorImg = "https://cdn.iol.pt/js/utils/JW8/assets/img/geoblock.jpg";
348                errorCode = "(geoblock-100)";
349                break;
350
351              case "101":
352                errorMsg =
353                  "Lamentamos mas n&atilde;o existem direitos de transmiss&atilde;o via internet para este programa";
354                errorImg = "https://cdn.iol.pt/js/utils/JW8/assets/img/geoblock.jpg";
355                errorCode = "(geoblock-101)";
356                break;
357
358              case "200":
359                var errorMssageTviPlayer = `Subscreva o TVI Player Internacional para poder ver este conte&uacute;do.
360                Clique <a href="https://tviplayer.iol.pt/subscricao">aqui</a> para conhecer todas as vantagens.
361                Se j&aacute; tem uma subscri&ccedil;&atilde;o, por favor, clique <a href="#/iol/login">aqui</a> para efetuar login.`;
362
363                var errorMssageClubeMca = `Tens que fazer parte do Clube Morangos com A&ccedil;&uacute;car para poderes ver este conte&uacute;do.
364                <a href="https://tvi.iol.pt/clubemca/subscricao" class="bt-more">Junta-te ao clube!</a>
365                Se j&aacute; tens uma subscri&ccedil;&atilde;o, por favor, clica <a href="#/iol/login">aqui</a> para entrares.`
366                errorMsg = _this.iolJWPlayer.options.project === 'clubemca' ? errorMssageClubeMca : errorMssageTviPlayer;
367                errorImg = "https://cdn.iol.pt/js/utils/JW8/assets/img/error.jpg";
368                errorCode = "(prd-200)";
369                break;
370
371              case "201":
372                var messageErrorMca201 = `Tens que fazer parte do Clube Morangos com A&ccedil;&uacute;car para poderes ver este conte&uacute;do.
373                <a href="https://tvi.iol.pt/clubemca/subscricao" class="bt-more">Junta-te ao clube!</a>`;
374                var messageErrorTviplayer201 = `Subscreve o TVI Player Internacional para poder ver este conte&uacute;do.
375                Clique <a href="https://tviplayer.iol.pt/subscricao">aqui</a> para conhecer todas as vantagens.`;
376                errorMsg = errorMsg = _this.iolJWPlayer.options.project === 'clubemca' ? messageErrorMca201 : messageErrorTviplayer201;
377                errorImg = "https://cdn.iol.pt/js/utils/JW8/assets/img/error.jpg";
378                errorCode = "(prd-201)";
379                break;
380
381              case "300":
382                errorMsg = "Lamentamos mas o v&iacute;deo n&atilde;o est&aacute; dispon&iacute;vel.";
383                errorImg = "https://cdn.iol.pt/js/utils/JW8/assets/img/error_smile.jpg";
384                errorCode = "(block-300)";
385                break;
386            }
387
388            var element = `<div id="iolplayer-blocked" style="background: url('${errorImg}') center/cover;">
389                              <div class="iolplayer-blocked-text">
390                              ${errorMsg} <small style="font-size: 10px;">${errorCode}</small>
391                              </div>
392                          </div>`;
393            _this.iolJWPlayer.playerElement.html(element);
394          } else {
395            callback();
396          }
397        },
398        success: function(data) {
399          callback();
400        }
401      });
402    },
403
404    /**
405     * Initializes the Player Container
406     */
407    initIOLPlayer: function() {
408      if (!this.iolJWPlayer.options.video) {
409        return false;
410      }
411
412      /* Defining is a playlist is being played */
413      this.iolJWPlayer.isPlaylist = this.iolJWPlayer.options.video.length > 1;
414
415      /* Creates the DIV for the player, based in the current date */
416      this.iolJWPlayer.playerDivId = "iolplayer_" + Date.now();
417      this.iolJWPlayer.playlistDivId = "iolplaylist_" + Date.now();
418      this.iolJWPlayer.playerElement.html(
419        `<div id='${this.iolJWPlayer.playerDivId}'  class='iolplayer_instance'></div><div id='${this.iolJWPlayer.playlistDivId}' class='iolplaylist-wrapper' style='display:none;'></div>`
420      );
421      this.iolJWPlayer.playlistElement = $(`#${this.iolJWPlayer.playlistDivId}`);
422
423      this.showIOLPlayer(this.iolJWPlayer.playerDivId, this.iolJWPlayer.options.showPreroll);
424    },
425
426    /**
427     * Setups the Player with the Playlist and Advertising
428     */
429    showIOLPlayer: function() {
430      var related = this.getRelated();
431      if (related) this.iolJWPlayer.options.related = related;
432
433      var playlist = this.getPlaylist();
434      if (playlist) this.iolJWPlayer.options.playlist = playlist;
435
436      this.iolJWPlayer.firstPlay = true;
437      this.iolJWPlayer.adPlaying = false;
438      this.iolJWPlayer.tvAdPlaying = false;
439      this.iolJWPlayer.liveMidNum = 0;
440      this.iolJWPlayer.isStoppable = this.isAStoppableVideo();
441      this.iolJWPlayer.consentString = "";
442
443      this.iolJWPlayer.playerInstance = jwplayer(this.iolJWPlayer.playerDivId);
444      let development = document.location.host.includes("localhost") || document.location.host.includes("dev.") || document.location.host.includes("stg.") || document.location.host.includes("tst.");
445
446      if (!development) {
447        if(this.iolJWPlayer.waitForConsent) {
448            this.waitForQuantcast();
449        } else {
450            this.obtainAdvertisingAndSetup();
451        }
452      } else {
453        console.info("IOLPlayer: DEV MODE");
454        this.obtainAdvertisingAndSetup();
455      }
456    },
457
458    waitForQuantcast() {
459      let count = 0;
460      const consentCheckInterval = setInterval(() => {
461        if (window["__tcfapi"] || count == 60) {
462          try {
463            window["__tcfapi"]("addEventListener", 2, (tcData, success) => {
464              if (success && tcData.tcString) {
465                this.iolJWPlayer.consentString = tcData.tcString;
466                this.obtainAdvertisingAndSetup();
467                window["__tcfapi"](
468                  "removeEventListener",
469                  2,
470                  success => {
471                    if (success) console.info("IOLPlayer: CMP listener removed");
472                  },
473                  tcData.listenerId
474                );
475              }
476            });
477            clearInterval(consentCheckInterval);
478          } catch(error) {
479            console.error(error);
480            clearInterval(consentCheckInterval);
481            console.error("IOLPlayer: CMP not loaded");
482            this.obtainAdvertisingAndSetup();
483          }
484        }
485        count++;
486      }, 100);
487    },
488
489    obtainAdvertisingAndSetup: function() {
490        if(this.iolJWPlayer.options.hasAdvertising) {
491            this.iolJWPlayer.options.advertising = this.getAdvertising();
492        }
493
494
495        this.iolJWPlayer.playerInstance.setup(this.iolJWPlayer.options);
496
497        this.setIOLPlayerEvents();
498    },
499
500    /**
501     * Validades if should stop the video after an ammount of time
502     */
503    isAStoppableVideo: function() {
504      for (var index = 0; index < this.iolJWPlayer.options.video.length; index++) {
505        if (/beachcam/.test(this.iolJWPlayer.options.video[index].videoUrl)) {
506          this.iolJWPlayer.options.preload = "metadata";
507          return {
508            name: "beachcam",
509            time: 300000
510          };
511        }
512      }
513      return;
514    },
515
516    /**
517     * Add related videos to the player.
518     * When the page content type is VIDEO redirects to video url.
519     */
520    getRelated: function() {
521      var relatedObject = {};
522
523      if (
524        (this.iolJWPlayer.options.project === "tvi" || this.iolJWPlayer.options.project === "nit") &&
525        !this.iolJWPlayer.options.relatedRSS
526      )
527        return;
528
529      if (this.iolJWPlayer.options.relatedRSS) {
530        relatedObject.file = this.iolJWPlayer.options.relatedRSS;
531        relatedObject.onclick = "link";
532        relatedObject.oncomplete = "none";
533        return relatedObject;
534      }
535
536      if (this.iolJWPlayer.options.pageContentType === "VIDEO" && this.iolJWPlayer.options.project) {
537        relatedObject.file = `https://front-api.iol.pt/api/v1/recomended?project=${this.iolJWPlayer.options.project.toLowerCase()}&mid=${
538          this.iolJWPlayer.options.video[0].id
539        }`;
540        //relatedObject.file = `https://www.iol.pt/jwplayer.xml?project=${this.iolJWPlayer.options.project.toLowerCase()}&mid=${
541        //  this.iolJWPlayer.options.video[0].id
542        //}`;
543        relatedObject.onclick = "link";
544        relatedObject.oncomplete = this.iolJWPlayer.options.videoRedirect ? "none" : "show";
545        return relatedObject;
546      }
547
548      if (
549        this.iolJWPlayer.options.pageContentType === "ARTICLE" &&
550        !this.iolJWPlayer.isPlaylist &&
551        this.iolJWPlayer.options.project
552      ) {
553        relatedObject.file = `https://front-api.iol.pt/api/v1/recomended?project=${this.iolJWPlayer.options.project.toLowerCase()}&mid=${
554          this.iolJWPlayer.options.video[0].id
555        }`;
556        //relatedObject.file = `https://www.iol.pt/jwplayer.xml?project=${this.iolJWPlayer.options.project.toLowerCase()}&mid=${
557        //  this.iolJWPlayer.options.video[0].id
558        //}`;
559        relatedObject.onclick = "link";
560        relatedObject.oncomplete = "show";
561        this.iolJWPlayer.options.nextUpDisplay = false;
562        return relatedObject;
563      }
564
565      return;
566    },
567
568    /**
569     * Creates a JWPlayer Playlist
570     */
571    getPlaylist: function() {
572      var playlistObject = {};
573
574      if (!this.iolJWPlayer.isPlaylist) {
575        this.iolJWPlayer.options.file =
576          this.iolJWPlayer.options.video[0].videoUrl +
577          (["nit", "embed"].includes(this.iolJWPlayer.options.project.toLowerCase()) ? "" : this.iolJWPlayer.playerTK);
578        this.iolJWPlayer.options.image = this.iolJWPlayer.options.imageUrl
579          ? this.iolJWPlayer.options.imageUrl
580          : this.iolJWPlayer.options.video[0].cover;
581        this.iolJWPlayer.options.title = this.iolJWPlayer.options.video[0].title;
582        return;
583      }
584
585      playlistObject.playlist = [];
586
587      for (var index = 0; index < this.iolJWPlayer.options.video.length; index++) {
588        playlistObject.playlist.push({
589          description: decodeURI(this.iolJWPlayer.options.video[index].description),
590          tags: this.iolJWPlayer.options.video[index].tags,
591          image: this.iolJWPlayer.options.video[index].cover,
592          title: decodeURI(this.iolJWPlayer.options.video[index].title),
593          sources: [
594            {
595              file:
596                this.iolJWPlayer.options.video[index].videoUrl +
597                (["nit", "embed"].includes(this.iolJWPlayer.options.project.toLowerCase()) === "nit"
598                  ? ""
599                  : this.iolJWPlayer.playerTK)
600            }
601          ],
602          duration: this.iolJWPlayer.options.video[index].duration
603        });
604      }
605      return playlistObject;
606    },
607
608    /**
609     * Sets the Advertising options
610     */
611    getAdvertising: function() {
612      var advertising = new Object();
613      var videoIndex =
614        this.iolJWPlayer.playerInstance && this.iolJWPlayer.playerInstance.getPlaylistIndex()
615          ? this.iolJWPlayer.playerInstance.getPlaylistIndex()
616          : 0;
617
618      var videoDuration = this.iolJWPlayer.options.video[videoIndex].duration;
619      var videoDurationRounded = this.roundToQuarter(videoDuration);
620      const adTags = this.iolJWPlayer.options.video[videoIndex].adTags ? encodeURIComponent(this.iolJWPlayer.options.video[videoIndex].adTags) : "";
621
622      if (this.iolJWPlayer.options.pub) {
623        var url = window.encodeURIComponent(window.location.href);
624        var videoSizes = "720x576";
625
626        var creativeProfile = "ALLvideos";
627        var gdpr = this.iolJWPlayer.consentString ? `&gdpr=1&gdpr_consent=${this.iolJWPlayer.consentString}` : '';
628
629        //Url ads VMAP 2
630        var adUrlNew = `https://pubads.g.doubleclick.net/gampad/ads?&sz=${videoSizes}&iu=${
631          this.iolJWPlayer.options.pub
632        }&ciu_szs&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&description_url=${url}&url=${url}${gdpr}&plcmt=1&correlator=${Math.floor(
633          Math.random() * 100000
634        ) + 1}&vid_d=${videoDurationRounded}&cust_params=category%3D${adTags}`;
635
636        advertising.client = "googima";
637        advertising.admessage = "Esta publicidade termina em xx segundos.";
638        advertising.vpaidcontrols = true;
639        //Added for VMAP
640        advertising.schedule = adUrlNew;
641
642        advertising.companiondiv = {
643          id: "MPU1",
644          width: 300,
645          height: 250
646        };
647
648        return advertising;
649      }
650
651      return;
652    },
653
654    getLiveMidRoll() {
655      var url = window.encodeURIComponent(window.location.href);
656      var videoSizes = "720x576";
657      var creativeProfile = "ALLvideos";
658      var gdpr = this.iolJWPlayer.consentString ? `&gdpr=1&gdpr_consent=${this.iolJWPlayer.consentString}`:'';
659      var midrollUrl = `https://pubads.g.doubleclick.net/gampad/ads?sz=${videoSizes}&iu=${this.iolJWPlayer.options.pub}&ciu_szs&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&plcmt=1&description_url=${url}&url=${url}${gdpr}&vpos=midroll&ad_rule=0`;
660
661      var correlator = Math.floor(Math.random() * 100000) + 1;
662      return `${midrollUrl}&liveMid=true&mridx=${this.iolJWPlayer.liveMidNum++}&correlator=${correlator}`;
663    },
664    /**
665     * Defines all the events to be caught
666     */
667    setIOLPlayerEvents: function() {
668      //due to scope
669      var _this = this;
670
671      /**** SETUP EVENTS ****/
672      this.iolJWPlayer.playerInstance.on("relatedReady", function(event) {
673        _this.iolJWPlayer.relatedPlugin = jwplayer().getPlugin("related");
674
675        _this.iolJWPlayer.relatedPlugin.on("play", function(event) {
676          var actionName = `recomendados jw ${event.auto ? "auto" : "click"}`;
677          try {
678            IOLAnalytics.setInternalOrigin(actionName, true); //old version
679          } catch (err) {
680            if (window.iol_analytics) {
681              //new version
682              window.iol_analytics.setInternalOrigin(actionName, true);
683            } else {
684              console.log("analytics module not loaded");
685            }
686          }
687        });
688      });
689
690      this.iolJWPlayer.playerInstance.on("ready", function(event) {
691        $(".jw-nextup").on("click", function() {
692          try {
693            IOLAnalytics.setInternalOrigin(`playlist overlay`, false);
694          } catch (err) {
695            if (window.iol_analytics) {
696              //new version
697              window.iol_analytics.setInternalOrigin(`playlist overlay`, false);
698            } else {
699              console.log("analytics module not loaded");
700            }
701          }
702        });
703        _this.iolJWPlayer.options.onReady.call(this, event);
704      });
705
706      this.iolJWPlayer.playerInstance.on("setupError", function(event) {
707        //_this.sendMonitoringErrorEvent("Setup Error", event);
708      });
709
710      /**** AD EVENTS ****/
711      this.iolJWPlayer.playerInstance.on("adRequest", function(event) {
712        _this.iolJWPlayer.adPlaying = true;
713        //_this.iolJWPlayer.options.onAdPlay.call(this, event);
714      });
715
716      this.iolJWPlayer.playerInstance.on("adPlay", function(event) {
717        _this.iolJWPlayer.options.onAdPlay.call(this, event);
718      });
719
720      this.iolJWPlayer.playerInstance.on("adImpression", function(event) {
721        _this.sendGAEvent("JW Player Ad Impression", "Impression", event.adposition);
722        _this.iolJWPlayer.options.onAdImpression.call(this, event);
723      });
724
725      this.iolJWPlayer.playerInstance.on("adPause", function(event) {
726        _this.iolJWPlayer.options.onAdPause.call(this, event);
727      });
728
729      this.iolJWPlayer.playerInstance.on("adComplete", function(event) {
730        _this.iolJWPlayer.adPlaying = false;
731        _this.sendGAEvent("JW Player Ad Complete", "Complete", event.adposition);
732
733        if (event.tag.includes("liveMid=true") && _this.iolJWPlayer.tvAdPlaying && _this.iolJWPlayer.consentString) {
734          if (_this.iolJWPlayer.tvAdPlaying) _this.iolJWPlayer.playerInstance.playAd(_this.getLiveMidRoll());
735        }
736        _this.iolJWPlayer.options.onAdComplete.call(this, event);
737      });
738
739      this.iolJWPlayer.playerInstance.on("adClick", function(event) {
740        _this.sendGAEvent("JW Player Ad Click", "Click", event.adposition);
741        _this.iolJWPlayer.options.onAdClick.call(this, event);
742      });
743
744      this.iolJWPlayer.playerInstance.on("adError", function(event) {
745        _this.iolJWPlayer.adPlaying = false;
746        _this.sendGAEvent("JW Player Ad Error", event.message, event.adposition);
747        _this.iolJWPlayer.options.onAdComplete.call(this, event);
748      });
749
750      /**** PLAY EVENTS ****/
751      this.iolJWPlayer.playerInstance.on("buffer", function(event) {
752        //_this.sendMonitoringEvent("Buffer", { bufferState: event });
753      });
754
755      //**** TimeStamp Feature ****//
756      if (_this.iolJWPlayer.options.video[0].liveType == "VOD") {
757        let playerTime = _this.iolJWPlayer.playerInstance;
758        playerTime.on("beforePlay", () => {
759          window.addEventListener('contextmenu', (event) => {
760            let btnTime = document.querySelector('.jw-btn-time');
761            let leftClick = document.querySelector('ul.jw-rightclick-list');
762
763            //create new right click menu option
764            if(btnTime == null){
765              let li = document.createElement("li");
766              li.setAttribute('class', 'jw-reset jw-rightclick-item');
767              let btnTime = document.createElement('button')
768              btnTime.setAttribute('class', 'jw-reset-text jw-rightclick-link jw-btn-time');
769              btnTime.textContent = "Copiar link com tempo";
770              li.appendChild(btnTime);
771              leftClick.appendChild(li);
772              event.stopPropagation();
773              btnTime.addEventListener('click', (ev) =>{
774                getTimeLink(leftClick);
775              });
776            }
777            // get url time param
778            function getTimeLink(leftClick){
779                let seconds = new URLSearchParams(window.location.search).getAll("t");
780                let link = window.location.href;
781                if( seconds <= 0 ){
782                  let totalSeconds = playerTime.getPosition();
783                  let convertedTime = secondsConverter(totalSeconds);
784                  link = window.location.href + '?t=' + convertedTime;
785                }
786                else{
787                  let totalSeconds = playerTime.getPosition();
788                  let convertedTime = secondsConverter(totalSeconds);
789                  link = link.replace(seconds, convertedTime);
790                }
791                try{
792                  navigator.clipboard.writeText(link);
793                }
794                catch(error){
795                  console.error('Error copying link to clipboard:', error);
796                }
797
798                //close right click menu after click
799                let parent = leftClick.parentNode;
800                parent.classList.remove('jw-open');
801
802            }
803
804            // convert seconds in hours and minutes
805            function secondsConverter(totalSeconds){
806              const totalMinutes = Math.floor(totalSeconds / 60);
807              const hours = Math.floor(totalMinutes / 60);
808              const minutes = String(totalMinutes % 60).padStart(2, '0');
809              const seconds = String(Math.floor(totalSeconds % 60)).padStart(2, '0');
810              const time = `${hours}:${minutes}:${seconds}`;
811
812              return time;
813            }
814          });
815
816            let urlTime = new URLSearchParams(window.location.search).get("t");
817            let matches = urlTime ? urlTime.match(/\d+/g) : null;
818            // convert hours and minutes in seconds
819            let hours = parseInt(matches[0]);
820            let minutes = parseInt(matches[1]);
821            let seconds = parseInt(matches[2]);
822
823            let timestamp = hours * 3600 + minutes * 60 + seconds;
824
825            var videoDuration = _this.iolJWPlayer.options.video[0].duration;
826
827            function seekTime(){
828              if (timestamp > 0 && timestamp < videoDuration) {
829                _this.hasplayer = true;
830                playerTime.seek(timestamp);
831              }
832            }
833            playerTime.on('firstFrame', () => {
834              seekTime();
835            });
836        });
837      }
838      //**** END TimeStamp Feature ****//
839
840      this.iolJWPlayer.playerInstance.on("play", function(event) {
841        var videoIndex = _this.iolJWPlayer.playerInstance ? _this.iolJWPlayer.playerInstance.getPlaylistIndex() : 0;
842        var el = _this.iolJWPlayer.options.embedPlatform ? _this.iolJWPlayer.options.embedPlatform : "Video";
843
844        if (_this.iolJWPlayer.firstPlay && ["INCONTENT VIDEO", "Video"].includes(el)) {
845          if (
846            _this.iolJWPlayer.isPlaylist &&
847            (event.playReason === "related-interaction" || event.playReason === "playlist")
848          ) {
849            /*
850                event.playReason: 'related-interaction' -> related screen
851                event.playReason: 'playlist' -> autoplay
852            */
853            var playType =
854              event.playReason === "interaction"
855                ? "overlay"
856                : event.playReason === "related-interaction"
857                ? "related"
858                : "auto";
859
860            try {
861              IOLAnalytics.setInternalOrigin(`playlist ${playType}`, false);
862            } catch (err) {
863              if (window.iol_analytics) {
864                //new version
865                window.iol_analytics.setInternalOrigin(`playlist ${playType}`, false);
866              } else {
867                console.log("analytics module not loaded");
868              }
869            }
870          }
871
872          _this.sendGAEvent("JW Player Video Plays", "Play", el);
873          _this.sendGAEvent("Play Programa", "Play", el);
874
875          /* Call SmartTop service if a smartoken is provided*/
876          if (_this.iolJWPlayer.options.smartToken) {
877            var ST = Array.isArray(_this.iolJWPlayer.options.smartToken)
878              ? _this.iolJWPlayer.options.smartToken[videoIndex]
879              : _this.iolJWPlayer.options.smartToken;
880            var URLVisit = "https://mais-vistos-producer.iol.pt/mais-vistos-producer?token=" + ST;
881            _this.iolJWPlayer.playerElement.append(
882              "<img class='smarttop' style='display:none;' src='" + URLVisit + "' height='1' width='1'/>"
883            );
884          }
885
886          _this.iolJWPlayer.firstPlay = false;
887          _this.iolJWPlayer.options.onFirstPlay.call(this, event);
888        }
889
890        /* Pauses the player if is a stoppable playlist */
891        if (_this.iolJWPlayer.isStoppable) {
892          setTimeout(function() {
893            _this.iolJWPlayer.playerInstance.stop();
894          }, _this.iolJWPlayer.isStoppable.time);
895        }
896
897        _this.iolJWPlayer.options.onPlay.call(this, event);
898      });
899
900      this.iolJWPlayer.playerInstance.on("pause", function(event) {
901        _this.iolJWPlayer.options.onPause.call(this, event);
902      });
903
904      this.iolJWPlayer.playerInstance.on("idle", function(event) {
905        _this.iolJWPlayer.options.onIdle.call(this, event);
906      });
907
908      this.iolJWPlayer.playerInstance.on("seek", function(event) {
909        _this.iolJWPlayer.options.onSeek.call(this, event);
910      });
911
912      this.iolJWPlayer.playerInstance.on("playAttemptFailed", function(event) {
913        //_this.sendMonitoringErrorEvent("Play Attempt Failed", event);
914      });
915
916      this.iolJWPlayer.playerInstance.on("time", function(event) {
917        _this.iolJWPlayer.options.onTime.call(this, event);
918      });
919
920      this.iolJWPlayer.playerInstance.on("complete", function(event) {
921        var videoIndex = _this.iolJWPlayer.playerInstance ? _this.iolJWPlayer.playerInstance.getPlaylistIndex() : 0;
922        var el = _this.iolJWPlayer.options.embedPlatform ? _this.iolJWPlayer.options.embedPlatform : "Video";
923
924        if (["INCONTENT VIDEO", "Video"].includes(el)) {
925          _this.sendGAEvent("JW Player Video Completes", "Complete", el);
926        }
927        _this.iolJWPlayer.options.onComplete.call(this, event);
928      });
929
930      this.iolJWPlayer.playerInstance.on("error", function(event) {
931        var videoIndex = _this.iolJWPlayer.playerInstance ? _this.iolJWPlayer.playerInstance.getPlaylistIndex() : 0;
932        var el = _this.iolJWPlayer.options.embedPlatform ? _this.iolJWPlayer.options.embedPlatform : "Video";
933        if (["INCONTENT VIDEO", "Video"].includes(el)) {
934          _this.sendGAEvent("JW Player Video Error", event.message, el);
935        }
936
937        //_this.sendMonitoringErrorEvent("Error", event);
938        _this.iolJWPlayer.options.onError.call(this, event);
939      });
940
941      /**** APPEAREANCE EVENTS ****/
942      this.iolJWPlayer.playerInstance.on("visualQuality", function(event) {
943        _this.sendGAEvent("JW Player Visual Quality", event.mode, event.level.height + " | " + event.level.bitrate);
944        _this.iolJWPlayer.options.onVisualQuality.call(this, event);
945      });
946
947      this.iolJWPlayer.playerInstance.on("viewable", function(event) {
948        //pause ad when isn't visible
949        event.viewable === 0
950          ? _this.iolJWPlayer.playerInstance.pauseAd(true)
951          : _this.iolJWPlayer.playerInstance.pauseAd(false);
952
953        if (_this.iolJWPlayer.options.playOnViewable) {
954          event.viewable === 0 ? _this.iolJWPlayer.playerInstance.pause() : _this.iolJWPlayer.playerInstance.play();
955        }
956      });
957
958      /**** PLAYLIST EVENTS ****/
959      this.iolJWPlayer.playerInstance.on("playlistItem", function(event) {
960        _this.iolJWPlayer.firstPlay = true;
961        _this.iolJWPlayer.options.onPlaylistItem.call(this, event);
962      });
963
964      this.iolJWPlayer.playerInstance.on("playlistComplete", function(event) {
965        _this.openRelated();
966        _this.iolJWPlayer.options.onPlaylistComplete.call(this, event);
967      });
968
969      var prevTagId;
970      this.iolJWPlayer.playerInstance.on('meta', (event) => {
971          if(!this.iolJWPlayer.options.hasAdvertising) {
972            return
973          }
974          const metadata = event?.metadata;
975        
976          if (metadata?.tag !== 'EXT-X-DATERANGE' || (!metadata.content?.includes('SCTE35-OUT') && !metadata.content?.includes('SCTE35-IN'))) {
977            return;
978          } 
979          
980        
981          const idMatch = metadata.content.match(/ID="([^"]+)"/);
982          const currentTagId = idMatch?.[1] ?? null;
983        
984          if (currentTagId && currentTagId === prevTagId) {
985            return;
986          } 
987          prevTagId = currentTagId;
988        
989          const isCueOut = metadata.content.includes('SCTE35-OUT');
990          const isCueIn  = metadata.content.includes('SCTE35-IN');
991          
992          const rawDuration = metadata.duration > 0 ? metadata.duration * 1000 : 120_000;
993          const duration    = Math.max(rawDuration - 10_000, 0);
994        
995          console.log(`[SCTE-35] ${new Date().toLocaleString('sv-SE', { timeZone: 'Europe/Lisbon' })} | tag=${metadata.tag} | id=${currentTagId} | duration=${metadata.duration}s | content=${metadata.content}`);
996        
997          if(isCueOut) {
998              const adUrlMidroll = _this.getMidrollUrl();
999              if (!adUrlMidroll) {
1000                console.warn('[SCTE-35] No midroll URL available, skipping ad.');
1001                return;
1002              }
1003            
1004              const adString = `${adUrlMidroll}&pmnd=0&pmxd=${duration}&pmad=10&pod=2`;
1005            
1006              try {
1007                _this.iolJWPlayer.playerInstance.playAd(adString);
1008              } catch (error) {
1009                console.error('[SCTE-35] playAd failed:', error);
1010              }
1011          }
1012        });
1013    },
1014
1015    /**
1016     * Sends the Google Analytics Events
1017     */
1018    sendGAEvent: function(category, action, label) {
1019      var playerVersion = this.iolJWPlayer.playerInstance.version.split("+")[0];
1020      var videoIndex =
1021        this.iolJWPlayer.playerInstance && this.iolJWPlayer.playerInstance.getPlaylistIndex()
1022          ? this.iolJWPlayer.playerInstance.getPlaylistIndex()
1023          : 0;
1024
1025      if (this.iolJWPlayer.options.shouldSendEvents) {
1026        if (typeof dataLayer !== "undefined") {
1027          if (window.iol_analytics) {
1028            this.sendGAEventByIOLAnalytics(category, action, label, playerVersion, videoIndex);
1029          } else {
1030            this.sendGAEventByDataLayer(category, action, label, playerVersion, videoIndex);
1031          }
1032        } else if (typeof ga !== "undefined") {
1033          ga("send", "event", category, label, action);
1034        }
1035      }
1036    },
1037
1038    sendGAEventByDataLayer: function(category, action, label, playerVersion, videoIndex) {
1039      dataLayer.push({
1040        "versao player": `JW_${playerVersion}|IOL_${JW_IOL_Version}`,
1041        eventCategory: category,
1042        eventLabel: label,
1043        eventAction: action,
1044        Programa_Id: decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].program.id),
1045        Programa_Nome: decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].program.name),
1046        Temporada_Id: decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].program.season),
1047        Episodio_Id: decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].program.ep),
1048        Multimedia_Id: decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].id),
1049        Titulo: this.limitEncodedText(this.iolJWPlayer.options.video[videoIndex].title, 150),
1050        Videoplay_Simultaneo: "S", //S|N
1051        Tipo: this.iolJWPlayer.options.video[videoIndex].videoType, //Clip|Integra|Live|Macro
1052        Live: this.iolJWPlayer.options.video[videoIndex].liveType, //DIRETO|ONLIVE|VOD
1053        AdUnit: this.iolJWPlayer.options.pub, //PUB|undefined
1054        Video_Play: 1,
1055        Plataforma: this.iolJWPlayer.options.playerPlatform,
1056        Duracao: this.roundToQuarter(this.iolJWPlayer.options.video[videoIndex].duration),
1057        event: "gaEvent"
1058      });
1059      dataLayer.push({
1060        "versao player": ""
1061      });
1062    },
1063    sendGAEventByIOLAnalytics: function(category, action, label, playerVersion, videoIndex) {
1064      let iolAnalytics = window.iol_analytics;
1065      iolAnalytics.sendEvent(
1066        category,
1067        label,
1068        action,
1069        "gaEvent",
1070        iolAnalytics.createDataLayerObjectWithDuration(
1071          "Video",
1072          decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].title ? this.iolJWPlayer.options.video[videoIndex].title.replace("%", "") : ""),
1073          decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].id),
1074          decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].program.ep),
1075          decodeURIComponent(this.iolJWPlayer.options.video[videoIndex].program.name),
1076          "",
1077          "",
1078          "S",
1079          this.iolJWPlayer.options.video[videoIndex].videoType,
1080          this.iolJWPlayer.options.video[videoIndex].liveType,
1081          `JW_${playerVersion}|IOL_${JW_IOL_Version}`,
1082          this.iolJWPlayer.options.playerPlatform,
1083          this.iolJWPlayer.options.pub,
1084          "",
1085          false,
1086          this.roundToQuarter(this.iolJWPlayer.options.video[videoIndex].duration)
1087        )
1088      );
1089      iolAnalytics.sendEvent("", "", "", "", undefined, {
1090        "versao player": ""
1091      });
1092    },
1093
1094    limitEncodedText: function(string) {
1095      var decodedStr = string.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
1096      decodedStr = encodeURIComponent(decodedStr);
1097      if (decodedStr.length > 150) {
1098        decodedStr = decodedStr.substring(0, 150);
1099        while (!this.isAValidEncodedText(decodedStr)) {
1100          decodedStr = this.limitEncodedTextdText(decodedStr);
1101        }
1102      }
1103      return decodeURIComponent(decodedStr);
1104    },
1105
1106    isAValidEncodedText: function(string) {
1107      try {
1108        decodeURIComponent(string);
1109        return true;
1110      } catch (err) {
1111        return false;
1112      }
1113    },
1114
1115    limitEncodedTextdText: function(string) {
1116      return string.substring(0, string.lastIndexOf("%"));
1117    },
1118    /**
1119     * Sends an event to the Graylog
1120     * @param {string} segmentation
1121     * @param {string} event
1122     */
1123    sendMonitoringEvent: function(segmentation, event) {
1124      var playerVersion = this.iolJWPlayer.playerInstance
1125        ? this.iolJWPlayer.playerInstance.version.split("+")[0]
1126        : "Error";
1127      var userAgent = navigator.userAgent;
1128      var host = window.location.href;
1129      var quality = this.iolJWPlayer.playerInstance ? this.iolJWPlayer.playerInstance.getVisualQuality() : undefined;
1130
1131      var videoIndex =
1132        this.iolJWPlayer.playerInstance && this.iolJWPlayer.playerInstance.getPlaylistIndex()
1133          ? this.iolJWPlayer.playerInstance.getPlaylistIndex()
1134          : 0;
1135      if (!this.iolJWPlayer.user) this.getUser();
1136
1137      var errorObj = {
1138        message: `INFO | ${segmentation}`,
1139        host: `${host}`,
1140        "user-agent": `${userAgent}`,
1141        _u: this.iolJWPlayer.user.uname,
1142        _file: this.iolJWPlayer.options.video[videoIndex].videoUrl,
1143        _bufferState: !event.bufferState ? "" : event.bufferState,
1144        _network: {
1145          downlink: navigator.connection.downlink,
1146          effectiveType: navigator.connection.effectiveType
1147        },
1148        _resolution: !quality
1149          ? ""
1150          : {
1151              mode: quality.mode,
1152              height: quality.level.height
1153            },
1154        _version: `JW_${playerVersion}|IOL_${JW_IOL_Version}`
1155      };
1156
1157      var _this = this;
1158
1159      errorObj["_ip"] = _this.iolJWPlayer.user.IPCode;
1160      errorObj["_countryCode"] = _this.iolJWPlayer.user.IPCountryCode;
1161
1162      $.ajax({
1163        type: "POST",
1164        url: "https://services.iol.pt/pevents",
1165        data: JSON.stringify(errorObj),
1166        contentType: "application/json",
1167        dataType: "json"
1168      });
1169    },
1170
1171    /**
1172     * Sends an error event to the Graylog
1173     * @param {string} segmentation
1174     * @param {string} event
1175     * @param {function} callback
1176     */
1177    sendMonitoringErrorEvent: function(segmentation, event, callback) {
1178      var playerVersion = this.iolJWPlayer.playerInstance
1179        ? this.iolJWPlayer.playerInstance.version.split("+")[0]
1180        : "Error";
1181      var userAgent = navigator.userAgent;
1182      var host = window.location.href;
1183      var quality = this.iolJWPlayer.playerInstance ? this.iolJWPlayer.playerInstance.getVisualQuality() : undefined;
1184      var videoIndex =
1185        this.iolJWPlayer.playerInstance && this.iolJWPlayer.playerInstance.getPlaylistIndex()
1186          ? this.iolJWPlayer.playerInstance.getPlaylistIndex()
1187          : 0;
1188
1189      if (!this.iolJWPlayer.user) this.getUser();
1190
1191      var errorObj = {
1192        message: `${segmentation} | ${event.message}`,
1193        host: `${host}`,
1194        "user-agent": `${userAgent}`,
1195        _code: event.code ? `${event.code}` : "",
1196        _type: event.type ? `${event.type}` : "",
1197        _u: this.iolJWPlayer.user.uname,
1198        _file: this.iolJWPlayer.options.video[videoIndex].videoUrl,
1199        _sourceError: !event.sourceError
1200          ? ""
1201          : {
1202              type: `${event.sourceError.type}`,
1203              details: `${event.sourceError.details}`,
1204              fatal: `${event.sourceError.fatal}`,
1205              url: `${event.sourceError.url}`
1206            },
1207        _bufferState: !event.bufferState ? "" : event.bufferState,
1208        _network: {
1209          downlink: navigator.connection.downlink,
1210          effectiveType: navigator.connection.effectiveType
1211        },
1212        _resolution: !quality
1213          ? ""
1214          : {
1215              mode: quality.mode,
1216              level: quality.level
1217            },
1218        _version: `JW_${playerVersion}|IOL_${JW_IOL_Version}`
1219      };
1220
1221      var _this = this;
1222
1223      errorObj["_ip"] = _this.iolJWPlayer.user.IPCode;
1224      errorObj["_countryCode"] = _this.iolJWPlayer.user.IPCountryCode;
1225
1226      this.errorValidation(errorObj, callback);
1227    },
1228
1229    /**
1230     * Validates the different types of error
1231     * @param {JSON} errorObj
1232     * @param {function} callback
1233     */
1234    errorValidation: function(errorObj, callback) {
1235      /* Validates cookie creation date */
1236      var cookieExp = $.cookie("jwiol_c");
1237      var videoIndex =
1238        this.iolJWPlayer.playerInstance && this.iolJWPlayer.playerInstance.getPlaylistIndex()
1239          ? this.iolJWPlayer.playerInstance.getPlaylistIndex()
1240          : 0;
1241
1242      if (cookieExp) {
1243        var creationDate = Date.parse(cookieExp);
1244        var currentDate = new Date();
1245
1246        if ((currentDate.getTime() - creationDate) / 1000 / 3600 > 20) {
1247          errorObj["_mcdError"] = "errorExpired";
1248          $.ajax({
1249            type: "POST",
1250            url: "https://services.iol.pt/pevents",
1251            data: JSON.stringify(errorObj),
1252            contentType: "application/json",
1253            dataType: "json"
1254          });
1255
1256          if (callback) callback(errorObj["_mcdError"]);
1257        }
1258      }
1259
1260      /* If is a live transmition with the error cod 232403 validates the rights of the transmission */
1261      if (this.iolJWPlayer.options.video[videoIndex].liveType == "DIRETO" && errorObj["_
1261code"] == "232403") {
1262        this.getErrorDetails(errorObj, callback);
1263      } else {
1264        errorObj["_mcdError"] = "errorDefault";
1265        $.ajax({
1266          type: "POST",
1267          url: "https://services.iol.pt/pevents",
1268          data: JSON.stringify(errorObj),
1269          contentType: "application/json",
1270          dataType: "json"
1271        });
1272
1273        if (callback) callback(errorObj["_mcdError"]);
1274      }
1275    },
1276
1277    /**
1278     * Determines the error reason
1279     * @param {JSON} errorObj
1280     * @param {function} callback
1281     */
1282    getErrorDetails: function(errorObj, callback) {
1283      var videoIndex =
1284        this.iolJWPlayer.playerInstance && this.iolJWPlayer.playerInstance.getPlaylistIndex()
1285          ? this.iolJWPlayer.playerInstance.getPlaylistIndex()
1286          : 0;
1287
1288      $.get(
1289        `https://services.iol.pt/videoMonitoring?canal=${this.iolJWPlayer.options.video[videoIndex].channel}&countrycode=${errorObj["_countryCode"]}`,
1290        function(data) {
1291          data = JSON.parse(data);
1292          errorObj["_mcdError"] = data["error"];
1293          errorObj["_mcdDetails"] = data["programa"];
1294
1295          $.ajax({
1296            type: "POST",
1297            url: "https://services.iol.pt/pevents",
1298            data: JSON.stringify(errorObj),
1299            contentType: "application/json",
1300            dataType: "json"
1301          });
1302
1303          if (callback) callback(errorObj["_mcdError"]);
1304        }
1305      ).fail(function() {
1306        errorObj["_mcdError"] = "errorFailed";
1307        $.ajax({
1308          type: "POST",
1309          url: "https://services.iol.pt/pevents",
1310          data: JSON.stringify(errorObj),
1311          contentType: "application/json",
1312          dataType: "json"
1313        });
1314
1315        if (callback) callback(errorObj["_mcdError"]);
1316      });
1317    },
1318
1319    /**
1320     * Gets the Username
1321     */
1322    getUser: function() {
1323      var user = { u: "", id: "id" , subscribedProducts:[]};
1324      this.iolJWPlayer.user = {};
1325
1326      var sluserx1 = localStorage.getItem("userx1");
1327      var slx1user = localStorage.getItem("x1user");
1328
1329      if (sluserx1 != null) {
1330        sl = JSON.parse(sluserx1);
1331        user["u"] = sl.userName ? sl.userName : "";
1332        user["id"] = sl.id ? sl.id : "";
1333        user["subscribedProducts"] = sl.subscribedProducts ? sl.subscribedProducts : [];
1334      }
1335      if (slx1user != null) {
1336        sl = JSON.parse(slx1user);
1337        user["u"] = sl.userName ? sl.userName : "";
1338        user["id"] = sl.id ? sl.id : "";
1339        user["subscribedProducts"] = sl.subscribedProducts ? sl.subscribedProducts : [];
1340      }
1341
1342      this.iolJWPlayer.user.uname = user["u"];
1343      this.iolJWPlayer.user.uid = user["id"];
1344      var _this = this;
1345      $.ajax({
1346        url: "https://services.iol.pt/getgcc/ipdetails",
1347        type: "get",
1348        async: false,
1349        success: function(data) {
1350          data = data.split("|");
1351          _this.iolJWPlayer.user.IPCode = data[0];
1352          _this.iolJWPlayer.user.IPCountryCode = data[1];
1353          user["i"] = btoa(data[0]);
1354        },
1355        error: function() {
1356          console.log("error");
1357        }
1358      });
1359
1360      return user;
1361    },
1362
1363    shouldPlayAds(user) {
1364      return !(user && user["subscribedProducts"] != null && user["subscribedProducts"].length > 0 && noPubProducts.some(r=> user["subscribedProducts"].includes(r)));
1365    },
1366
1367    getMidrollUrl: function () {
1368      var url = window.encodeURIComponent(window.location.href);
1369      var videoSizes = "720x576";
1370      var gdpr = this.iolJWPlayer.consentString ? `&gdpr=1&gdpr_consent=${this.iolJWPlayer.consentString}` : '';
1371      //Url ads VAST
1372      let adUrlMidroll = `https://pubads.g.doubleclick.net/gampad/ads?sz=${videoSizes}&iu=${this.iolJWPlayer.options.pub}&ciu_szs&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&plcmt=1&url=${url}${gdpr}&vpos=midroll&correlator=${Math.floor(1e5 * Math.random()) + 1}&ad_rule=0`;
1373
1374      return adUrlMidroll;
1375    },
1376
1377    roundToQuarter : function(seconds) {
1378        const num = Number(seconds);
1379
1380        if (isNaN(num) || num < 0) {
1381            return;
1382        }
1383
1384        var remainder = num % 15;
1385
1386        var rounded = remainder === 0 ? num : num + (15 - remainder);
1387
1388        return rounded;
1389      },
1390    jwplayer: function() {
1391      return this.iolJWPlayer.playerInstance;
1392    },
1393
1394    play: function() {
1395      return jwplayer(this.iolJWPlayer.playerDivId).play();
1396    },
1397
1398    pause: function() {
1399      return jwplayer(this.iolJWPlayer.playerDivId).pause();
1400    },
1401
1402    stop: function() {
1403      return jwplayer(this.iolJWPlayer.playerDivId).stop();
1404    },
1405
1406    change: function(videoIndex) {
1407      return jwplayer(this.iolJWPlayer.playerDivId).playlistItem(videoIndex);
1408    },
1409
1410    mute: function() {
1411      return jwplayer(this.iolJWPlayer.playerDivId).setMute(true);
1412    },
1413
1414    unmute: function() {
1415      return jwplayer(this.iolJWPlayer.playerDivId).setMute(false);
1416    },
1417
1418    openRelated: function() {
1419      jwplayer(this.iolJWPlayer.playerDivId)
1420        .getPlugin("related")
1421        .open();
1422    },
1423
1424    getPosition: function() {
1425      return jwplayer(this.iolJWPlayer.playerDivId).getPosition();
1426    },
1427
1428    getState: function() {
1429      return jwplayer(this.iolJWPlayer.playerDivId).getState();
1430    },
1431
1432    seek: function(position) {
1433      return jwplayer(this.iolJWPlayer.playerDivId).seek(position);
1434    }
1435  };
1436})(jQuery, window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.