@oddin-gg/havik-player 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +21 -19
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +58 -30
- package/dist/index.js.map +1 -1
- package/docs/API.md +30 -30
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -67,7 +67,16 @@ export declare interface CreatePlayerOptions {
|
|
|
67
67
|
baseUrl: string;
|
|
68
68
|
matchUrn: string;
|
|
69
69
|
credential: CredentialSource;
|
|
70
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Start playback once ready. Default: true. With false the player resolves
|
|
72
|
+
* playback, then holds in a pre-play 'paused' state (poster + play card,
|
|
73
|
+
* no spinner) and defers media loading — segments and DRM license traffic —
|
|
74
|
+
* until the first play(). The hls.js engine still parses the manifest
|
|
75
|
+
* pre-play ('ready', track lists); the native engine defers all fetching
|
|
76
|
+
* and emits 'ready' at attach. A policy-blocked programmatic play()
|
|
77
|
+
* ('autoplayblocked') leaves the loader warming the buffer — media and DRM
|
|
78
|
+
* traffic flows from that kick, not from a viewer gesture.
|
|
79
|
+
*/
|
|
71
80
|
autoplay?: boolean;
|
|
72
81
|
/** Mute the element (required for reliable autoplay with sound policies). Default: false. */
|
|
73
82
|
muted?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,16 @@ export declare interface CreatePlayerOptions {
|
|
|
67
67
|
baseUrl: string;
|
|
68
68
|
matchUrn: string;
|
|
69
69
|
credential: CredentialSource;
|
|
70
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Start playback once ready. Default: true. With false the player resolves
|
|
72
|
+
* playback, then holds in a pre-play 'paused' state (poster + play card,
|
|
73
|
+
* no spinner) and defers media loading — segments and DRM license traffic —
|
|
74
|
+
* until the first play(). The hls.js engine still parses the manifest
|
|
75
|
+
* pre-play ('ready', track lists); the native engine defers all fetching
|
|
76
|
+
* and emits 'ready' at attach. A policy-blocked programmatic play()
|
|
77
|
+
* ('autoplayblocked') leaves the loader warming the buffer — media and DRM
|
|
78
|
+
* traffic flows from that kick, not from a viewer gesture.
|
|
79
|
+
*/
|
|
71
80
|
autoplay?: boolean;
|
|
72
81
|
/** Mute the element (required for reliable autoplay with sound policies). Default: false. */
|
|
73
82
|
muted?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -663,12 +663,15 @@ var z = class {
|
|
|
663
663
|
keySession = null;
|
|
664
664
|
fairplayArmed = !1;
|
|
665
665
|
fairplayKeyIV;
|
|
666
|
+
loadStarted;
|
|
667
|
+
preloadTouched = !1;
|
|
668
|
+
savedPreload = null;
|
|
666
669
|
constructor(e) {
|
|
667
|
-
this.deps = e;
|
|
670
|
+
this.deps = e, this.loadStarted = e.deferLoad !== !0;
|
|
668
671
|
}
|
|
669
672
|
async load() {
|
|
670
673
|
let { video: e, descriptor: t, emit: r } = this.deps;
|
|
671
|
-
if (t.drmEnabled) {
|
|
674
|
+
if (this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
|
|
672
675
|
if (!t.drm?.fairplay) {
|
|
673
676
|
r({
|
|
674
677
|
type: "error",
|
|
@@ -679,11 +682,21 @@ var z = class {
|
|
|
679
682
|
}
|
|
680
683
|
this.armFairPlay();
|
|
681
684
|
}
|
|
682
|
-
|
|
685
|
+
let i = !this.loadStarted;
|
|
686
|
+
this.onLoaded = i ? void 0 : () => r({ type: "ready" }), this.onError = () => r({
|
|
683
687
|
type: "error",
|
|
684
688
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
685
689
|
fatal: !0
|
|
686
|
-
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ee(t.manifestUrl, t.analytics?.sid), e.load();
|
|
690
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ee(t.manifestUrl, t.analytics?.sid), e.load();
|
|
691
|
+
}
|
|
692
|
+
startLoad() {
|
|
693
|
+
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
694
|
+
}
|
|
695
|
+
restorePreload() {
|
|
696
|
+
if (!this.preloadTouched) return;
|
|
697
|
+
this.preloadTouched = !1;
|
|
698
|
+
let { video: e } = this.deps;
|
|
699
|
+
this.savedPreload === null ? e.removeAttribute("preload") : e.setAttribute("preload", this.savedPreload);
|
|
687
700
|
}
|
|
688
701
|
armFairPlay() {
|
|
689
702
|
let { video: e, descriptor: t, credential: r, deviceId: a, userId: o, emit: s } = this.deps, c = t.drm?.fairplay;
|
|
@@ -805,7 +818,7 @@ var z = class {
|
|
|
805
818
|
try {
|
|
806
819
|
e.pause();
|
|
807
820
|
} catch {}
|
|
808
|
-
e.removeAttribute("src");
|
|
821
|
+
e.removeAttribute("src"), this.restorePreload();
|
|
809
822
|
try {
|
|
810
823
|
e.load();
|
|
811
824
|
} catch {}
|
|
@@ -872,8 +885,9 @@ var V = class {
|
|
|
872
885
|
sizeCapManaged = !0;
|
|
873
886
|
dprMedia = null;
|
|
874
887
|
onDprChange = null;
|
|
888
|
+
loadStarted;
|
|
875
889
|
constructor(e) {
|
|
876
|
-
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
|
|
890
|
+
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
877
891
|
}
|
|
878
892
|
async load() {
|
|
879
893
|
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = L(r) && R(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
@@ -894,6 +908,9 @@ var V = class {
|
|
|
894
908
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
895
909
|
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => this.clampOverSeek(), r.addEventListener("seeking", this.onSeeking), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
896
910
|
}
|
|
911
|
+
startLoad() {
|
|
912
|
+
this.loadStarted || (this.loadStarted = !0, this.hls?.startLoad(-1));
|
|
913
|
+
}
|
|
897
914
|
watchDprChanges() {
|
|
898
915
|
if (typeof matchMedia != "function") return;
|
|
899
916
|
this.unwatchDprChanges();
|
|
@@ -927,6 +944,7 @@ var V = class {
|
|
|
927
944
|
maxLiveSyncPlaybackRate: 1.5,
|
|
928
945
|
abrEwmaDefaultEstimate: 1e6,
|
|
929
946
|
capLevelToPlayerSize: !1,
|
|
947
|
+
...this.loadStarted ? {} : { autoStartLoad: !1 },
|
|
930
948
|
...u ? {
|
|
931
949
|
emeEnabled: !0,
|
|
932
950
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
@@ -951,7 +969,7 @@ var V = class {
|
|
|
951
969
|
} } : {},
|
|
952
970
|
...c
|
|
953
971
|
};
|
|
954
|
-
We(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0;
|
|
972
|
+
We(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
955
973
|
let f = new e(d);
|
|
956
974
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
957
975
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.applySizeCap(), l({ type: "ready" });
|
|
@@ -1422,7 +1440,7 @@ var Ye = class {
|
|
|
1422
1440
|
keepalive: !0
|
|
1423
1441
|
}).catch(() => {});
|
|
1424
1442
|
}
|
|
1425
|
-
}, Xe = "2.0.
|
|
1443
|
+
}, Xe = "2.0.4", W = {
|
|
1426
1444
|
accent: "#E1B600",
|
|
1427
1445
|
accentText: "#1B1C23",
|
|
1428
1446
|
background: "#0e0f13",
|
|
@@ -1874,6 +1892,8 @@ var dt = class {
|
|
|
1874
1892
|
_lastError = null;
|
|
1875
1893
|
analyticsSession = null;
|
|
1876
1894
|
detachSeekListener;
|
|
1895
|
+
playRequested = !1;
|
|
1896
|
+
pendingStartLoad = !1;
|
|
1877
1897
|
constructor(e) {
|
|
1878
1898
|
this.opts = e;
|
|
1879
1899
|
}
|
|
@@ -2002,18 +2022,20 @@ var dt = class {
|
|
|
2002
2022
|
let n = await s(this.opts.credential);
|
|
2003
2023
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2004
2024
|
this.setState("loading");
|
|
2005
|
-
let r = this.createEngine(e, n),
|
|
2025
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = we(this.opts.video, (e) => {
|
|
2006
2026
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2007
2027
|
});
|
|
2008
|
-
if (await
|
|
2009
|
-
|
|
2028
|
+
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
2029
|
+
a(), i.destroy();
|
|
2010
2030
|
return;
|
|
2011
2031
|
}
|
|
2012
2032
|
if (this._state === "error") {
|
|
2013
|
-
|
|
2033
|
+
a(), i.destroy();
|
|
2014
2034
|
return;
|
|
2015
2035
|
}
|
|
2016
|
-
this.engine =
|
|
2036
|
+
this.engine = i, this.detachMedia = a, this.opts.maxBitrate != null && i.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.startAnalytics(e, i, n.apiKey), r && (this.pendingStartLoad = !0, this.setState("paused"), i.name === "native" && setTimeout(() => {
|
|
2037
|
+
this.destroyed || t !== this.loadGen || this.engine !== i || (this.analyticsSession?.noteReady(), this.emit("ready"));
|
|
2038
|
+
}, 0));
|
|
2017
2039
|
}
|
|
2018
2040
|
startAnalytics(e, t, n) {
|
|
2019
2041
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachSeekListener?.(), this.opts.analytics === !1) return;
|
|
@@ -2041,10 +2063,10 @@ var dt = class {
|
|
|
2041
2063
|
let s = () => o.noteSeek();
|
|
2042
2064
|
a.addEventListener("seeking", s), this.detachSeekListener = () => a.removeEventListener("seeking", s), o.start();
|
|
2043
2065
|
}
|
|
2044
|
-
createEngine(e, t) {
|
|
2045
|
-
let
|
|
2046
|
-
this.opts.startLevel != null && (
|
|
2047
|
-
let
|
|
2066
|
+
createEngine(e, t, r = !1) {
|
|
2067
|
+
let i = { ...this.opts.hlsConfig };
|
|
2068
|
+
this.opts.startLevel != null && (i.startLevel = this.opts.startLevel), this.opts.liveLatencyTarget != null && (i.liveSyncDuration = this.opts.liveLatencyTarget);
|
|
2069
|
+
let a = {
|
|
2048
2070
|
video: this.opts.video,
|
|
2049
2071
|
descriptor: e,
|
|
2050
2072
|
credential: t,
|
|
@@ -2053,20 +2075,21 @@ var dt = class {
|
|
|
2053
2075
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
2054
2076
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
2055
2077
|
debug: this.opts.debug,
|
|
2056
|
-
|
|
2078
|
+
deferLoad: r,
|
|
2079
|
+
hlsConfig: i,
|
|
2057
2080
|
emit: (e) => this.onEngineEvent(e)
|
|
2058
|
-
},
|
|
2059
|
-
if (
|
|
2060
|
-
if (
|
|
2061
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && L(this.opts.video) && R()) return new z(
|
|
2062
|
-
if (De()) return new V(
|
|
2063
|
-
if (L(this.opts.video)) return new z(
|
|
2081
|
+
}, o = this.opts.engine ?? "auto";
|
|
2082
|
+
if (o === "native") return new z(a);
|
|
2083
|
+
if (o === "hls") return new V(a);
|
|
2084
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && L(this.opts.video) && R()) return new z(a);
|
|
2085
|
+
if (De()) return new V(a);
|
|
2086
|
+
if (L(this.opts.video)) return new z(a);
|
|
2064
2087
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2065
2088
|
}
|
|
2066
2089
|
onEngineEvent(e) {
|
|
2067
2090
|
if (!this.destroyed) switch (e.type) {
|
|
2068
2091
|
case "ready":
|
|
2069
|
-
this.analyticsSession?.noteReady(), this.emit("ready"), this.opts.autoplay !== !1 && this.play();
|
|
2092
|
+
this.analyticsSession?.noteReady(), this.emit("ready"), (this.opts.autoplay !== !1 || this.playRequested) && this.play();
|
|
2070
2093
|
break;
|
|
2071
2094
|
case "lowLatencyDetected":
|
|
2072
2095
|
this._descriptor && (this._descriptor.isLowLatency = e.value);
|
|
@@ -2116,7 +2139,7 @@ var dt = class {
|
|
|
2116
2139
|
t === "match_ended" && this._endedReason !== "match_ended" && (this._endedReason = t, this.emit("ended", t));
|
|
2117
2140
|
return;
|
|
2118
2141
|
}
|
|
2119
|
-
this.endedHandled = !0, this._endedReason = t ?? null, this.stopRefresh(), this.engine?.stop(), this.setState("ended");
|
|
2142
|
+
this.endedHandled = !0, this._endedReason = t ?? null, this.stopRefresh(), this.pendingStartLoad = !1, this.engine?.stop(), this.setState("ended");
|
|
2120
2143
|
}
|
|
2121
2144
|
}
|
|
2122
2145
|
rejoinEnabled() {
|
|
@@ -2135,7 +2158,7 @@ var dt = class {
|
|
|
2135
2158
|
this.teardownPlayback(), this.setState("waiting"), this.beginArming(e, void 0, !0);
|
|
2136
2159
|
}
|
|
2137
2160
|
teardownPlayback() {
|
|
2138
|
-
this.stopStats(), this.stopRefresh(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
|
|
2161
|
+
this.stopStats(), this.stopRefresh(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null, this.pendingStartLoad = !1;
|
|
2139
2162
|
}
|
|
2140
2163
|
mountControls() {
|
|
2141
2164
|
let e = this.opts.controls ?? "custom", t = this.opts.video;
|
|
@@ -2206,10 +2229,15 @@ var dt = class {
|
|
|
2206
2229
|
}
|
|
2207
2230
|
}
|
|
2208
2231
|
async play() {
|
|
2209
|
-
if (
|
|
2232
|
+
if (this.destroyed) return;
|
|
2233
|
+
let e = !this.playRequested;
|
|
2234
|
+
this.playRequested = !0;
|
|
2235
|
+
let t = this.pendingStartLoad && this._state !== "ended" && this._state !== "error";
|
|
2236
|
+
t && (this.pendingStartLoad = !1, this.setState("loading"), this.engine?.startLoad());
|
|
2237
|
+
try {
|
|
2210
2238
|
await this.opts.video.play();
|
|
2211
|
-
} catch (
|
|
2212
|
-
|
|
2239
|
+
} catch (n) {
|
|
2240
|
+
n instanceof DOMException && n.name === "NotAllowedError" && (e && (this.playRequested = !1), t && !this.destroyed && this._state === "loading" && this.setState("paused"), this.emit("autoplayblocked"));
|
|
2213
2241
|
}
|
|
2214
2242
|
}
|
|
2215
2243
|
pause() {
|