UNPKG

@tidal-music/player

Version:
260 lines (259 loc) 8.82 kB
import { B as f, c as g, m as p } from "./basePlayer-DD7cIuDm.js"; import { d as P, m as y, s as c, e as S, g as L, w as I } from "./index-C6ZwgBzI.js"; class b extends f { #t; #r; #i = !0; #o; #e; #s = document.createElement("video"); #a = !1; name = "browserPlayer"; constructor() { super(), this.playbackState = "IDLE"; const e = () => { this.mediaElement && !this.mediaElement.paused && (this.playbackState = "PLAYING"); }, i = (s) => { this.currentStreamingSessionId && s.target instanceof HTMLMediaElement && c.overwriteDuration( this.currentStreamingSessionId, s.target.duration ); }, t = () => { this.playbackState = "STALLED"; }, a = () => { (async () => { const s = this.#t; if (s) { if (this.preloadedStreamingSessionId && s.currentTime === s.duration && (await I(1e3), s.currentTime !== s.duration)) return; this.playbackState = "NOT_PLAYING"; } })().catch(console.error); }, n = (s) => { if (s instanceof Event) { const l = s.target; l.readyState > HTMLMediaElement.HAVE_NOTHING && (this.currentTime = l.currentTime); } }, o = (s) => { n(s), this.finishCurrentMediaProduct("completed"); }, r = (s) => console.error("HTMLMediaElement errored", s), d = () => { this.mediaElement && (this.currentTime = this.mediaElement.currentTime, this.seekEnd(this.currentTime)); }; this.#e = { durationChangeHandler: i, endedHandler: o, errorHandler: r, pauseHandler: a, playHandler: e, playingHandler: e, seekedHandler: d, stalledHandler: t, timeUpdateHandler: n, waitingHandler: t }, P().then().catch(console.error), this.#r = y, this.currentPlayer = this.#r; } #n(e, i) { this.debugLog( "mediaElementEvents", i ? "adding to" : "removing from", e ); const t = i ? "addEventListener" : "removeEventListener"; e[t]( "durationchange", this.#e.durationChangeHandler, { passive: !0 } ), e[t]("play", this.#e.playHandler, { passive: !0 }), e[t]( "playing", this.#e.playingHandler, { passive: !0 } ), e[t]( "timeupdate", this.#e.timeUpdateHandler, { passive: !0 } ), e[t]( "pause", this.#e.pauseHandler, { passive: !0 } ), e[t]( "ended", this.#e.endedHandler, { passive: !0 } ), e[t]( "error", this.#e.errorHandler, { passive: !0 } ), e[t]( "waiting", this.#e.waitingHandler, { passive: !0 } ), e[t]( "stalled", this.#e.stalledHandler, { passive: !0 } ), e[t]( "seeked", this.#e.seekedHandler, { passive: !0 } ); } getPosition() { return this.debugLog("getPosition"), this.mediaElement && (this.mediaElement.ended ? this.currentTime = 0 : this.currentTime = this.mediaElement.currentTime), this.currentTime; } async load(e, i) { this.debugLog("load", e), this.currentTime = e.assetPosition, this.startAssetPosition = e.assetPosition, await P(), await this.reset(), this.#i = !1, i === "explicit" && (this.playbackState = "NOT_PLAYING"); const { assetPosition: t, mediaProduct: a, playbackInfo: n, streamInfo: o } = e; this.currentStreamingSessionId = o.streamingSessionId; const { currentPlayer: r } = this; if (!r) return; const d = new Promise( (h) => r.addEventListener("canplay", () => h(), { once: !0 }) ); r.src = o.streamUrl, r.currentTime = t, r.load(); const s = new Promise( (h) => r.addEventListener( "durationchange", (m) => { m.target instanceof HTMLMediaElement && h(m.target.duration); }, { once: !0 } ) ); if (await d, this.currentStreamingSessionId !== o.streamingSessionId) return; const l = await s, u = g({ assetPosition: t, duration: l, playbackInfo: n, streamInfo: o }); return c.saveMediaProductTransition( o.streamingSessionId, { mediaProduct: a, playbackContext: u } ), this.debugLog("dispatching mediaProductTransition"), S.dispatchEvent( p(a, u) ), this.#a ? (this.#a = !1, this.play()) : Promise.resolve(); } async next(e) { this.debugLog("next", e), this.playbackState === "IDLE" && (this.playbackState = "NOT_PLAYING"); const { mediaProduct: i, playbackInfo: t, streamInfo: a } = e, n = this.#s; if (this.preloadedStreamingSessionId = a.streamingSessionId, !n) return; n.src = a.streamUrl, n.load(); const o = await new Promise( (d) => n.addEventListener( "durationchange", (s) => { s.target instanceof HTMLMediaElement && d(s.target.duration); }, { once: !0 } ) ), r = g({ assetPosition: 0, duration: o, playbackInfo: t, streamInfo: a }); c.saveMediaProductTransition( a.streamingSessionId, { mediaProduct: i, playbackContext: r } ), this.#i = !1; } pause() { this.debugLog("pause"), this.mediaElement && this.mediaElement.pause(); } async play() { if (this.debugLog("play"), await this.maybeHardReload(), this.playbackState === "IDLE") return this.debugLog("is IDLE, returning early"), this.#a = !0, Promise.resolve(); "setSinkId" in y && await this.updateOutputDevice(), this.currentStreamingSessionId && this.mediaProductStarted(this.currentStreamingSessionId), this.setStateToXIfNotYInZMs(1e3, "PLAYING", "STALLED"), this.currentPlayer && await this.currentPlayer.play().catch(console.error); } async playbackEngineEndedHandler(e) { if (this.isActivePlayer) { const { reason: i } = e.detail; i === "completed" && (this.hasNextItem() ? (await this.skipToPreloadedMediaProduct(), await this.play()) : (console.warn("No item preloaded, not progressing."), this.playbackState = "NOT_PLAYING")); } } async reset({ keepPreload: e } = { keepPreload: !1 }) { if (this.#i) return Promise.resolve(); this.debugLog("reset"), this.playbackState !== "IDLE" && this.finishCurrentMediaProduct("skip"), this.playbackState = "IDLE", this.detachPlaybackEngineEndedHandler(), this.currentStreamingSessionId = void 0, e || (this.preloadedStreamingSessionId = void 0); const { currentPlayer: i } = this; return i && i.readyState !== 0 && (i.load(), await new Promise( (t) => i.addEventListener("emptied", () => t(), { passive: !0 }) )), this.#i = !0, Promise.resolve(); } // eslint-disable-next-line @typescript-eslint/no-misused-promises seek(e) { this.debugLog("seek", e); const { currentPlayer: i } = this, t = e; if (i) return this.seekStart(this.currentTime), "fastSeek" in i ? i.fastSeek(t) : i.currentTime = t, new Promise((a) => { i.addEventListener("seeked", () => a(i.currentTime), { once: !0 }); }); } // eslint-disable-next-line @typescript-eslint/require-await async skipToPreloadedMediaProduct() { const e = c.getMediaProductTransition( this.preloadedStreamingSessionId ); if (!e) { this.playbackState = "NOT_PLAYING"; return; } if (this.debugLog( "skipToPreloadedMediaProduct", this.preloadedStreamingSessionId ), this.#s.src && this.currentPlayer) { this.currentPlayer.src = this.#s.src, this.currentStreamingSessionId = String(this.preloadedStreamingSessionId), this.preloadedStreamingSessionId = void 0; const { mediaProduct: i, playbackContext: t } = e; S.dispatchEvent( p(i, t) ), this.playbackState === "IDLE" && (this.playbackState = "NOT_PLAYING"); } } togglePlayback() { this.debugLog("togglePlayback"), this.mediaElement && (this.mediaElement.paused ? this.mediaElement.play().catch(console.error) : this.mediaElement.pause()); } // eslint-disable-next-line @typescript-eslint/require-await async unloadPreloadedMediaProduct() { this.debugLog( "unloadPreloadedMediaProduct", this.preloadedStreamingSessionId ), this.cleanUpStoredPreloadInfo(); const e = this.#s; e && (e.src = "", e.load()); } get currentPlayer() { return this.#t; } set currentPlayer(e) { this.debugLog("set currentPlayer", e), this.#t && (this.#n(this.#t, !1), this.#t.load()), e && (this.#t = e, this.#n(e, !0)); } get mediaElement() { return this.currentPlayer ?? null; } get ready() { return this.#o; } get volume() { return L("desiredVolumeLevel"); } set volume(e) { this.debugLog("Setting volume to", e), this.currentPlayer && (this.currentPlayer.volume = e); } } export { b as default };