UNPKG

@slashedcloud/player

Version:

A media player application utilizing Shaka Player for adaptive video streaming, capable of playing HLS, MPD and plain HTTP video streams.

949 lines (948 loc) 39.1 kB
import './Slashedcloud-player.css';var ge = Object.defineProperty; var J = Object.getOwnPropertySymbols; var be = Object.prototype.hasOwnProperty, Ce = Object.prototype.propertyIsEnumerable; var X = (o) => { throw TypeError(o); }; var W = (o, t, e) => t in o ? ge(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e, P = (o, t) => { for (var e in t || (t = {})) be.call(t, e) && W(o, e, t[e]); if (J) for (var e of J(t)) Ce.call(t, e) && W(o, e, t[e]); return o; }; var h = (o, t, e) => W(o, typeof t != "symbol" ? t + "" : t, e), K = (o, t, e) => t.has(o) || X("Cannot " + e); var r = (o, t, e) => (K(o, t, "read from private field"), e ? e.call(o) : t.get(o)), g = (o, t, e) => t.has(o) ? X("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(o) : t.set(o, e), w = (o, t, e, i) => (K(o, t, "write to private field"), i ? i.call(o, e) : t.set(o, e), e), f = (o, t, e) => (K(o, t, "access private method"), e); var Z = (o, t, e, i) => ({ set _(s) { w(o, t, s, e); }, get _() { return r(o, t, i); } }); var b = (o, t, e) => new Promise((i, s) => { var n = (c) => { try { l(e.next(c)); } catch (d) { s(d); } }, a = (c) => { try { l(e.throw(c)); } catch (d) { s(d); } }, l = (c) => c.done ? i(c.value) : Promise.resolve(c.value).then(n, a); l((e = e.apply(o, t)).next()); }); import { a as A, s as y } from "./shaka-player.ui-CvkRFlcE.js"; import { l as ke, _ as ye } from "./Common-B3lKdzU9.js"; import { P as m, S as p } from "./PlayerError-JebC7rsX.js"; /*! * SlashedCloud v0.1.2 (https://github.com/SlashedCloud/player#readme) * Copyright 2024-2024 rogerio.jardim@fedrax.pt * Licensed under Apache (https://github.com/SlashedCloud/player/blob/develop/LICENSE) */ const ee = { RESOLUTION: "settings", CHECKMARK: "done" }, ve = { Ids: { AUTO_QUALITY: "AUTO_QUALITY", RESOLUTION: "RESOLUTION", QUALITY: "QUALITY" } }; var E; class we extends A.ui.SettingsMenu { constructor(e, i) { super(e, i, ee.RESOLUTION); g(this, E, []); this.button.classList.add("shaka-resolution-button"), this.button.classList.add("shaka-tooltip-status"), this.menu.classList.add("shaka-resolutions"), this.eventManager.listen(i, "trackschanged", () => { console.log("trackschanged"), this.updateResolutionSelection_(); }), this.updateResolutionSelection_(); } /** @private */ updateResolutionSelection_() { return b(this, null, function* () { const e = se.get(this.controls); e && w(this, E, e.srcSet); const i = r(this, E).find((a) => a.active); w(this, E, r(this, E).filter((a, l) => r(this, E).findIndex((d) => d.label == a.label && d.type == a.type && d.url == a.url) == l)); const s = this.menu.querySelector(".shaka-back-to-overflow-button"); A.util.Dom.removeAllChildren(this.menu), s && this.menu.appendChild(s); const n = { abr: { enabled: !1 } }; this.player.configure(n); for (const a of r(this, E)) { const l = document.createElement("button"); l.setAttribute("type", "button"), l.classList.add("explicit-resolution"), this.eventManager.listen(l, "click", this.onTrackSelected_.bind(this, a)); const c = document.createElement("span"); c.textContent = a.label, l.appendChild(c), a == i && (l.ariaSelected = "true", l.appendChild(z.checkmarkIcon()), c.classList.add("shaka-chosen-item"), this.currentSelection.textContent = c.textContent), this.menu.appendChild(l); } z.focusOnTheChosenItem(this.menu), this.updateLocalizedStrings_(), z.setDisplay(this.button, r(this, E).length > 0); }); } /** * @private */ updateLocalizedStrings_() { const i = ve.Ids.RESOLUTION; this.button.ariaLabel = this.localization.resolve(i), this.backButton.ariaLabel = this.localization.resolve(i), this.backSpan.textContent = this.localization.resolve(i), this.nameSpan.textContent = this.localization.resolve(i); } onTrackSelected_(e) { return b(this, null, function* () { const i = this.video.currentTime, s = this.video.paused; if (this.video.src !== e.url) { this.video.src = e.url, this.video.currentTime = i, s || (yield this.video.play()); for (const n of r(this, E)) n.active = !1; e.active = !0, this.controls.dispatchEvent(new A.util.FakeEvent("resolutionselectionupdated")), this.updateResolutionSelection_(); } }); } } E = new WeakMap(); const z = class { /** * @return {!Element} */ static checkmarkIcon() { const o = document.createElement("i"); return o.classList.add("material-icons-round"), o.classList.add("shaka-chosen-item"), o.textContent = ee.CHECKMARK, o.ariaHidden = "true", o; } /** * Finds a descendant of |menu| that has a 'shaka-chosen-item' class * and focuses on its' parent. * * @param {HTMLElement} menu */ static focusOnTheChosenItem(o) { if (!o) return; const t = this.getDescendantIfExists(o, "shaka-chosen-item"); t && t.parentElement.focus(); } /** * @param {!HTMLElement} element * @param {string} className * @return {?Element} */ static getDescendantIfExists(o, t) { const e = o.getElementsByClassName(t); return e.length ? e[0] : null; } /** * Depending on the value of display, sets/removes the css class of element to * either display it or hide it. * * @param {Element} element * @param {boolean} display */ static setDisplay(o, t) { o && (t ? o.classList.remove("shaka-hidden") : o.classList.add("shaka-hidden")); } }; var L, x, U, Q; class Ee extends A.ui.SeekBar { constructor(e, i) { super(e, i); g(this, x); h(this, "custumSeekBarActive", !1); h(this, "isChaptersEnabled", !1); h(this, "isMarkersEnabled", !1); h(this, "isThumbnailEnabled", !1); g(this, L); h(this, "chapters", []); h(this, "markers", []); h(this, "thumbnailWrapper"); h(this, "thumbnailMarkerContainer"); h(this, "thumbnailMarkerText"); h(this, "thumbnailMarkerImage"); h(this, "thumbnailMarkerTime"); h(this, "markerContainer"); h(this, "chapterContainer"); h(this, "chapterContainerText"); h(this, "preloadedMarkerImages", /* @__PURE__ */ new Map()); h(this, "hideChapters"); h(this, "hideMarkers"); h(this, "thumbnailContainer"); h(this, "eventManager"); h(this, "controlsContainer"); const s = i.getLocalization(), [n] = s ? s.getCurrentLocales() : ["en"]; if (!this.player) throw new Error("Player is not available"); this.controlsContainer = i.getControlsContainer(), this.chapterContainerText = document.createElement("div"), this.chapterContainerText.id = "shaka-chapter-text", this.chapterContainer = document.createElement("div"), this.chapterContainer.classList.add("shaka-chapter-container"), this.chapterContainer.appendChild(this.chapterContainerText), this.markerContainer = document.createElement("div"), this.markerContainer.classList.add("shaka-marker-container"), this.thumbnailMarkerText = document.createElement("div"), this.thumbnailMarkerText.id = "shaka-player-ui-thumbnail-marker-text", this.thumbnailMarkerContainer = document.createElement("div"), this.thumbnailMarkerContainer.id = "shaka-player-ui-thumbnail-marker-container", this.thumbnailMarkerTime = document.createElement("div"), this.thumbnailMarkerTime.id = "shaka-player-ui-thumbnail-marker-time", this.thumbnailMarkerImage = document.createElement("img"), this.thumbnailMarkerImage.id = "shaka-player-ui-thumbnail-marker-image", this.thumbnailMarkerContainer.appendChild(this.thumbnailMarkerImage), this.thumbnailMarkerContainer.appendChild(this.thumbnailMarkerText), this.thumbnailMarkerContainer.appendChild(this.thumbnailMarkerTime), this.thumbnailWrapper = document.createElement("div"), this.thumbnailWrapper.id = "shaka-player-ui-thumbnail-wrapper", this.thumbnailWrapper.appendChild(this.thumbnailMarkerContainer), this.container.appendChild(this.thumbnailWrapper), window.innerWidth < 768 && this.thumbnailMarkerText.classList.add("mobile"), this.eventManager = new A.util.EventManager(), this.hideChapters = new A.util.Timer(() => { this.hideChapters_(); }), this.hideMarkers = new A.util.Timer(() => { this.hideMarkers_(); }), this.isThumbnailEnabled = this.player.getImageTracks().length > 0, this.thumbnailContainer = this.container.querySelector("#shaka-player-ui-thumbnail-container"), this.thumbnailContainer && this.thumbnailWrapper.appendChild(this.thumbnailContainer); const c = this.player.getChaptersTracks().find((T) => T.language === n) ? this.player.getChapters(n) : this.player.getChapters("en"); c && c.length > 0 && this.registerChapters(c); const d = this.player.getChapters("markers"); d && d.length > 0 && this.registerMarkers(d), this.eventManager.listen(this.container, "mouseleave", () => { this.isChaptersEnabled && (this.hideChapters.stop(), this.hideChapters.tickAfter( /* seconds= */ 0.05 )), this.isMarkersEnabled && (this.hideMarkers.stop(), this.hideMarkers.tickAfter( /* seconds= */ 0.05 )); }); } /** * @override */ update() { super.update(), this.isChaptersEnabled && this.updateChapters(); } /** * Called by the base class when user interaction with the input element * ends. * * @override */ onChangeEnd() { super.onChangeEnd(), this.isChaptersEnabled && (this.hideChapters.stop(), this.hideChapters.tickAfter( /* seconds= */ 0.25 )), this.isMarkersEnabled && (this.hideMarkers.stop(), this.hideMarkers.tickAfter( /* seconds= */ 0.25 )); } /** * Update the video element's state to match the input element's state. * Called by the base class when the input element changes. * * @override */ onChange() { super.onChange(), this.isChaptersEnabled && this.onChangeChapters(); } changeTo(e) { super.changeTo(e); } updateChapters() { const e = this.controls.getConfig(), i = e.seekBarColors, s = this.getValue(), n = this.video.buffered.length, a = n ? this.video.buffered.start(0) : 0, l = n ? this.video.buffered.end(n - 1) : 0, c = this.player.seekRange(); if (n == 0) { this.container.style.background = i.base; return; } if (!this.chapterContainer) return; const d = Math.max(a, c.start), T = Math.min(l, c.end), S = Math.min(Math.max(s, c.start), c.end), q = d - c.start, ue = T - c.start, me = S - c.start, pe = e.showUnbufferedStart ? i.base : i.played; for (const v of this.chapters) { if (!v.element) return; if (s > v.endTime) { v.element.style.background = i.played; continue; } if (s < v.startTime) { v.element.style.background = i.base; continue; } const $ = v.endTime - v.startTime, H = (q - v.startTime) / $ || 0, G = (ue - v.startTime) / $ || 0, Y = (me - v.startTime) / $ || 0, fe = [ "to right", this.makeColor_(pe, H), this.makeColor_(i.played, H), this.makeColor_(i.played, Y), this.makeColor_(i.buffered, Y), this.makeColor_(i.buffered, G), this.makeColor_(i.base, G) ]; v.element.style.background = "linear-gradient(" + fe.join(",") + ")"; } } onChangeChapters() { const e = parseFloat(this.bar.min), i = parseFloat(this.bar.max), s = this.bar.getBoundingClientRect(), n = Math.round(this.getValue()), a = (i - e) / s.width, l = (n - e) / a; f(this, x, U).call(this, l, n); } setChapters(e) { const i = this.player.seekRange(), s = i.end - i.start; e = e.filter((a) => a.startTime >= i.start && a.startTime <= i.end), e = e.filter((a) => a.endTime <= i.end && a.endTime >= i.start); for (const a in e) { const l = e[a]; l.id = a; const c = e[parseInt(a) + 1]; c && c.startTime > l.endTime && e.push({ id: `${a}-break`, startTime: l.endTime, endTime: c.startTime, title: "" }); } e.sort((a, l) => a.startTime - l.startTime); const n = e[e.length - 1]; if (n.endTime) { const a = s - n.endTime; n.endTime > i.end || a <= 1 ? n.endTime = i.end : e.push({ id: `${n.id}-break`, startTime: n.endTime, endTime: s, title: "" }); } for (const a of e) { const l = document.createElement("div"); l.classList.add("shaka-chapter"), l.id = `chapter-${a.id}`; const c = this.calcFrac(a, i, s); l.style.width = `calc(${(c.endFrac - c.startFrac) * 100}% - 4px)`; const d = document.createElement("div"); d.classList.add("shaka-chapter-spacing"), d.style.width = "4px", this.chapterContainer.appendChild(l), this.chapterContainer.appendChild(d), a.element = l; } this.chapters = e, this.eventManager.listen(this.bar, "mousemove", (a) => b(this, null, function* () { const l = this.bar.getBoundingClientRect(), c = parseFloat(this.bar.min), d = parseFloat(this.bar.max), T = a.clientX - l.left, S = (d - c) / l.width, q = Math.round(c + S * T); f(this, x, U).call(this, T, q); })), this.thumbnailWrapper.style.bottom = "25px"; } calcFrac(e, i, s) { const a = (e.startTime - i.start) / s || 0; let l = a + 0.01; return e.endTime && (l = (e.endTime - i.start) / s || 0), { startFrac: a, endFrac: l }; } /** * @param {string} color * @param {number} fract * @return {string} * @private */ makeColor_(e, i) { return e + " " + i * 100 + "%"; } setMarkers(e) { if (!e.length) { this.markerContainer.style.background = "transparent"; return; } const i = this.player.seekRange(), s = i.end - i.start; for (const n in e) { const a = e[n]; if (a.time = Number(a.time), !(a.time >= i.start && a.time < i.end)) continue; this.preloadImage(a.thumb, a.time); const c = (a.time - i.start) / s || 0, d = document.createElement("div"); d.classList.add("shaka-marker"), d.id = `marker-${n}`, d.dataset.time = `${a.time}`, d.style.left = `${c * 100}%`, a.element = d, this.markerContainer.appendChild(d), this.eventManager.listen(d, "click", this.changeTo.bind(this, a.time)), this.eventManager.listen(d, "mousemove", f(this, x, Q).bind(this, a)), this.eventManager.listen(d, "mouseleave", () => { this.hideMarkers.stop(), this.hideMarkers.tickNow(); }), this.eventManager.listen(d, "showMarker", f(this, x, Q).bind(this, a)); } this.eventManager.listen(this.controlsContainer, "hideMarker", () => { this.hideMarkers.stop(), this.hideMarkers.tickNow(); }), this.eventManager.listen(this.bar, "mousemove", () => { this.hideMarkers.stop(), this.hideMarkers.tickNow(); }), this.markers = e; } /** * Preload image * @param {string} url * @param {number} time */ preloadImage(e, i) { return b(this, null, function* () { if (this.preloadedMarkerImages.has(i)) return; const s = new Image(); s.src = e, s.onload = () => this.preloadedMarkerImages.set(i, s); }); } /** * Load image * @param {string} url * @param {string} alt */ loadImage(e, i) { return b(this, null, function* () { return new Promise((s, n) => { this.thumbnailMarkerImage.onload = () => s(!0), this.thumbnailMarkerImage.onerror = n, this.thumbnailMarkerImage.src = e, this.thumbnailMarkerImage.alt = i; }); }); } /** * @param {number} totalSeconds * @private */ timeFormatter_(e) { const i = Math.round(e), s = Math.floor(i / 3600); let n = Math.floor((i - s * 3600) / 60), a = i - s * 3600 - n * 60; return a < 10 && (a = "0" + a), s > 0 ? (n < 10 && (n = "0" + n), s + ":" + n + ":" + a) : n + ":" + a; } hideChapters_() { var e; if (this.isChaptersEnabled) { this.chapterContainerText.style.visibility = "hidden"; for (const i of this.chapters) (e = i.element) == null || e.classList.remove("shaka-chapter-select"); this.controlsContainer.dispatchEvent(new CustomEvent("chapterHidden")); } } hideMarkers_() { var e; if (this.isMarkersEnabled && r(this, L)) { w(this, L, void 0), this.thumbnailMarkerContainer.style.visibility = "hidden", this.thumbnailMarkerImage.src = "", this.thumbnailMarkerImage.alt = "", this.thumbnailMarkerTime.textContent = "", this.thumbnailMarkerText.textContent = ""; for (const i of this.markers) (e = i.element) == null || e.classList.remove("active"); this.controlsContainer.dispatchEvent(new CustomEvent("markerHidden")); } } // registerChapters(locale: string) { registerChapters(e) { if (!e || !e.length) throw new Error("Chapters are not available"); this.setChapters(e), this.container.insertBefore(this.chapterContainer, this.container.childNodes[0]), this.container.classList.add("shaka-no-background"), this.isChaptersEnabled = !0; } registerMarkers(e) { return b(this, null, function* () { const i = []; for (const s in e) { const n = e[s], [a, l] = n.title.split("#thumb#"); i.push({ time: n.startTime, title: a, thumb: l, id: s }); } if (!i || !i.length) throw new Error("Markers are not available"); this.setMarkers(i), this.container.insertBefore(this.markerContainer, this.container.childNodes[0]), this.isMarkersEnabled = !0; }); } } L = new WeakMap(), x = new WeakSet(), U = function(e, i) { var d, T; const s = this.player.seekRange(), n = Math.max(Math.ceil(s.start), Math.min(Math.floor(s.end), i)); this.chapterContainerText.style.visibility = "hidden"; for (const S of this.chapters) (d = S.element) == null || d.classList.remove("shaka-chapter-select"); const a = this.chapters.find((S) => S.startTime <= n && n <= S.endTime); if (!a || !a.title) return; (T = this.chapterContainer.querySelector(`#chapter-${a.id}`)) == null || T.classList.add("shaka-chapter-select"), this.chapterContainerText.textContent = a.title; const l = this.chapterContainerText.clientWidth, c = Math.min(this.bar.offsetWidth - l, Math.max(0, e - l / 2)); this.chapterContainerText.style.left = c + "px", this.chapterContainerText.style.visibility = "visible", this.controlsContainer.dispatchEvent(new CustomEvent("chapterShown")); }, Q = function(e) { var a; if (!e.element) throw new Error("Marker element is not defined"); if (r(this, L) === e.time) return; w(this, L, e.time), this.isThumbnailEnabled && (this.thumbnailContainer.style.visibility = "hidden"); const i = e.element.offsetLeft, s = this.preloadedMarkerImages.get(e.time); s && (e.thumb = s.src); const n = this.loadImage(e.thumb, e.title); for (const l of this.markers) (a = l.element) == null || a.classList.remove("active"); e.element.classList.add("active"), this.thumbnailMarkerText.textContent = e.title, this.thumbnailMarkerTime.textContent = this.timeFormatter_(e.time), n.then(() => { const l = this.thumbnailMarkerContainer.offsetWidth, c = Math.min(this.bar.offsetWidth - l, Math.max(0, i - l / 2)); this.thumbnailMarkerContainer.style.left = c + "px", this.controlsContainer.dispatchEvent(new CustomEvent("markerShown")), this.thumbnailMarkerContainer.style.visibility = "visible"; }).catch(() => { }); }; const Me = /* @__PURE__ */ new Map([ ["adStart", y.ads.AdManager.AD_STARTED], ["adComplete", y.ads.AdManager.AD_COMPLETE], ["adAllCompleted", y.ads.AdManager.ALL_ADS_COMPLETED], ["adClick", y.ads.AdManager.AD_CLICKED], ["adSkip", y.ads.AdManager.AD_SKIPPED], ["adError", y.ads.AdManager.AD_ERROR] ]); var O, te, ie; class Te { constructor(t, e) { g(this, O); h(this, "name", "ServerSideAdsInsertionPlugin"); h(this, "loadIm3", null); h(this, "options"); h(this, "player"); h(this, "preventDoubleTrigger", []); this.player = t, this.options = e; } /** * Sets up the server-side ads insertion. * @returns A promise that resolves to the stream request URL. * @throws {Error} If the Google IMA SDK or Google IMA DAI SDK is not loaded, or if the ad manager is not available. */ setup() { return b(this, null, function* () { if (this.loadIm3 && (this.loadIm3 = yield ke("https://imasdk.googleapis.com/js/sdkloader/ima3_dai.js")), !window.google || !window.google.ima) throw new m(this.name, p.ERROR, "IMA SDK Not Loaded.", { description: "The Google IMA SDK is required to display ads." }); if (!window.google.ima.dai) throw new m(this.name, p.ERROR, "IMA DAI SDK Not Loaded.", { description: "The Google IMA DAI SDK is required to display ads." }); const t = this.player.basePlayer.getAdManager(); if (!t) throw new m(this.name, p.ERROR, "Ad Manager Not Available", { description: "The Ad Manager is currently unavailable." }); const e = yield f(this, O, te).call(this, t); return f(this, O, ie).call(this, t), e; }); } } O = new WeakSet(), te = function(t) { return b(this, null, function* () { const e = this.player.controls.getServerSideAdContainer(); if (!e) throw new m(this.name, p.ERROR, "Ad Container Not Available", { reason: "The Server-side ad container is not available." }); let i; switch (this.options.type) { case "ima-dai": switch (this.options.stream) { case "vod": i = new google.ima.dai.api.VODStreamRequest(), this.options.contentSourceId && (i.contentSourceId = this.options.contentSourceId), this.options.videoId && (i.videoId = this.options.videoId); break; case "live": i = new google.ima.dai.api.LiveStreamRequest(), this.options.assetKey && (i.assetKey = this.options.assetKey); break; default: throw new m(this.name, p.ERROR, "Invalid stream type"); } return t.initServerSide(e, this.player.videoElement), this.options.adTagParameters && (i.adTagParameters = this.options.adTagParameters), this.options.apiKey && (i.apiKey = this.options.apiKey), this.options.authToken && (i.authToken = this.options.authToken), this.options.format && (i.format = this.options.format), this.options.omidAccessModeRules && (i.omidAccessModeRules = this.options.omidAccessModeRules), this.options.streamActivityMonitorId && (i.streamActivityMonitorId = this.options.streamActivityMonitorId), yield t.requestServerSideStream(i); case "media-tailor": const s = this.player.basePlayer.getNetworkingEngine(); if (!s) throw new m(this.name, p.ERROR, "Networking engine is not available", { reason: "Networking engine is required for MediaTailor stream requests" }); t.initMediaTailor(e, s, this.player.videoElement); const n = {}; this.options.assetId && (n.assetId = this.options.assetId), this.options.podDuration && (n.podDuration = this.options.podDuration); const a = Object.keys(n).length === 0 ? null : { adsParams: n }; return yield t.requestMediaTailorStream(this.options.url, a); default: throw new m(this.name, p.ERROR, "Invalid stream type"); } }); }, /** * Adds event listeners for ads events. * @param {shaka.extern.IAdManager} adManager - The ad manager. * @returns {void} */ ie = function(t) { for (const [e, i] of Me) t.addEventListener(i, () => { switch (e) { case "adStart": if (this.preventDoubleTrigger.includes("adStart")) return; this.preventDoubleTrigger.push(e); break; case "adComplete": case "adAllCompleted": case "adSkip": case "adError": const s = this.preventDoubleTrigger.indexOf("adStart"); s > -1 && this.preventDoubleTrigger.splice(s, 1); break; } this.player.emit(e); }); }; var M, D; class Ie { constructor() { g(this, M, /* @__PURE__ */ new Map()); g(this, D, []); h(this, "off", this.removeListener.bind(this)); } on(t, e) { if (Array.isArray(t)) { const i = []; for (const s of t) { const n = this.on(s, e); i.push(n); } return i; } return r(this, M).has(t) || r(this, M).set(t, []), r(this, M).get(t).push(e), () => this.removeListener(t, e); } once(t, e) { if (Array.isArray(t)) return t.map((s) => this.once(s, e)); const i = this.on(t, (...s) => { i(), e.apply(this, s); }); return i; } /** * Adds a listener to all events * @param listener */ all(t) { r(this, D).push(t); } /** * Removes a listener from the event * @param event * @param listener * @returns */ removeListener(t, e) { if (Array.isArray(t)) { for (const n of t) this.removeListener(n, e); return; } if (!r(this, M).has(t)) return; const i = r(this, M).get(t), s = i.indexOf(e); s > -1 && i.splice(s, 1); } /** * Removes all existing listeners */ removeAllListeners() { r(this, M).clear(); } /** * Emits an event for all listeners * @param event * @param args * @returns */ emit(t, ...e) { const i = []; r(this, M).has(t) && i.push(...r(this, M).get(t)), r(this, D).length && i.push(...r(this, D)); for (const s of i) s.apply(this, [t, ...e]); } } M = new WeakMap(), D = new WeakMap(); class Se { constructor(t) { h(this, "expiresIn"); h(this, "prefix"); this.prefix = (t == null ? void 0 : t.prefix) || "player_persister", this.expiresIn = (t == null ? void 0 : t.expiresIn) || 365 * 30 * 24 * 60 * 60 * 1e3; } get(t) { const e = `${this.prefix}-${t}`, i = localStorage.getItem(e); if (!i) return; const s = JSON.parse(i); return Date.now() >= s.expiresAt ? this.delete(t) : s.data; } set(t, e, i) { const s = `${this.prefix}-${t}`, n = i || this.expiresIn, a = new Date((/* @__PURE__ */ new Date()).getTime() + n).getTime(), l = JSON.stringify({ expiresAt: a, data: e }); localStorage.setItem(s, l); } delete(t) { const e = `${this.prefix}-${t}`; localStorage.removeItem(e); } } const xe = { adStatisticsList: [], addBigPlayButton: !1, addSeekBar: !0, castAndroidReceiverCompatible: !1, castReceiverAppId: "", clearBufferOnQualityChange: !0, contextMenuElements: [], controlPanelElements: [ "play_pause", "mute", "volume", "time_and_duration", "spacer", "playback_rate", // 'language', // 'captions', "recenter_vr", "toggle_stereoscopic", "quality", "fullscreen" ], customContextMenu: !1, defaultVrProjectionMode: "equirectangular", displayInVrMode: !1, doubleClickForFullscreen: !0, enableFullscreenOnRotation: !0, enableKeyboardPlaybackControls: !0, enableTooltips: !1, fadeDelay: 0, fastForwardRates: [2, 4, 8, 1], forceLandscapeOnFullscreen: !0, // fullScreenElement: document.createElement('div'), keyboardLargeSeekDistance: 60, keyboardSeekDistance: 5, overflowMenuButtons: [], playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], preferDocumentPictureInPicture: !0, refreshTickInSeconds: 0.125, rewindRates: [-1, -2, -4, -8], seekBarColors: { base: "rgba(255, 255, 255, 0.3)", buffered: "rgba(255, 255, 255, 0.54)", played: "rgb(255, 255, 255)", adBreaks: "rgb(255, 204, 0)" }, seekOnTaps: !0, // setupMediaSession: true, showAudioChannelCountVariants: !0, showUnbufferedStart: !1, singleClickForPlayAndPause: !0, statisticsList: [], tapSeekDistance: 10, // textTrackLabelFormat: 'LANGUAGE', // trackLabelFormat: 'LANGUAGE', volumeBarColors: { base: "rgba(255, 255, 255, 0.54)", level: "rgb(255, 255, 255)" } }; y.polyfill.installAll(); if (!y.Player.isBrowserSupported()) throw console.error("Browser not supported!"), new Error("Browser not supported!"); y.ui.Controls.registerElement("customQualitySelector", { create: (o, t) => new we(o, t) }); y.ui.Controls.registerSeekBar({ create(o, t) { return new Ee(o, t); } }); const se = /* @__PURE__ */ new Map(); var R, C, k, N, _, B, I, F, u, ae, ne, re, oe, V, le, j, he, ce, de; class De { constructor(t, e) { g(this, u); // Element ID of the container h(this, "elementId"); h(this, "basePlayer"); h(this, "overlay"); h(this, "controls"); h(this, "localization"); h(this, "container"); h(this, "videoElement"); h(this, "options"); h(this, "uiConfig"); h(this, "language"); // Map of plugins g(this, R, /* @__PURE__ */ new Map()); // Event emitter g(this, C, new y.util.EventManager()); g(this, k, new Ie()); // Persister instance g(this, N); // Current volume of the video element g(this, _); // Flag to indicate that the source is server side ads g(this, B, !1); // Index of the current source in the sources array g(this, I, 0); // Index of the last error source in the sources array g(this, F, -1); // Event listeners (Bound to emitter) h(this, "on", r(this, k).on.bind(r(this, k))); h(this, "once", r(this, k).once.bind(r(this, k))); h(this, "all", r(this, k).all.bind(r(this, k))); h(this, "removeListener", r(this, k).removeListener.bind(r(this, k))); h(this, "off", r(this, k).off.bind(r(this, k))); h(this, "emit", r(this, k).emit.bind(r(this, k))); var a, l; if (!t) throw new m("Player", p.CRITICAL, "Element ID is required"); const i = document.getElementById(t); if (!i) throw new m("Player", p.CRITICAL, `Element with ID '${t}' not found.`); this.elementId = t, w(this, N, new Se(e.persister)), this.options = P({}, e), this.language = (l = (a = this.options.language) != null ? a : navigator.language) != null ? l : "en", this.container = i, this.uiConfig = ye(xe), f(this, u, oe).call(this), this.videoElement = f(this, u, ae).call(this); const s = this.uiConfig.displayInVrMode ? f(this, u, ne).call(this) : null; this.basePlayer = f(this, u, re).call(this), this.overlay = new y.ui.Overlay(this.basePlayer, i, this.videoElement, s), this.overlay.configure(this.uiConfig); const n = this.overlay.getControls(); if (!n) throw new m("Player", p.CRITICAL, "Controls not found"); this.controls = n, this.localization = n.getLocalization(), this.localization && this.localization.changeLocale([this.language]), w(this, _, this.videoElement.volume); } initialize() { return b(this, null, function* () { try { if (!this.options.src) throw new m("Player", p.CRITICAL, "No source provided"); f(this, u, de).call(this), yield this.basePlayer.attach(this.videoElement); const t = yield f(this, u, V).call(this, this.options.src); yield f(this, u, j).call(this, t), yield f(this, u, ce).call(this), this.overlay.configure(this.uiConfig), this.emit("ready"), this.emit("acknowledge"); } catch (t) { let e = t; t instanceof m || (e = new m("Player", p.CRITICAL, t.message, { reason: t })), this.emit("error", P({}, e.toObject())); } }); } onError(t, e = !1) { return b(this, null, function* () { if (r(this, F) + 1 !== r(this, I)) return; if (w(this, F, r(this, I)), !Array.isArray(this.options.src)) throw new m("Player", p.CRITICAL, t.message, { reason: t }); const i = r(this, I) + 1, s = yield f(this, u, V).call(this, this.options.src, i), n = new m("Player", p.WARNING, t.message, { reason: t, description: `Fallback to the next source... ${i}` }); this.emit("error", P({}, n.toObject())), Z(this, I)._++, yield f(this, u, j).call(this, s); }); } loadPlugin(t, e) { const i = new t(this, e); return r(this, R).set(t, i), i; } /** * Returns a loaded plugin instance * @param PluginClass * @returns */ getPlugin(t) { if (!r(this, R).has(t)) throw new m("Player", p.WARNING, `Plugin ${t.name} not found`); return r(this, R).get(t); } play() { return b(this, null, function* () { const t = this.videoElement.play(); t && (yield t.catch((e) => { console.error("Play:", e); })); }); } pause() { this.videoElement.pause(); } volume(t) { (t < 0 || t > 1) && (t = 1), this.videoElement.volume = t; } mute() { this.videoElement.muted = !0; } unmute() { this.videoElement.muted = !1; } get persister() { return r(this, N); } get currentSourceIndex() { return r(this, I); } } R = new WeakMap(), C = new WeakMap(), k = new WeakMap(), N = new WeakMap(), _ = new WeakMap(), B = new WeakMap(), I = new WeakMap(), F = new WeakMap(), u = new WeakSet(), ae = function() { var e, i, s; const t = document.createElement("video"); return t.id = "video-player", t.className = "shaka-video", t.crossOrigin = "anonymous", t.controls = !1, t.preload = "auto", t.autoplay = (e = this.options.autoplay) != null ? e : !1, t.muted = (i = this.options.muted) != null ? i : !1, t.playsInline = (s = this.options.playsInline) != null ? s : !1, t.setAttribute("data-shaka-player", ""), this.container.style.width = this.options.width ? `${this.options.width}px` : "100%", this.container.style.height = this.options.height ? `${this.options.height}px` : "100%", this.container.classList.add("shaka-theme", "youtube-theme"), this.container.appendChild(t), t; }, ne = function() { const t = document.createElement("canvas"); return t.className = "shaka-vr-canvas-container", this.container.appendChild(t), t; }, re = function() { const t = new y.Player(); return t.configure({ preferredTextLanguage: this.language, preferredAudioLanguage: this.language, streaming: { // useNativeHlsOnSafari: true, preferNativeHls: !0, useNativeHlsForFairPlay: !0 }, abr: { // TODO : review when is http enabled: !0, clearBufferSwitch: !0, restrictToScreenSize: !0, restrictions: { maxHeight: window.screen.height, maxWidth: window.screen.width } } }), t; }, oe = function() { for (const t in this.uiConfig) t in this.options && (this.uiConfig[t] = this.options[t]); }, V = function(t, e = 0) { return b(this, null, function* () { if (Array.isArray(t)) { if (e > t.length - 1) throw new m("Player", p.CRITICAL, "All sources are played and none of them are working"); const i = t[e]; if (!i) throw new m("Player", p.CRITICAL, "No source provided"); return i; } return t; }); }, le = function(t) { return b(this, null, function* () { var s; let e, i; if ((s = this.uiConfig.controlPanelElements) != null && s.length) { const n = this.uiConfig.controlPanelElements.indexOf("customQualitySelector"); n !== -1 && (this.uiConfig.controlPanelElements[n] = "quality"); } if (typeof t == "string") e = t, i = null; else switch (t.type) { case "multi-progressive": ({ url: e, type: i } = f(this, u, he).call(this, t)); break; case "media-tailor": case "ima-dai": const a = yield new Te(this, t).setup(); w(this, B, !0), e = a, i = null; break; case "application/dash+xml": case "dash": case "mpd": e = t.url, i = "application/dash+xml"; break; case "application/x-mpegurl": case "m3u8": case "hls": e = t.url, i = "application/x-mpegurl"; break; default: throw new m("Player", p.CRITICAL, "Invalid source type"); } return this.basePlayer.load(e, null, i); }); }, j = function(t) { return b(this, null, function* () { try { const e = yield f(this, u, le).call(this, t); return r(this, I) > 0 && this.emit("fallback", { source: t }), e; } catch (e) { yield this.onError(e); } }); }, /** * Sets the custom quality selector for the player * Replace the default quality selector with the custom quality selector * Return the first source in the array * @param src * @returns string */ he = function(t) { var s, n, a; const e = t.srcSet; if (!e.length) throw new m("Player", p.CRITICAL, "No source provided"); const i = (s = e.find((l) => l.active)) != null ? s : e[Math.floor(e.length / 2)]; if (i.active || (i.active = !0), ((n = this.uiConfig.controlPanelElements) == null ? void 0 : n.length) === 0) return i; if (se.set(this.controls, t), ((a = this.uiConfig.controlPanelElements) == null ? void 0 : a.indexOf("customQualitySelector")) === -1) { const l = this.uiConfig.controlPanelElements.indexOf("quality"); l === -1 ? this.uiConfig.controlPanelElements.push("customQualitySelector") : this.uiConfig.controlPanelElements[l] = "customQualitySelector"; } return i; }, ce = function() { return b(this, null, function* () { const t = []; for (const e of r(this, R).values()) t.push( e.setup().catch((i) => { i instanceof m || (i = new m(e.name, p.WARNING, i.message, P({}, i))), this.emit("error", P({}, i.toObject())); }) ); return Promise.all(t); }); }, de = function() { this.once("ready", () => { r(this, C).listen(this.controls, "resolutionselectionupdated", () => this.emit("qualityChange")); }), r(this, C).listenOnce(this.videoElement, "play", () => this.emit("firstPlay")), r(this, C).listen(this.videoElement, "play", () => this.emit("play")), r(this, C).listen(this.videoElement, "playing", () => this.emit("playing")), r(this, C).listen(this.videoElement, "pause", () => this.emit("pause")), r(this, C).listen(this.videoElement, "ended", () => this.emit("ended")), r(this, C).listen(this.videoElement, "seeking", () => this.emit("seeking")), r(this, C).listen(this.videoElement, "seeked", () => this.emit("seeked")), r(this, C).listen(this.container, "fullscreenchange", () => { this.controls.isFullScreenEnabled() ? this.emit("fullScreenIn") : this.emit("fullScreenOut"); }), r(this, C).listen(this.videoElement, "volumechange", () => { const t = this.videoElement.volume; if (r(this, _) !== t) return w(this, _, t), this.emit("volumeChange", { volume: t }); this.emit(this.videoElement.muted ? "mute" : "unmute"); }), r(this, C).listenOnce(this.videoElement, "play", () => { const t = /* @__PURE__ */ new Date(); r(this, C).listenOnce(this.videoElement, "playing", () => { const e = (/* @__PURE__ */ new Date()).getTime() - t.getTime(); this.emit("playAttempt", { attemptDuration: e }); }); }), r(this, C).listen(this.videoElement, "error", () => { this.videoElement.error && this.emit("error", { error: this.videoElement.error }); }), this.container.addEventListener("error", (t) => { this.emit("error", { error: t.error }); }), this.options.debug && this.all((t, ...e) => { console.log("======= Debug ======="), console.log("Event sent:", t, ...e); }); }; export { De as default };