@mdcrtrs/player 0.1.3

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/index.cjs ADDED
@@ -0,0 +1,667 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ MediaCreatorsPlayer: () => MediaCreatorsPlayer,
34
+ usePlaybackSession: () => usePlaybackSession,
35
+ useWatchProgress: () => useWatchProgress
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/components/player.tsx
40
+ var import_react5 = require("react");
41
+ var import_mux_player_react = __toESM(require("@mux/mux-player-react"), 1);
42
+ var import_sutro = require("player.style/sutro");
43
+
44
+ // src/hooks/use-playback-session.ts
45
+ var import_react = require("react");
46
+
47
+ // src/types.ts
48
+ var PLATFORM = {
49
+ apiBase: "https://api.mediacreators.io",
50
+ playbackBase: "https://playback.mediacreators.io",
51
+ dataEnvKey: "fhri2484lqcn6gk89r013ckmb"
52
+ };
53
+
54
+ // src/lib/api.ts
55
+ var ApiError = class extends Error {
56
+ constructor(message, status) {
57
+ super(message);
58
+ this.status = status;
59
+ this.name = "ApiError";
60
+ }
61
+ };
62
+ async function fetchWithRetry(url, init, maxRetries = 3) {
63
+ let lastError = new Error("Unknown fetch error");
64
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
65
+ try {
66
+ const res = await fetch(url, init);
67
+ if (res.ok || res.status < 500) {
68
+ return res;
69
+ }
70
+ lastError = new ApiError(`HTTP ${res.status}`, res.status);
71
+ } catch (err) {
72
+ lastError = err instanceof Error ? err : new Error(String(err));
73
+ }
74
+ if (attempt < maxRetries - 1) {
75
+ await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 500));
76
+ }
77
+ }
78
+ throw lastError;
79
+ }
80
+ async function fetchSessionToken(creatorId, fanToken) {
81
+ const headers = {};
82
+ if (fanToken) {
83
+ headers["X-Fan-Token"] = fanToken;
84
+ }
85
+ const url = `${PLATFORM.apiBase}/v1/mos/${encodeURIComponent(creatorId)}/playback-session`;
86
+ const res = await fetchWithRetry(url, { method: "POST", headers });
87
+ if (!res.ok) {
88
+ throw new ApiError(`Failed to fetch session token: ${res.status}`, res.status);
89
+ }
90
+ const json = await res.json();
91
+ return { token: json.token, expiresAt: json.expires_at };
92
+ }
93
+ async function fetchPlaybackTokens(creatorId, playbackId, duration, sessionToken) {
94
+ const params = new URLSearchParams({ duration: String(duration) });
95
+ const url = `${PLATFORM.playbackBase}/v1/${encodeURIComponent(creatorId)}/tokens/${encodeURIComponent(playbackId)}?${params}`;
96
+ const res = await fetchWithRetry(url, {
97
+ headers: { Authorization: `Bearer ${sessionToken}` }
98
+ });
99
+ if (res.status === 401 || res.status === 403) {
100
+ throw new ApiError("Session token invalid or expired", res.status);
101
+ }
102
+ if (!res.ok) {
103
+ throw new ApiError(`Failed to fetch playback tokens: ${res.status}`, res.status);
104
+ }
105
+ const json = await res.json();
106
+ return {
107
+ video: json.tokens.video,
108
+ thumbnail: json.tokens.thumbnail,
109
+ storyboard: json.tokens.storyboard,
110
+ expiresIn: json.expires_in
111
+ };
112
+ }
113
+ async function saveWatchProgress(creatorId, assetId, position, duration, fanToken, completed) {
114
+ const url = `${PLATFORM.apiBase}/v1/mos/${encodeURIComponent(creatorId)}/watch-progress/${encodeURIComponent(assetId)}`;
115
+ try {
116
+ const res = await fetch(url, {
117
+ method: "PUT",
118
+ headers: {
119
+ "Content-Type": "application/json",
120
+ "X-Fan-Token": fanToken
121
+ },
122
+ body: JSON.stringify({ position, duration, completed: completed != null ? completed : false }),
123
+ keepalive: true
124
+ });
125
+ if (!res.ok) return { ok: false, status: res.status };
126
+ return { ok: true };
127
+ } catch (e) {
128
+ return { ok: false, status: 0 };
129
+ }
130
+ }
131
+ async function getWatchProgress(creatorId, assetId, fanToken) {
132
+ const url = `${PLATFORM.apiBase}/v1/mos/${encodeURIComponent(creatorId)}/watch-progress/${encodeURIComponent(assetId)}`;
133
+ try {
134
+ const res = await fetch(url, {
135
+ headers: { "X-Fan-Token": fanToken }
136
+ });
137
+ if (res.status === 401 || res.status === 404) return null;
138
+ if (!res.ok) return null;
139
+ const json = await res.json();
140
+ return json.data;
141
+ } catch (e) {
142
+ return null;
143
+ }
144
+ }
145
+
146
+ // src/hooks/use-playback-session.ts
147
+ function scheduleRefresh(expiresIn, refreshFn, timerRef) {
148
+ if (timerRef.current !== null) {
149
+ clearTimeout(timerRef.current);
150
+ }
151
+ const refreshAtMs = expiresIn * 0.8 * 1e3;
152
+ timerRef.current = setTimeout(async () => {
153
+ try {
154
+ await refreshFn();
155
+ } catch (err) {
156
+ console.error("[player/session] Scheduled refresh failed:", err);
157
+ }
158
+ }, refreshAtMs);
159
+ }
160
+ function cancelRefresh(timerRef) {
161
+ if (timerRef.current !== null) {
162
+ clearTimeout(timerRef.current);
163
+ timerRef.current = null;
164
+ }
165
+ }
166
+ function usePlaybackSession(creatorId, playbackId, duration, fanToken) {
167
+ const [tokens, setTokens] = (0, import_react.useState)(null);
168
+ const [isLoading, setIsLoading] = (0, import_react.useState)(true);
169
+ const [error, setError] = (0, import_react.useState)(null);
170
+ const sessionTokenRef = (0, import_react.useRef)(null);
171
+ const sessionExpiresAtRef = (0, import_react.useRef)(null);
172
+ const tokensRef = (0, import_react.useRef)(null);
173
+ const timerRef = (0, import_react.useRef)(null);
174
+ const visibilityHandlerRef = (0, import_react.useRef)(null);
175
+ (0, import_react.useEffect)(() => {
176
+ let cancelled = false;
177
+ tokensRef.current = null;
178
+ setTokens(null);
179
+ setIsLoading(true);
180
+ setError(null);
181
+ async function refresh() {
182
+ if (!sessionTokenRef.current || !sessionExpiresAtRef.current) return;
183
+ const now = Date.now();
184
+ const sessionExpiry = sessionExpiresAtRef.current.getTime();
185
+ let sessionToken = sessionTokenRef.current;
186
+ if (sessionExpiry - now < 6e4) {
187
+ const newSession = await fetchSessionToken(creatorId, fanToken);
188
+ sessionToken = newSession.token;
189
+ sessionTokenRef.current = newSession.token;
190
+ sessionExpiresAtRef.current = new Date(newSession.expiresAt);
191
+ }
192
+ const nextTokens = await fetchPlaybackTokens(creatorId, playbackId, duration, sessionToken);
193
+ if (cancelled) return;
194
+ tokensRef.current = nextTokens;
195
+ setTokens(nextTokens);
196
+ scheduleRefresh(nextTokens.expiresIn, refresh, timerRef);
197
+ }
198
+ async function initialize() {
199
+ try {
200
+ const session = await fetchSessionToken(creatorId, fanToken);
201
+ if (cancelled) return;
202
+ sessionTokenRef.current = session.token;
203
+ sessionExpiresAtRef.current = new Date(session.expiresAt);
204
+ const initialTokens = await fetchPlaybackTokens(creatorId, playbackId, duration, session.token);
205
+ if (cancelled) return;
206
+ tokensRef.current = initialTokens;
207
+ setTokens(initialTokens);
208
+ scheduleRefresh(initialTokens.expiresIn, refresh, timerRef);
209
+ visibilityHandlerRef.current = () => {
210
+ if (document.visibilityState !== "visible") return;
211
+ const current = tokensRef.current;
212
+ if (!sessionTokenRef.current || !sessionExpiresAtRef.current || !current) return;
213
+ const now = Date.now();
214
+ const sessionExpiry = sessionExpiresAtRef.current.getTime();
215
+ const approxTokenExpiry = now + current.expiresIn * 1e3;
216
+ const sessionExpired = sessionExpiry <= now;
217
+ const tokenNearExpiry = approxTokenExpiry - now < current.expiresIn * 0.2 * 1e3;
218
+ if (sessionExpired || tokenNearExpiry) {
219
+ cancelRefresh(timerRef);
220
+ refresh().catch((err) => {
221
+ if (!cancelled) setError(err);
222
+ });
223
+ }
224
+ };
225
+ document.addEventListener("visibilitychange", visibilityHandlerRef.current);
226
+ } catch (err) {
227
+ if (!cancelled) {
228
+ setError(err instanceof Error ? err : new Error(String(err)));
229
+ setTokens(null);
230
+ }
231
+ } finally {
232
+ if (!cancelled) setIsLoading(false);
233
+ }
234
+ }
235
+ void initialize();
236
+ return () => {
237
+ cancelled = true;
238
+ cancelRefresh(timerRef);
239
+ if (visibilityHandlerRef.current) {
240
+ document.removeEventListener("visibilitychange", visibilityHandlerRef.current);
241
+ visibilityHandlerRef.current = null;
242
+ }
243
+ sessionTokenRef.current = null;
244
+ sessionExpiresAtRef.current = null;
245
+ };
246
+ }, [creatorId, playbackId, duration, fanToken]);
247
+ return { tokens, isLoading, error };
248
+ }
249
+
250
+ // src/hooks/use-player-events.ts
251
+ var import_react2 = require("react");
252
+ var QUARTILES = [25, 50, 75, 100];
253
+ function usePlayerEvents(events, assetId) {
254
+ const firedQuartiles = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
255
+ const prevTime = (0, import_react2.useRef)(0);
256
+ const eventsRef = (0, import_react2.useRef)(events);
257
+ eventsRef.current = events;
258
+ (0, import_react2.useEffect)(() => {
259
+ firedQuartiles.current = /* @__PURE__ */ new Set();
260
+ prevTime.current = 0;
261
+ }, [assetId]);
262
+ return {
263
+ handleTimeUpdate: (currentTime, duration) => {
264
+ var _a, _b, _c, _d, _e, _f;
265
+ if (!duration || duration <= 0) return;
266
+ const pct = currentTime / duration * 100;
267
+ (_b = (_a = eventsRef.current).onTimeUpdate) == null ? void 0 : _b.call(_a, currentTime, duration, pct);
268
+ for (const q of QUARTILES) {
269
+ if (pct >= q && !firedQuartiles.current.has(q)) {
270
+ firedQuartiles.current.add(q);
271
+ (_d = (_c = eventsRef.current).onQuartile) == null ? void 0 : _d.call(_c, q);
272
+ }
273
+ }
274
+ const delta = Math.abs(currentTime - prevTime.current);
275
+ if (delta > 2 && prevTime.current > 0) {
276
+ (_f = (_e = eventsRef.current).onSeeked) == null ? void 0 : _f.call(_e, prevTime.current, currentTime);
277
+ }
278
+ prevTime.current = currentTime;
279
+ },
280
+ handlePause: (currentTime) => {
281
+ var _a, _b;
282
+ (_b = (_a = eventsRef.current).onPause) == null ? void 0 : _b.call(_a, currentTime);
283
+ },
284
+ handlePlay: (currentTime) => {
285
+ var _a, _b;
286
+ (_b = (_a = eventsRef.current).onPlay) == null ? void 0 : _b.call(_a, currentTime);
287
+ },
288
+ handleComplete: () => {
289
+ var _a, _b, _c, _d;
290
+ if (!firedQuartiles.current.has(100)) {
291
+ firedQuartiles.current.add(100);
292
+ (_b = (_a = eventsRef.current).onQuartile) == null ? void 0 : _b.call(_a, 100);
293
+ }
294
+ (_d = (_c = eventsRef.current).onComplete) == null ? void 0 : _d.call(_c);
295
+ },
296
+ handleReady: () => {
297
+ var _a, _b;
298
+ (_b = (_a = eventsRef.current).onReady) == null ? void 0 : _b.call(_a);
299
+ },
300
+ handleError: (message) => {
301
+ var _a, _b;
302
+ (_b = (_a = eventsRef.current).onError) == null ? void 0 : _b.call(_a, { code: "PLAYER_ERROR", message });
303
+ }
304
+ };
305
+ }
306
+
307
+ // src/hooks/use-volume.ts
308
+ var import_react3 = require("react");
309
+ var STORAGE_KEY = "mc-player-volume";
310
+ function getStoredVolume() {
311
+ try {
312
+ const raw = window.localStorage.getItem(STORAGE_KEY);
313
+ if (raw === null) return null;
314
+ const parsed = parseFloat(raw);
315
+ if (Number.isNaN(parsed) || parsed < 0 || parsed > 1) return null;
316
+ return parsed;
317
+ } catch (e) {
318
+ return null;
319
+ }
320
+ }
321
+ function saveVolume(volume) {
322
+ try {
323
+ window.localStorage.setItem(STORAGE_KEY, String(volume));
324
+ } catch (e) {
325
+ }
326
+ }
327
+ function useVolume() {
328
+ const initialVolume = (0, import_react3.useRef)(getStoredVolume());
329
+ const debounceTimer = (0, import_react3.useRef)(null);
330
+ const handleVolumeChange = (0, import_react3.useCallback)((volume) => {
331
+ if (debounceTimer.current !== null) clearTimeout(debounceTimer.current);
332
+ debounceTimer.current = setTimeout(() => saveVolume(volume), 500);
333
+ }, []);
334
+ return { initialVolume: initialVolume.current, handleVolumeChange };
335
+ }
336
+
337
+ // src/hooks/use-watch-progress.ts
338
+ var import_react4 = require("react");
339
+ var SAVE_DEBOUNCE_MS = 1e4;
340
+ function useWatchProgress(creatorId, assetId, fanToken, autoResume, onResume) {
341
+ const [resumePosition, setResumePosition] = (0, import_react4.useState)(null);
342
+ const [authExpired, setAuthExpired] = (0, import_react4.useState)(false);
343
+ const debounceTimer = (0, import_react4.useRef)(null);
344
+ const onResumeRef = (0, import_react4.useRef)(onResume);
345
+ onResumeRef.current = onResume;
346
+ const stoppedRef = (0, import_react4.useRef)(false);
347
+ (0, import_react4.useEffect)(() => {
348
+ stoppedRef.current = false;
349
+ setAuthExpired(false);
350
+ setResumePosition(null);
351
+ if (!fanToken || !autoResume) return;
352
+ let cancelled = false;
353
+ void getWatchProgress(creatorId, assetId, fanToken).then((record) => {
354
+ var _a;
355
+ if (cancelled || !record || record.completed) return;
356
+ if (record.position > 5) {
357
+ setResumePosition(record.position);
358
+ (_a = onResumeRef.current) == null ? void 0 : _a.call(onResumeRef, record.position);
359
+ }
360
+ });
361
+ return () => {
362
+ cancelled = true;
363
+ if (debounceTimer.current !== null) {
364
+ clearTimeout(debounceTimer.current);
365
+ debounceTimer.current = null;
366
+ }
367
+ };
368
+ }, [creatorId, assetId, fanToken, autoResume]);
369
+ const saveProgress = (0, import_react4.useCallback)(
370
+ (position, duration) => {
371
+ if (!fanToken || stoppedRef.current) return;
372
+ if (debounceTimer.current !== null) clearTimeout(debounceTimer.current);
373
+ debounceTimer.current = setTimeout(() => {
374
+ const completed = duration > 0 && position / duration >= 0.95;
375
+ void saveWatchProgress(creatorId, assetId, position, duration, fanToken, completed).then((result) => {
376
+ if (!result.ok && result.status === 401) {
377
+ stoppedRef.current = true;
378
+ setAuthExpired(true);
379
+ }
380
+ });
381
+ }, SAVE_DEBOUNCE_MS);
382
+ },
383
+ [creatorId, assetId, fanToken]
384
+ );
385
+ return { resumePosition, saveProgress, authExpired };
386
+ }
387
+
388
+ // src/lib/session.ts
389
+ var SESSION_STORAGE_KEY = "mc-player-session";
390
+ function getSessionId() {
391
+ try {
392
+ const existing = window.sessionStorage.getItem(SESSION_STORAGE_KEY);
393
+ if (existing) return existing;
394
+ const generated = crypto.randomUUID();
395
+ window.sessionStorage.setItem(SESSION_STORAGE_KEY, generated);
396
+ return generated;
397
+ } catch (e) {
398
+ return null;
399
+ }
400
+ }
401
+
402
+ // src/lib/theme.ts
403
+ function normalizeHex(hex) {
404
+ const sanitized = hex.trim().replace(/^#/, "");
405
+ if (!/^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/.test(sanitized)) {
406
+ return "#1a1a1a";
407
+ }
408
+ if (sanitized.length === 3) {
409
+ return `#${sanitized.split("").map((c) => c + c).join("")}`;
410
+ }
411
+ return `#${sanitized}`;
412
+ }
413
+ function hexToRgb(hex) {
414
+ const full = normalizeHex(hex).slice(1);
415
+ return {
416
+ r: parseInt(full.slice(0, 2), 16),
417
+ g: parseInt(full.slice(2, 4), 16),
418
+ b: parseInt(full.slice(4, 6), 16)
419
+ };
420
+ }
421
+ function relativeLuminance(hex) {
422
+ const { r, g, b } = hexToRgb(hex);
423
+ const linear = [r, g, b].map((channel) => {
424
+ const s = channel / 255;
425
+ return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
426
+ });
427
+ return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
428
+ }
429
+ function hexToHSL(hex) {
430
+ const { r, g, b } = hexToRgb(hex);
431
+ const rNorm = r / 255;
432
+ const gNorm = g / 255;
433
+ const bNorm = b / 255;
434
+ const max = Math.max(rNorm, gNorm, bNorm);
435
+ const min = Math.min(rNorm, gNorm, bNorm);
436
+ const delta = max - min;
437
+ let h = 0;
438
+ if (delta !== 0) {
439
+ if (max === rNorm) {
440
+ h = (gNorm - bNorm) / delta % 6;
441
+ } else if (max === gNorm) {
442
+ h = (bNorm - rNorm) / delta + 2;
443
+ } else {
444
+ h = (rNorm - gNorm) / delta + 4;
445
+ }
446
+ h = Math.round(h * 60);
447
+ if (h < 0) h += 360;
448
+ }
449
+ const l = (max + min) / 2;
450
+ const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
451
+ return {
452
+ h,
453
+ s: Math.round(s * 100),
454
+ l: Math.round(l * 100)
455
+ };
456
+ }
457
+ function hslToHex({ h, s, l }) {
458
+ const sNorm = s / 100;
459
+ const lNorm = l / 100;
460
+ const c = (1 - Math.abs(2 * lNorm - 1)) * sNorm;
461
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
462
+ const m = lNorm - c / 2;
463
+ let r = 0;
464
+ let g = 0;
465
+ let b = 0;
466
+ if (h < 60) {
467
+ ;
468
+ [r, g, b] = [c, x, 0];
469
+ } else if (h < 120) {
470
+ ;
471
+ [r, g, b] = [x, c, 0];
472
+ } else if (h < 180) {
473
+ ;
474
+ [r, g, b] = [0, c, x];
475
+ } else if (h < 240) {
476
+ ;
477
+ [r, g, b] = [0, x, c];
478
+ } else if (h < 300) {
479
+ ;
480
+ [r, g, b] = [x, 0, c];
481
+ } else {
482
+ ;
483
+ [r, g, b] = [c, 0, x];
484
+ }
485
+ const toHex = (v) => Math.round((v + m) * 255).toString(16).padStart(2, "0");
486
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
487
+ }
488
+ function clamp(value, min, max) {
489
+ return Math.min(max, Math.max(min, value));
490
+ }
491
+ function deriveColors(primaryHex) {
492
+ const brand = normalizeHex(primaryHex);
493
+ const hsl = hexToHSL(brand);
494
+ const lum = relativeLuminance(brand);
495
+ const accentL = clamp(hsl.l < 42 ? 50 : hsl.l > 78 ? 70 : hsl.l, 38, 72);
496
+ const accent = hslToHex({
497
+ h: hsl.h,
498
+ s: clamp(hsl.s, 0, 100),
499
+ l: accentL
500
+ });
501
+ let primary;
502
+ if (lum >= 0.72) {
503
+ primary = "#1a1a1a";
504
+ } else if (lum >= 0.58 && hsl.s < 22) {
505
+ primary = brand;
506
+ } else {
507
+ primary = "#ffffff";
508
+ }
509
+ const secondary = lum >= 0.72 ? "rgba(0, 0, 0, 0.1)" : "rgba(255, 255, 255, 0.14)";
510
+ return { primary, secondary, accent };
511
+ }
512
+ function deriveTheme(primaryColor) {
513
+ return deriveColors(primaryColor);
514
+ }
515
+
516
+ // src/components/player.tsx
517
+ var import_jsx_runtime = require("react/jsx-runtime");
518
+ function decodeJwtSub(token) {
519
+ try {
520
+ const payloadPart = token.split(".")[1];
521
+ if (!payloadPart) return null;
522
+ const padded = payloadPart + "==".slice((payloadPart.length % 4 || 4) - 2);
523
+ const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
524
+ const json = JSON.parse(atob(base64));
525
+ return typeof json.sub === "string" ? json.sub : null;
526
+ } catch (e) {
527
+ return null;
528
+ }
529
+ }
530
+ var MediaCreatorsPlayer = (0, import_react5.memo)(function MediaCreatorsPlayer2({
531
+ creatorId,
532
+ asset,
533
+ auth,
534
+ theme,
535
+ playerTheme,
536
+ poster,
537
+ metadata,
538
+ autoResume,
539
+ className,
540
+ onTimeUpdate,
541
+ onQuartile,
542
+ onPause,
543
+ onPlay,
544
+ onSeeked,
545
+ onComplete,
546
+ onError,
547
+ onReady,
548
+ onResume
549
+ }) {
550
+ var _a, _b, _c, _d, _e, _f, _g;
551
+ const durationHint = (_a = asset.duration) != null ? _a : 3600;
552
+ const { tokens, isLoading, error } = usePlaybackSession(creatorId, asset.playbackId, durationHint, auth == null ? void 0 : auth.fanToken);
553
+ const colors = (0, import_react5.useMemo)(() => {
554
+ var _a2;
555
+ return deriveTheme((_a2 = theme == null ? void 0 : theme.primaryColor) != null ? _a2 : "#1a1a1a");
556
+ }, [theme == null ? void 0 : theme.primaryColor]);
557
+ const { initialVolume, handleVolumeChange } = useVolume();
558
+ const playerRef = (0, import_react5.useRef)(null);
559
+ const seekDoneRef = (0, import_react5.useRef)(false);
560
+ const events = usePlayerEvents(
561
+ { onTimeUpdate, onQuartile, onPause, onPlay, onSeeked, onComplete, onError, onReady, onResume },
562
+ asset.assetId
563
+ );
564
+ const { resumePosition, saveProgress } = useWatchProgress(
565
+ creatorId,
566
+ asset.assetId,
567
+ auth == null ? void 0 : auth.fanToken,
568
+ autoResume,
569
+ onResume
570
+ );
571
+ (0, import_react5.useEffect)(() => {
572
+ if (error) {
573
+ onError == null ? void 0 : onError({ code: "SESSION_ERROR", message: error.message });
574
+ }
575
+ }, [error, onError]);
576
+ (0, import_react5.useEffect)(() => {
577
+ seekDoneRef.current = false;
578
+ }, [asset.assetId]);
579
+ (0, import_react5.useEffect)(() => {
580
+ if (seekDoneRef.current) return;
581
+ if (resumePosition === null || !playerRef.current) return;
582
+ const el = playerRef.current;
583
+ if (typeof el.currentTime === "number") {
584
+ el.currentTime = resumePosition;
585
+ seekDoneRef.current = true;
586
+ }
587
+ }, [resumePosition, tokens]);
588
+ const handlePlayerRef = (0, import_react5.useCallback)(
589
+ (el) => {
590
+ playerRef.current = el;
591
+ if (el && initialVolume !== null) {
592
+ ;
593
+ el.volume = initialVolume;
594
+ }
595
+ },
596
+ [initialVolume]
597
+ );
598
+ const viewerUserId = (_d = (_c = (_b = metadata == null ? void 0 : metadata.viewerUserId) != null ? _b : (auth == null ? void 0 : auth.fanToken) ? decodeJwtSub(auth.fanToken) : null) != null ? _c : getSessionId()) != null ? _d : void 0;
599
+ if (isLoading || !tokens) {
600
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: { width: "100%", aspectRatio: "16 / 9", background: "#111" } });
601
+ }
602
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
603
+ import_mux_player_react.default,
604
+ {
605
+ ref: handlePlayerRef,
606
+ className,
607
+ theme: playerTheme,
608
+ playbackId: asset.playbackId,
609
+ poster,
610
+ envKey: PLATFORM.dataEnvKey,
611
+ tokens: {
612
+ playback: tokens.video,
613
+ thumbnail: tokens.thumbnail,
614
+ storyboard: tokens.storyboard
615
+ },
616
+ primaryColor: colors.primary,
617
+ secondaryColor: colors.secondary,
618
+ accentColor: colors.accent,
619
+ metadata: {
620
+ video_id: asset.assetId,
621
+ video_title: asset.title,
622
+ video_stream_type: "on-demand",
623
+ viewer_user_id: viewerUserId,
624
+ sub_property_id: creatorId,
625
+ player_name: (_e = metadata == null ? void 0 : metadata.playerName) != null ? _e : "mediacreators-sdk",
626
+ custom_1: (_f = metadata == null ? void 0 : metadata.custom1) != null ? _f : creatorId,
627
+ custom_2: (_g = metadata == null ? void 0 : metadata.custom2) != null ? _g : "sdk"
628
+ },
629
+ playsInline: true,
630
+ style: { width: "100%", aspectRatio: "16 / 9" },
631
+ onLoadedData: () => events.handleReady(),
632
+ onTimeUpdate: (e) => {
633
+ const el = e.target;
634
+ if (!el) return;
635
+ events.handleTimeUpdate(el.currentTime, el.duration);
636
+ if (auth == null ? void 0 : auth.fanToken) {
637
+ saveProgress(el.currentTime, el.duration);
638
+ }
639
+ },
640
+ onPause: (e) => {
641
+ var _a2;
642
+ const el = e.target;
643
+ events.handlePause((_a2 = el == null ? void 0 : el.currentTime) != null ? _a2 : 0);
644
+ },
645
+ onPlay: (e) => {
646
+ var _a2;
647
+ const el = e.target;
648
+ events.handlePlay((_a2 = el == null ? void 0 : el.currentTime) != null ? _a2 : 0);
649
+ },
650
+ onEnded: () => events.handleComplete(),
651
+ onVolumeChange: (e) => {
652
+ const el = e.target;
653
+ if (el && typeof el.volume === "number") {
654
+ handleVolumeChange(el.volume);
655
+ }
656
+ },
657
+ onError: () => events.handleError("Playback error")
658
+ }
659
+ );
660
+ });
661
+ // Annotate the CommonJS export names for ESM import in node:
662
+ 0 && (module.exports = {
663
+ MediaCreatorsPlayer,
664
+ usePlaybackSession,
665
+ useWatchProgress
666
+ });
667
+ //# sourceMappingURL=index.cjs.map