@codenkay/video-nsgplayer-core 4.0.0 → 5.1.0
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/CHANGELOG.md +15 -0
- package/README.md +2 -0
- package/dist/index.cjs +57 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +55 -11
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add `streaming.mediaProxyUrlBuilder` so playlists, segments, and encryption keys are loaded through a same-origin proxy. The playback API rejects the browser origin and does not send CORS headers.
|
|
8
|
+
- Leave URLs that are already on the page origin unchanged, so a rewritten playlist is not proxied twice.
|
|
9
|
+
- Recognize `/live/` and `/hls-web-live/` playlists for direct `sourceUrl` playback, including when the live address is nested in a proxy `url` parameter.
|
|
10
|
+
- Send same-origin encryption-key requests with the site cookie and without a bearer token. The playback credential stays in the query string.
|
|
11
|
+
|
|
12
|
+
## 5.0.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- Update meta data
|
|
17
|
+
|
|
3
18
|
## 4.0.0
|
|
4
19
|
|
|
5
20
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Framework-agnostic HLS video player engine for NSG.
|
|
4
4
|
|
|
5
|
+
**Try it:** [nsgplayer-sample-react](https://github.com/codenannu/nsgplayer-sample-react) (npm package homepage). Also [Next.js BFF](https://github.com/codenannu/nsgplayer-sample-nextjs) · [Angular](https://github.com/codenannu/nsgplayer-sample-angular).
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -53,7 +53,9 @@ __export(index_exports, {
|
|
|
53
53
|
getLiveEdgeTime: () => getLiveEdgeTime,
|
|
54
54
|
isAtLiveEdge: () => isAtLiveEdge,
|
|
55
55
|
isEncryptionKeyUrl: () => isEncryptionKeyUrl,
|
|
56
|
+
isLivePlaylistUrl: () => isLivePlaylistUrl,
|
|
56
57
|
isPlainObject: () => isPlainObject,
|
|
58
|
+
isSameOriginHttpUrl: () => isSameOriginHttpUrl,
|
|
57
59
|
mergePlayerConfig: () => mergePlayerConfig,
|
|
58
60
|
redactObject: () => redactObject,
|
|
59
61
|
redactSensitive: () => redactSensitive,
|
|
@@ -309,6 +311,7 @@ var SKIP_DEEP_SCAN_KEYS = /* @__PURE__ */ new Set([
|
|
|
309
311
|
"getsource",
|
|
310
312
|
"refreshsource",
|
|
311
313
|
"keyproxyurlbuilder",
|
|
314
|
+
"mediaproxyurlbuilder",
|
|
312
315
|
"getkeyaccesstoken"
|
|
313
316
|
]);
|
|
314
317
|
var SECRET_SCAN_MAX_DEPTH = 32;
|
|
@@ -393,6 +396,7 @@ function mergePlayerConfig(partial) {
|
|
|
393
396
|
...DEFAULT_PLAYER_CONFIG.streaming.hls,
|
|
394
397
|
...partial?.streaming?.hls
|
|
395
398
|
},
|
|
399
|
+
mediaProxyUrlBuilder: partial?.streaming?.mediaProxyUrlBuilder,
|
|
396
400
|
keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder,
|
|
397
401
|
getKeyAccessToken: partial?.streaming?.getKeyAccessToken,
|
|
398
402
|
keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures
|
|
@@ -834,6 +838,26 @@ function seekToLiveEdge(media, options) {
|
|
|
834
838
|
return { moved: true, edge };
|
|
835
839
|
}
|
|
836
840
|
|
|
841
|
+
// src/streaming/mediaUrl.ts
|
|
842
|
+
var LIVE_PLAYLIST_PATH = /\/(?:hls-web-live|live)\//i;
|
|
843
|
+
function isLivePlaylistUrl(value) {
|
|
844
|
+
if (LIVE_PLAYLIST_PATH.test(value)) return true;
|
|
845
|
+
try {
|
|
846
|
+
const parsed = new URL(value, "http://localhost");
|
|
847
|
+
const inner = parsed.searchParams.get("url");
|
|
848
|
+
return Boolean(inner && LIVE_PLAYLIST_PATH.test(inner));
|
|
849
|
+
} catch {
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
function isSameOriginHttpUrl(value, baseOrigin) {
|
|
854
|
+
try {
|
|
855
|
+
return new URL(value, baseOrigin).origin === new URL(baseOrigin).origin;
|
|
856
|
+
} catch {
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
837
861
|
// src/streaming/authParamsLoader.ts
|
|
838
862
|
var ENC_KEY_PATH_RE = /enc\.key$/i;
|
|
839
863
|
var BUILTIN_LOADER_NAMES = /* @__PURE__ */ new Set(["XhrLoader", "FetchLoader"]);
|
|
@@ -903,8 +927,16 @@ function rewriteHlsRequestUrl(rawUrl, store, options = {}, baseOrigin = typeof l
|
|
|
903
927
|
mobile: snapshot.mobile
|
|
904
928
|
});
|
|
905
929
|
}
|
|
906
|
-
|
|
907
|
-
return
|
|
930
|
+
const withAuth = store.hasParams() ? store.applyToUrl(rawUrl, baseOrigin) : parsed.toString();
|
|
931
|
+
return applyMediaProxy(withAuth, options, baseOrigin);
|
|
932
|
+
}
|
|
933
|
+
function applyMediaProxy(url, options, baseOrigin) {
|
|
934
|
+
if (!options.mediaProxyUrlBuilder) return url;
|
|
935
|
+
if (isSameOriginHttpUrl(url, baseOrigin)) return url;
|
|
936
|
+
return options.mediaProxyUrlBuilder({
|
|
937
|
+
url,
|
|
938
|
+
videoId: options.videoId
|
|
939
|
+
});
|
|
908
940
|
}
|
|
909
941
|
function createLoaderStats() {
|
|
910
942
|
const now = performance.now();
|
|
@@ -935,12 +967,14 @@ function isProxyUpstreamBlocked(status, contentType, bodyHead, errorText) {
|
|
|
935
967
|
return false;
|
|
936
968
|
}
|
|
937
969
|
async function fetchEncryptionKeyBytes(url, accessToken, signal) {
|
|
938
|
-
const
|
|
970
|
+
const pageOrigin = typeof location !== "undefined" ? location.origin : "http://localhost";
|
|
971
|
+
const sameOrigin = isSameOriginHttpUrl(url, pageOrigin);
|
|
972
|
+
const headers = !sameOrigin && accessToken ? { Authorization: `Bearer ${accessToken}`, Accept: "*/*" } : void 0;
|
|
939
973
|
try {
|
|
940
974
|
const response = await fetch(url, {
|
|
941
975
|
method: "GET",
|
|
942
976
|
...headers ? { headers } : {},
|
|
943
|
-
credentials: "omit",
|
|
977
|
+
credentials: sameOrigin ? "same-origin" : "omit",
|
|
944
978
|
cache: "no-store",
|
|
945
979
|
signal
|
|
946
980
|
});
|
|
@@ -1231,7 +1265,7 @@ function createAuthParamsLoader(HlsModule, store, options = {}) {
|
|
|
1231
1265
|
const originalUrl = context.url;
|
|
1232
1266
|
const isKey = isEncryptionKeyUrl(originalUrl);
|
|
1233
1267
|
if (!isKey) {
|
|
1234
|
-
if (store.hasParams()) {
|
|
1268
|
+
if (store.hasParams() || options.mediaProxyUrlBuilder) {
|
|
1235
1269
|
context.url = rewriteHlsRequestUrl(originalUrl, store, {
|
|
1236
1270
|
...options,
|
|
1237
1271
|
keyProxyUrlBuilder: void 0
|
|
@@ -1356,7 +1390,7 @@ var HlsEngine = class {
|
|
|
1356
1390
|
if (videoEl.canPlayType("application/vnd.apple.mpegurl")) {
|
|
1357
1391
|
this.supportMode = "native";
|
|
1358
1392
|
this.options.callbacks.onSupportMode?.("native");
|
|
1359
|
-
videoEl.src = this.
|
|
1393
|
+
videoEl.src = this.playbackRequestUrl(playbackUrl);
|
|
1360
1394
|
this.bindMediaEvents();
|
|
1361
1395
|
this.bindNativeTextTracks();
|
|
1362
1396
|
this.options.callbacks.onStateChange?.("ready");
|
|
@@ -1381,6 +1415,7 @@ var HlsEngine = class {
|
|
|
1381
1415
|
} = this.options;
|
|
1382
1416
|
const loader = createAuthParamsLoader(Hls, authParams, {
|
|
1383
1417
|
videoId,
|
|
1418
|
+
mediaProxyUrlBuilder: this.options.mediaProxyUrlBuilder,
|
|
1384
1419
|
keyProxyUrlBuilder,
|
|
1385
1420
|
getKeyAccessToken,
|
|
1386
1421
|
keyProxyMaxFailures: this.options.keyProxyMaxFailures
|
|
@@ -1409,7 +1444,7 @@ var HlsEngine = class {
|
|
|
1409
1444
|
loader
|
|
1410
1445
|
});
|
|
1411
1446
|
this.hls.attachMedia(videoEl);
|
|
1412
|
-
this.hls.loadSource(
|
|
1447
|
+
this.hls.loadSource(this.playbackRequestUrl(playbackUrl));
|
|
1413
1448
|
this.hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {
|
|
1414
1449
|
if (this.destroyed) return;
|
|
1415
1450
|
this.qualities = (data.levels ?? []).map((level, index) => ({
|
|
@@ -1587,13 +1622,20 @@ var HlsEngine = class {
|
|
|
1587
1622
|
if (this.supportMode === "native" && this.options.videoEl) {
|
|
1588
1623
|
const time = this.options.videoEl.currentTime;
|
|
1589
1624
|
const wasPaused = this.options.videoEl.paused;
|
|
1590
|
-
this.options.videoEl.src = this.options.
|
|
1591
|
-
this.options.playbackUrl
|
|
1592
|
-
);
|
|
1625
|
+
this.options.videoEl.src = this.playbackRequestUrl(this.options.playbackUrl);
|
|
1593
1626
|
this.options.videoEl.currentTime = time;
|
|
1594
1627
|
if (!wasPaused) void this.options.videoEl.play();
|
|
1595
1628
|
}
|
|
1596
1629
|
}
|
|
1630
|
+
playbackRequestUrl(playbackUrl) {
|
|
1631
|
+
return rewriteHlsRequestUrl(playbackUrl, this.options.authParams, {
|
|
1632
|
+
videoId: this.options.videoId,
|
|
1633
|
+
mediaProxyUrlBuilder: this.options.mediaProxyUrlBuilder,
|
|
1634
|
+
keyProxyUrlBuilder: this.options.keyProxyUrlBuilder,
|
|
1635
|
+
getKeyAccessToken: this.options.getKeyAccessToken,
|
|
1636
|
+
keyProxyMaxFailures: this.options.keyProxyMaxFailures
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1597
1639
|
resumeAfterAuthRenew() {
|
|
1598
1640
|
this.networkRecoveryCount = 0;
|
|
1599
1641
|
this.hls?.startLoad();
|
|
@@ -1858,7 +1900,7 @@ function createVideoPlayer(options) {
|
|
|
1858
1900
|
const source = {
|
|
1859
1901
|
url: options.sourceUrl,
|
|
1860
1902
|
expiresAt: Date.now() + 24 * 60 * 60 * 1e3,
|
|
1861
|
-
live:
|
|
1903
|
+
live: isLivePlaylistUrl(options.sourceUrl)
|
|
1862
1904
|
};
|
|
1863
1905
|
sourceManager.applyDirectSource(source);
|
|
1864
1906
|
playbackUrl = source.url;
|
|
@@ -1888,6 +1930,7 @@ function createVideoPlayer(options) {
|
|
|
1888
1930
|
startPosition: config.player.startPosition,
|
|
1889
1931
|
volume: config.player.volume,
|
|
1890
1932
|
videoId: options.videoId,
|
|
1933
|
+
mediaProxyUrlBuilder: config.streaming.mediaProxyUrlBuilder,
|
|
1891
1934
|
keyProxyUrlBuilder: config.streaming.keyProxyUrlBuilder,
|
|
1892
1935
|
// Enterprise AES key auth (see authParamsLoader):
|
|
1893
1936
|
// 1) keyProxyUrlBuilder BFF — max 2 failures then circuit
|
|
@@ -2219,6 +2262,7 @@ function createVideoPlayer(options) {
|
|
|
2219
2262
|
streaming: {
|
|
2220
2263
|
engine: "hls",
|
|
2221
2264
|
hls: { ...config.streaming.hls, ...partial?.streaming?.hls },
|
|
2265
|
+
mediaProxyUrlBuilder: partial?.streaming?.mediaProxyUrlBuilder ?? config.streaming.mediaProxyUrlBuilder,
|
|
2222
2266
|
keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder ?? config.streaming.keyProxyUrlBuilder,
|
|
2223
2267
|
getKeyAccessToken: partial?.streaming?.getKeyAccessToken ?? config.streaming.getKeyAccessToken ?? (() => authManager.getAccessToken()),
|
|
2224
2268
|
keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures ?? config.streaming.keyProxyMaxFailures
|
|
@@ -2267,7 +2311,9 @@ function createVideoPlayer(options) {
|
|
|
2267
2311
|
getLiveEdgeTime,
|
|
2268
2312
|
isAtLiveEdge,
|
|
2269
2313
|
isEncryptionKeyUrl,
|
|
2314
|
+
isLivePlaylistUrl,
|
|
2270
2315
|
isPlainObject,
|
|
2316
|
+
isSameOriginHttpUrl,
|
|
2271
2317
|
mergePlayerConfig,
|
|
2272
2318
|
redactObject,
|
|
2273
2319
|
redactSensitive,
|