@xhub-reels/sdk 0.1.14 → 0.1.17
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/README.md +11 -11
- package/dist/index.cjs +360 -280
- package/dist/index.d.cts +93 -24
- package/dist/index.d.ts +93 -24
- package/dist/index.js +360 -281
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -833,6 +833,21 @@ var ResourceGovernor = class {
|
|
|
833
833
|
isPreloading(index) {
|
|
834
834
|
return this.store.getState().preloadQueue.includes(index);
|
|
835
835
|
}
|
|
836
|
+
/**
|
|
837
|
+
* Returns the buffer tier (1–4) for a given index.
|
|
838
|
+
* - 1: Active (playing, 10s buffer)
|
|
839
|
+
* - 2: Hot (±bufferWindow, 2s buffer, instant swap)
|
|
840
|
+
* - 3: Warm (manifest + 1 segment, ~300ms show)
|
|
841
|
+
* - 4: Cold (preload queue — manifest in HTTP cache, no DOM)
|
|
842
|
+
*/
|
|
843
|
+
getTier(index) {
|
|
844
|
+
const { focusedIndex, activeAllocations, warmAllocations, preloadQueue } = this.store.getState();
|
|
845
|
+
if (index === focusedIndex) return 1;
|
|
846
|
+
if (activeAllocations.has(index)) return 2;
|
|
847
|
+
if (warmAllocations.has(index)) return 3;
|
|
848
|
+
if (preloadQueue.includes(index)) return 4;
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
836
851
|
getActiveAllocations() {
|
|
837
852
|
return [...this.store.getState().activeAllocations];
|
|
838
853
|
}
|
|
@@ -905,7 +920,9 @@ function usePointerGesture(config = {}) {
|
|
|
905
920
|
containerSize,
|
|
906
921
|
dragThresholdRatio = 0.5,
|
|
907
922
|
onSnap,
|
|
908
|
-
onBounceBack
|
|
923
|
+
onBounceBack,
|
|
924
|
+
onDragStart,
|
|
925
|
+
onDragEnd
|
|
909
926
|
} = config;
|
|
910
927
|
const isDraggingRef = react.useRef(false);
|
|
911
928
|
const dragOffsetRef = react.useRef(0);
|
|
@@ -922,6 +939,8 @@ function usePointerGesture(config = {}) {
|
|
|
922
939
|
const onDragThresholdRef = react.useRef(onDragThreshold);
|
|
923
940
|
const onSnapRef = react.useRef(onSnap);
|
|
924
941
|
const onBounceBackRef = react.useRef(onBounceBack);
|
|
942
|
+
const onDragStartRef = react.useRef(onDragStart);
|
|
943
|
+
const onDragEndRef = react.useRef(onDragEnd);
|
|
925
944
|
const disabledRef = react.useRef(disabled);
|
|
926
945
|
const containerSizeRef = react.useRef(containerSize);
|
|
927
946
|
const dragThresholdRatioRef = react.useRef(dragThresholdRatio);
|
|
@@ -930,6 +949,8 @@ function usePointerGesture(config = {}) {
|
|
|
930
949
|
onDragThresholdRef.current = onDragThreshold;
|
|
931
950
|
onSnapRef.current = onSnap;
|
|
932
951
|
onBounceBackRef.current = onBounceBack;
|
|
952
|
+
onDragStartRef.current = onDragStart;
|
|
953
|
+
onDragEndRef.current = onDragEnd;
|
|
933
954
|
disabledRef.current = disabled;
|
|
934
955
|
containerSizeRef.current = containerSize;
|
|
935
956
|
dragThresholdRatioRef.current = dragThresholdRatio;
|
|
@@ -996,6 +1017,7 @@ function usePointerGesture(config = {}) {
|
|
|
996
1017
|
window.removeEventListener("pointermove", handlePointerMove);
|
|
997
1018
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
998
1019
|
window.removeEventListener("pointercancel", handlePointerUp);
|
|
1020
|
+
onDragEndRef.current?.();
|
|
999
1021
|
const offset = dragOffsetRef.current;
|
|
1000
1022
|
const velocity = velocityRef.current;
|
|
1001
1023
|
const shouldSnap = Math.abs(velocity) > velocityThreshold || Math.abs(offset) > distanceThreshold;
|
|
@@ -1027,6 +1049,7 @@ function usePointerGesture(config = {}) {
|
|
|
1027
1049
|
lastTimeRef.current = performance.now();
|
|
1028
1050
|
velocityRef.current = 0;
|
|
1029
1051
|
dragOffsetRef.current = 0;
|
|
1052
|
+
onDragStartRef.current?.();
|
|
1030
1053
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1031
1054
|
window.addEventListener("pointermove", handlePointerMove, { passive: true });
|
|
1032
1055
|
window.addEventListener("pointerup", handlePointerUp);
|
|
@@ -1244,6 +1267,7 @@ function useResource() {
|
|
|
1244
1267
|
const networkType = useResourceSelector((s) => s.networkType);
|
|
1245
1268
|
const isActive = useResourceSelector((s) => s.isActive);
|
|
1246
1269
|
const prefetchIndex = useResourceSelector((s) => s.prefetchIndex);
|
|
1270
|
+
const preloadQueue = useResourceSelector((s) => s.preloadQueue);
|
|
1247
1271
|
const activeIndices = react.useMemo(() => [...activeAllocations], [activeAllocations]);
|
|
1248
1272
|
const warmIndices = react.useMemo(() => [...warmAllocations], [warmAllocations]);
|
|
1249
1273
|
const setFocusedIndex = react.useCallback(
|
|
@@ -1274,6 +1298,10 @@ function useResource() {
|
|
|
1274
1298
|
(i) => resourceGovernor.setPrefetchIndex(i),
|
|
1275
1299
|
[resourceGovernor]
|
|
1276
1300
|
);
|
|
1301
|
+
const getTier = react.useCallback(
|
|
1302
|
+
(index) => resourceGovernor.getTier(index),
|
|
1303
|
+
[resourceGovernor]
|
|
1304
|
+
);
|
|
1277
1305
|
return {
|
|
1278
1306
|
activeIndices,
|
|
1279
1307
|
warmIndices,
|
|
@@ -1282,13 +1310,15 @@ function useResource() {
|
|
|
1282
1310
|
networkType,
|
|
1283
1311
|
isActive,
|
|
1284
1312
|
prefetchIndex,
|
|
1313
|
+
preloadQueue,
|
|
1285
1314
|
setFocusedIndex,
|
|
1286
1315
|
setFocusedIndexImmediate,
|
|
1287
1316
|
setTotalItems,
|
|
1288
1317
|
shouldRenderVideo,
|
|
1289
1318
|
isAllocated,
|
|
1290
1319
|
isWarmAllocated,
|
|
1291
|
-
setPrefetchIndex
|
|
1320
|
+
setPrefetchIndex,
|
|
1321
|
+
getTier
|
|
1292
1322
|
};
|
|
1293
1323
|
}
|
|
1294
1324
|
var ACTIVE_HLS_DEFAULTS = {
|
|
@@ -1364,18 +1394,9 @@ function mapHlsError(data) {
|
|
|
1364
1394
|
}
|
|
1365
1395
|
function useHls(options) {
|
|
1366
1396
|
const { src, videoRef, isActive, isPrefetch, bufferTier = "active", hlsConfig, onError } = options;
|
|
1367
|
-
const
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
const hlsSupported = Hls__default.default.isSupported();
|
|
1371
|
-
const native = supportsNativeHls();
|
|
1372
|
-
setIsHlsJs(hlsSupported && !native);
|
|
1373
|
-
setIsNativeHls(native);
|
|
1374
|
-
}, []);
|
|
1375
|
-
const isHlsJsRef = react.useRef(false);
|
|
1376
|
-
const isNativeRef = react.useRef(false);
|
|
1377
|
-
isHlsJsRef.current = isHlsJs;
|
|
1378
|
-
isNativeRef.current = isNativeHls;
|
|
1397
|
+
const isHlsSupported = typeof window !== "undefined" && Hls__default.default.isSupported();
|
|
1398
|
+
const isNative = supportsNativeHls();
|
|
1399
|
+
const isHlsJs = isHlsSupported && !isNative;
|
|
1379
1400
|
const [isReady, setIsReady] = react.useState(false);
|
|
1380
1401
|
const hlsRef = react.useRef(null);
|
|
1381
1402
|
const onErrorRef = react.useRef(onError);
|
|
@@ -1400,18 +1421,7 @@ function useHls(options) {
|
|
|
1400
1421
|
currentSrcRef.current = void 0;
|
|
1401
1422
|
return;
|
|
1402
1423
|
}
|
|
1403
|
-
const isNative = isNativeRef.current;
|
|
1404
|
-
const isHlsSupported = isHlsJsRef.current;
|
|
1405
1424
|
if (!isActive && !isPrefetch) {
|
|
1406
|
-
if (isNative) {
|
|
1407
|
-
if (video.src) {
|
|
1408
|
-
video.removeAttribute("src");
|
|
1409
|
-
video.load();
|
|
1410
|
-
}
|
|
1411
|
-
setIsReady(false);
|
|
1412
|
-
currentSrcRef.current = void 0;
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
1425
|
destroy();
|
|
1416
1426
|
setIsReady(false);
|
|
1417
1427
|
canPlayFiredRef.current = false;
|
|
@@ -1419,45 +1429,40 @@ function useHls(options) {
|
|
|
1419
1429
|
return;
|
|
1420
1430
|
}
|
|
1421
1431
|
if (isNative) {
|
|
1422
|
-
if (
|
|
1423
|
-
|
|
1424
|
-
setIsReady(true);
|
|
1425
|
-
return void 0;
|
|
1426
|
-
}
|
|
1427
|
-
const handleCanPlayReuse = () => setIsReady(true);
|
|
1428
|
-
video.addEventListener("canplay", handleCanPlayReuse, { once: true });
|
|
1429
|
-
video.addEventListener("loadeddata", handleCanPlayReuse, { once: true });
|
|
1430
|
-
video.addEventListener("playing", handleCanPlayReuse, { once: true });
|
|
1431
|
-
if (video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
1432
|
-
video.load();
|
|
1433
|
-
}
|
|
1434
|
-
return () => {
|
|
1435
|
-
video.removeEventListener("canplay", handleCanPlayReuse);
|
|
1436
|
-
video.removeEventListener("loadeddata", handleCanPlayReuse);
|
|
1437
|
-
video.removeEventListener("playing", handleCanPlayReuse);
|
|
1438
|
-
};
|
|
1439
|
-
}
|
|
1440
|
-
video.src = src;
|
|
1441
|
-
currentSrcRef.current = src;
|
|
1442
|
-
if (!isActive) {
|
|
1432
|
+
if (video.src !== src) {
|
|
1433
|
+
video.src = src;
|
|
1443
1434
|
video.load();
|
|
1444
1435
|
}
|
|
1445
|
-
if (video.
|
|
1436
|
+
if (!video.hasAttribute("webkit-playsinline")) {
|
|
1437
|
+
video.setAttribute("webkit-playsinline", "");
|
|
1438
|
+
}
|
|
1439
|
+
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1446
1440
|
setIsReady(true);
|
|
1447
|
-
|
|
1441
|
+
currentSrcRef.current = src;
|
|
1442
|
+
return;
|
|
1448
1443
|
}
|
|
1449
1444
|
setIsReady(false);
|
|
1450
|
-
|
|
1445
|
+
canPlayFiredRef.current = false;
|
|
1446
|
+
currentSrcRef.current = src;
|
|
1447
|
+
const handleCanPlay2 = () => {
|
|
1448
|
+
canPlayFiredRef.current = true;
|
|
1449
|
+
setIsReady(true);
|
|
1450
|
+
};
|
|
1451
|
+
const handleLoadedData = () => {
|
|
1452
|
+
if (!canPlayFiredRef.current) {
|
|
1453
|
+
canPlayFiredRef.current = true;
|
|
1454
|
+
setIsReady(true);
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1451
1457
|
video.addEventListener("canplay", handleCanPlay2, { once: true });
|
|
1452
|
-
video.addEventListener("loadeddata",
|
|
1453
|
-
video.addEventListener("playing", handleCanPlay2, { once: true });
|
|
1458
|
+
video.addEventListener("loadeddata", handleLoadedData, { once: true });
|
|
1454
1459
|
return () => {
|
|
1455
1460
|
video.removeEventListener("canplay", handleCanPlay2);
|
|
1456
|
-
video.removeEventListener("loadeddata",
|
|
1457
|
-
video.removeEventListener("playing", handleCanPlay2);
|
|
1461
|
+
video.removeEventListener("loadeddata", handleLoadedData);
|
|
1458
1462
|
};
|
|
1459
1463
|
}
|
|
1460
1464
|
if (!isHlsSupported) {
|
|
1465
|
+
onErrorRef.current?.("UNKNOWN", "HLS playback not supported in this browser");
|
|
1461
1466
|
return;
|
|
1462
1467
|
}
|
|
1463
1468
|
if (hlsRef.current && currentSrcRef.current === src) {
|
|
@@ -1521,7 +1526,7 @@ function useHls(options) {
|
|
|
1521
1526
|
currentSrcRef.current = void 0;
|
|
1522
1527
|
}
|
|
1523
1528
|
};
|
|
1524
|
-
}, [src, isActive, isPrefetch
|
|
1529
|
+
}, [src, isActive, isPrefetch]);
|
|
1525
1530
|
react.useEffect(() => {
|
|
1526
1531
|
const hls = hlsRef.current;
|
|
1527
1532
|
if (!hls) {
|
|
@@ -1537,10 +1542,15 @@ function useHls(options) {
|
|
|
1537
1542
|
for (const key of configKeys) {
|
|
1538
1543
|
hlsAnyConfig[key] = newConfig[key];
|
|
1539
1544
|
}
|
|
1545
|
+
if (prevTier === "warm" && bufferTier === "active") {
|
|
1546
|
+
try {
|
|
1547
|
+
hls.startLoad();
|
|
1548
|
+
} catch {
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1540
1551
|
}, [bufferTier]);
|
|
1541
1552
|
return {
|
|
1542
1553
|
isHlsJs,
|
|
1543
|
-
isNativeHls,
|
|
1544
1554
|
isReady,
|
|
1545
1555
|
destroy
|
|
1546
1556
|
};
|
|
@@ -1659,6 +1669,60 @@ function skeletonCircle(size) {
|
|
|
1659
1669
|
background: "rgba(255,255,255,0.1)"
|
|
1660
1670
|
};
|
|
1661
1671
|
}
|
|
1672
|
+
function DefaultPauseAction() {
|
|
1673
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1674
|
+
"div",
|
|
1675
|
+
{
|
|
1676
|
+
style: {
|
|
1677
|
+
width: 72,
|
|
1678
|
+
height: 72,
|
|
1679
|
+
borderRadius: "50%",
|
|
1680
|
+
background: "rgba(0, 0, 0, 0.55)",
|
|
1681
|
+
display: "flex",
|
|
1682
|
+
alignItems: "center",
|
|
1683
|
+
justifyContent: "center",
|
|
1684
|
+
pointerEvents: "none",
|
|
1685
|
+
// Inset the triangle visually — triangles look off-center without this
|
|
1686
|
+
paddingLeft: 6
|
|
1687
|
+
},
|
|
1688
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1689
|
+
"svg",
|
|
1690
|
+
{
|
|
1691
|
+
width: "32",
|
|
1692
|
+
height: "32",
|
|
1693
|
+
viewBox: "0 0 32 32",
|
|
1694
|
+
fill: "none",
|
|
1695
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1696
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1697
|
+
"path",
|
|
1698
|
+
{
|
|
1699
|
+
d: "M8 5.5L27 16L8 26.5V5.5Z",
|
|
1700
|
+
fill: "white"
|
|
1701
|
+
}
|
|
1702
|
+
)
|
|
1703
|
+
}
|
|
1704
|
+
)
|
|
1705
|
+
}
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
var PLAY_AHEAD_MAX_CONCURRENT = 2;
|
|
1709
|
+
var _playAheadActive = 0;
|
|
1710
|
+
var _playAheadQueue = [];
|
|
1711
|
+
function acquirePlayAhead() {
|
|
1712
|
+
if (_playAheadActive < PLAY_AHEAD_MAX_CONCURRENT) {
|
|
1713
|
+
_playAheadActive++;
|
|
1714
|
+
return Promise.resolve();
|
|
1715
|
+
}
|
|
1716
|
+
return new Promise((resolve) => _playAheadQueue.push(resolve));
|
|
1717
|
+
}
|
|
1718
|
+
function releasePlayAhead() {
|
|
1719
|
+
_playAheadActive = Math.max(0, _playAheadActive - 1);
|
|
1720
|
+
const next = _playAheadQueue.shift();
|
|
1721
|
+
if (next) {
|
|
1722
|
+
_playAheadActive++;
|
|
1723
|
+
next();
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1662
1726
|
function VideoSlot({
|
|
1663
1727
|
item,
|
|
1664
1728
|
index,
|
|
@@ -1668,10 +1732,11 @@ function VideoSlot({
|
|
|
1668
1732
|
bufferTier,
|
|
1669
1733
|
isMuted,
|
|
1670
1734
|
onToggleMute,
|
|
1735
|
+
onAutoplayBlocked,
|
|
1671
1736
|
showFps = false,
|
|
1672
1737
|
renderOverlay,
|
|
1673
1738
|
renderActions,
|
|
1674
|
-
|
|
1739
|
+
renderPauseAction
|
|
1675
1740
|
}) {
|
|
1676
1741
|
const { optimisticManager, adapters } = useSDK();
|
|
1677
1742
|
if (!isVideoItem(item)) {
|
|
@@ -1704,10 +1769,11 @@ function VideoSlot({
|
|
|
1704
1769
|
bufferTier,
|
|
1705
1770
|
isMuted,
|
|
1706
1771
|
onToggleMute,
|
|
1772
|
+
onAutoplayBlocked,
|
|
1707
1773
|
showFps,
|
|
1708
1774
|
renderOverlay,
|
|
1709
1775
|
renderActions,
|
|
1710
|
-
|
|
1776
|
+
renderPauseAction,
|
|
1711
1777
|
optimisticManager,
|
|
1712
1778
|
adapters
|
|
1713
1779
|
}
|
|
@@ -1722,10 +1788,11 @@ function VideoSlotInner({
|
|
|
1722
1788
|
bufferTier,
|
|
1723
1789
|
isMuted,
|
|
1724
1790
|
onToggleMute,
|
|
1791
|
+
onAutoplayBlocked,
|
|
1725
1792
|
showFps,
|
|
1726
1793
|
renderOverlay,
|
|
1727
1794
|
renderActions,
|
|
1728
|
-
|
|
1795
|
+
renderPauseAction,
|
|
1729
1796
|
optimisticManager,
|
|
1730
1797
|
adapters
|
|
1731
1798
|
}) {
|
|
@@ -1736,7 +1803,7 @@ function VideoSlotInner({
|
|
|
1736
1803
|
const isHlsSource = sourceType === "hls";
|
|
1737
1804
|
const hlsSrc = isHlsSource && shouldLoadSrc ? src : void 0;
|
|
1738
1805
|
const mp4Src = !isHlsSource && shouldLoadSrc ? src : void 0;
|
|
1739
|
-
const { isReady: hlsReady
|
|
1806
|
+
const { isReady: hlsReady } = useHls({
|
|
1740
1807
|
src: hlsSrc,
|
|
1741
1808
|
videoRef,
|
|
1742
1809
|
isActive,
|
|
@@ -1775,9 +1842,7 @@ function VideoSlotInner({
|
|
|
1775
1842
|
}, [mp4Src, isActive, isPrefetch, isPreloaded, isHlsSource]);
|
|
1776
1843
|
const isReady = isHlsSource ? hlsReady : mp4Ready;
|
|
1777
1844
|
const [hasPlayedAhead, setHasPlayedAhead] = react.useState(false);
|
|
1778
|
-
const canPlayAhead = isHlsSource && !isNativeHls;
|
|
1779
1845
|
react.useEffect(() => {
|
|
1780
|
-
if (!canPlayAhead) return;
|
|
1781
1846
|
const video = videoRef.current;
|
|
1782
1847
|
if (!video) return;
|
|
1783
1848
|
if (isActive || !isReady) return;
|
|
@@ -1785,180 +1850,145 @@ function VideoSlotInner({
|
|
|
1785
1850
|
const prevMuted = video.muted;
|
|
1786
1851
|
video.muted = true;
|
|
1787
1852
|
let cancelled = false;
|
|
1788
|
-
let rafId = null;
|
|
1789
|
-
let vfcHandle = null;
|
|
1790
|
-
const pauseAfterDecode = () => {
|
|
1791
|
-
if (cancelled) return;
|
|
1792
|
-
video.pause();
|
|
1793
|
-
video.currentTime = 0;
|
|
1794
|
-
video.muted = prevMuted;
|
|
1795
|
-
setHasPlayedAhead(true);
|
|
1796
|
-
};
|
|
1797
1853
|
const doPlayAhead = async () => {
|
|
1854
|
+
await acquirePlayAhead();
|
|
1798
1855
|
try {
|
|
1799
1856
|
await video.play();
|
|
1800
|
-
if (cancelled)
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
pauseAfterDecode();
|
|
1805
|
-
});
|
|
1806
|
-
} else {
|
|
1807
|
-
rafId = requestAnimationFrame(() => {
|
|
1808
|
-
rafId = requestAnimationFrame(() => {
|
|
1809
|
-
rafId = null;
|
|
1810
|
-
pauseAfterDecode();
|
|
1811
|
-
});
|
|
1812
|
-
});
|
|
1857
|
+
if (cancelled) {
|
|
1858
|
+
video.pause();
|
|
1859
|
+
releasePlayAhead();
|
|
1860
|
+
return;
|
|
1813
1861
|
}
|
|
1862
|
+
const pauseAfterDecode = () => {
|
|
1863
|
+
video.pause();
|
|
1864
|
+
video.currentTime = 0;
|
|
1865
|
+
video.muted = prevMuted;
|
|
1866
|
+
releasePlayAhead();
|
|
1867
|
+
if (!cancelled) {
|
|
1868
|
+
setHasPlayedAhead(true);
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
setTimeout(pauseAfterDecode, 50);
|
|
1814
1872
|
} catch {
|
|
1815
|
-
|
|
1873
|
+
releasePlayAhead();
|
|
1816
1874
|
}
|
|
1817
1875
|
};
|
|
1818
1876
|
doPlayAhead();
|
|
1819
1877
|
return () => {
|
|
1820
1878
|
cancelled = true;
|
|
1821
|
-
if (rafId !== null) {
|
|
1822
|
-
cancelAnimationFrame(rafId);
|
|
1823
|
-
rafId = null;
|
|
1824
|
-
}
|
|
1825
|
-
if (vfcHandle !== null && "cancelVideoFrameCallback" in video) {
|
|
1826
|
-
video.cancelVideoFrameCallback(vfcHandle);
|
|
1827
|
-
vfcHandle = null;
|
|
1828
|
-
}
|
|
1829
1879
|
};
|
|
1830
|
-
}, [
|
|
1880
|
+
}, [isActive, isReady, hasPlayedAhead]);
|
|
1831
1881
|
react.useEffect(() => {
|
|
1832
1882
|
setHasPlayedAhead(false);
|
|
1833
1883
|
}, [src]);
|
|
1834
1884
|
const wasActiveRef = react.useRef(false);
|
|
1885
|
+
const [isManuallyPaused, setIsManuallyPaused] = react.useState(false);
|
|
1835
1886
|
react.useEffect(() => {
|
|
1836
1887
|
const video = videoRef.current;
|
|
1837
1888
|
if (!video) return;
|
|
1838
1889
|
let onReady = null;
|
|
1839
|
-
let
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
const startPlay = () => {
|
|
1844
|
-
if (onReady) {
|
|
1845
|
-
video.removeEventListener("canplay", onReady);
|
|
1846
|
-
video.removeEventListener("loadeddata", onReady);
|
|
1847
|
-
video.removeEventListener("playing", onReady);
|
|
1848
|
-
onReady = null;
|
|
1849
|
-
}
|
|
1850
|
-
if (fallbackTimerId !== null) {
|
|
1851
|
-
clearTimeout(fallbackTimerId);
|
|
1852
|
-
fallbackTimerId = null;
|
|
1853
|
-
}
|
|
1854
|
-
if (pollId !== null) {
|
|
1855
|
-
clearInterval(pollId);
|
|
1856
|
-
pollId = null;
|
|
1857
|
-
}
|
|
1890
|
+
let cancelled = false;
|
|
1891
|
+
const attemptPlay = () => {
|
|
1892
|
+
if (cancelled) return;
|
|
1893
|
+
if (isMuted) {
|
|
1858
1894
|
video.muted = true;
|
|
1859
|
-
video.play().
|
|
1860
|
-
video.muted = isMuted;
|
|
1861
|
-
}).catch(() => {
|
|
1862
|
-
video.muted = isMuted;
|
|
1895
|
+
video.play().catch(() => {
|
|
1863
1896
|
});
|
|
1864
|
-
};
|
|
1865
|
-
if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
1866
|
-
startPlay();
|
|
1867
1897
|
} else {
|
|
1868
|
-
|
|
1869
|
-
video.
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
if (
|
|
1879
|
-
|
|
1880
|
-
|
|
1898
|
+
video.muted = false;
|
|
1899
|
+
video.play().then(() => {
|
|
1900
|
+
if (cancelled) {
|
|
1901
|
+
video.pause();
|
|
1902
|
+
}
|
|
1903
|
+
}).catch((err) => {
|
|
1904
|
+
if (cancelled) return;
|
|
1905
|
+
if (err.name === "NotAllowedError") {
|
|
1906
|
+
video.muted = true;
|
|
1907
|
+
video.play().then(() => {
|
|
1908
|
+
if (cancelled) {
|
|
1909
|
+
video.pause();
|
|
1910
|
+
return;
|
|
1881
1911
|
}
|
|
1882
|
-
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
}
|
|
1886
|
-
fallbackTimerId = window.setTimeout(() => {
|
|
1887
|
-
fallbackTimerId = null;
|
|
1888
|
-
if (onReady) {
|
|
1889
|
-
startPlay();
|
|
1912
|
+
onAutoplayBlocked?.();
|
|
1913
|
+
}).catch(() => {
|
|
1914
|
+
});
|
|
1890
1915
|
}
|
|
1891
|
-
}
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
};
|
|
1919
|
+
if (isActive && !isManuallyPaused) {
|
|
1920
|
+
wasActiveRef.current = true;
|
|
1921
|
+
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1922
|
+
attemptPlay();
|
|
1923
|
+
} else {
|
|
1924
|
+
onReady = attemptPlay;
|
|
1925
|
+
video.addEventListener("canplay", onReady, { once: true });
|
|
1892
1926
|
}
|
|
1927
|
+
} else if (isActive && isManuallyPaused) {
|
|
1928
|
+
wasActiveRef.current = true;
|
|
1929
|
+
video.pause();
|
|
1893
1930
|
} else if (wasActiveRef.current) {
|
|
1894
1931
|
video.pause();
|
|
1895
1932
|
video.currentTime = 0;
|
|
1896
1933
|
wasActiveRef.current = false;
|
|
1934
|
+
setIsManuallyPaused(false);
|
|
1897
1935
|
setHasPlayedAhead(false);
|
|
1898
1936
|
} else if (!hasPlayedAhead) {
|
|
1899
1937
|
video.pause();
|
|
1900
1938
|
}
|
|
1901
1939
|
return () => {
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
video.removeEventListener("loadeddata", onReady);
|
|
1905
|
-
video.removeEventListener("playing", onReady);
|
|
1906
|
-
}
|
|
1907
|
-
if (fallbackTimerId !== null) {
|
|
1908
|
-
clearTimeout(fallbackTimerId);
|
|
1909
|
-
fallbackTimerId = null;
|
|
1910
|
-
}
|
|
1911
|
-
if (pollId !== null) {
|
|
1912
|
-
clearInterval(pollId);
|
|
1913
|
-
pollId = null;
|
|
1914
|
-
}
|
|
1940
|
+
cancelled = true;
|
|
1941
|
+
if (onReady) video.removeEventListener("canplay", onReady);
|
|
1915
1942
|
};
|
|
1916
|
-
}, [isActive, isMuted, hasPlayedAhead,
|
|
1943
|
+
}, [isActive, isMuted, hasPlayedAhead, isManuallyPaused, onAutoplayBlocked]);
|
|
1917
1944
|
react.useEffect(() => {
|
|
1918
1945
|
const video = videoRef.current;
|
|
1919
1946
|
if (!video) return;
|
|
1920
|
-
|
|
1921
|
-
video.muted = isMuted;
|
|
1922
|
-
} else {
|
|
1923
|
-
video.muted = true;
|
|
1924
|
-
}
|
|
1947
|
+
video.muted = isActive ? isMuted : true;
|
|
1925
1948
|
}, [isMuted, isActive]);
|
|
1926
|
-
const
|
|
1927
|
-
react.
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
video.removeEventListener("ended", onEnded);
|
|
1940
|
-
};
|
|
1949
|
+
const showPosterOverlay = !isReady && !hasPlayedAhead;
|
|
1950
|
+
const [showMuteIndicator, setShowMuteIndicator] = react.useState(false);
|
|
1951
|
+
const muteIndicatorTimer = react.useRef(null);
|
|
1952
|
+
const handleToggleMute = react.useCallback(() => {
|
|
1953
|
+
onToggleMute();
|
|
1954
|
+
setShowMuteIndicator(true);
|
|
1955
|
+
if (muteIndicatorTimer.current) clearTimeout(muteIndicatorTimer.current);
|
|
1956
|
+
muteIndicatorTimer.current = setTimeout(() => setShowMuteIndicator(false), 1200);
|
|
1957
|
+
}, [onToggleMute]);
|
|
1958
|
+
const tapStartRef = react.useRef(null);
|
|
1959
|
+
const TAP_SLOP_PX = 10;
|
|
1960
|
+
const handlePointerDown = react.useCallback((e) => {
|
|
1961
|
+
tapStartRef.current = { x: e.clientX, y: e.clientY };
|
|
1941
1962
|
}, []);
|
|
1942
|
-
react.
|
|
1943
|
-
if (
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1963
|
+
const handleClick = react.useCallback((e) => {
|
|
1964
|
+
if (e.button !== 0) return;
|
|
1965
|
+
if (!isActive) return;
|
|
1966
|
+
const start = tapStartRef.current;
|
|
1967
|
+
if (start) {
|
|
1968
|
+
const dx = Math.abs(e.clientX - start.x);
|
|
1969
|
+
const dy = Math.abs(e.clientY - start.y);
|
|
1970
|
+
if (dx > TAP_SLOP_PX || dy > TAP_SLOP_PX) {
|
|
1971
|
+
tapStartRef.current = null;
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
tapStartRef.current = null;
|
|
1948
1976
|
const video = videoRef.current;
|
|
1949
|
-
if (!video
|
|
1950
|
-
if (video.paused) {
|
|
1951
|
-
|
|
1977
|
+
if (!video) return;
|
|
1978
|
+
if (video.paused || isManuallyPaused) {
|
|
1979
|
+
setIsManuallyPaused(false);
|
|
1980
|
+
video.muted = true;
|
|
1981
|
+
video.play().then(() => {
|
|
1982
|
+
requestAnimationFrame(() => {
|
|
1983
|
+
video.muted = isMuted;
|
|
1984
|
+
});
|
|
1985
|
+
}).catch(() => {
|
|
1952
1986
|
});
|
|
1953
|
-
setIsPaused(false);
|
|
1954
1987
|
} else {
|
|
1988
|
+
setIsManuallyPaused(true);
|
|
1955
1989
|
video.pause();
|
|
1956
|
-
setIsPaused(true);
|
|
1957
1990
|
}
|
|
1958
|
-
}, [isActive]);
|
|
1959
|
-
react.useEffect(() => {
|
|
1960
|
-
if (isActive) setIsPaused(false);
|
|
1961
|
-
}, [isActive]);
|
|
1991
|
+
}, [isActive, isManuallyPaused, isMuted]);
|
|
1962
1992
|
const likeDelta = react.useSyncExternalStore(
|
|
1963
1993
|
optimisticManager.store.subscribe,
|
|
1964
1994
|
() => optimisticManager.getLikeDelta(item.id),
|
|
@@ -1976,12 +2006,36 @@ function VideoSlotInner({
|
|
|
1976
2006
|
followState,
|
|
1977
2007
|
share: () => adapters.interaction?.share?.(item.id),
|
|
1978
2008
|
isMuted,
|
|
1979
|
-
toggleMute:
|
|
1980
|
-
isPaused,
|
|
1981
|
-
togglePause: handleTap,
|
|
2009
|
+
toggleMute: handleToggleMute,
|
|
1982
2010
|
isActive,
|
|
1983
2011
|
index
|
|
1984
|
-
}), [item, likeDelta, followState, isMuted,
|
|
2012
|
+
}), [item, likeDelta, followState, isMuted, isActive, index, optimisticManager, adapters, handleToggleMute]);
|
|
2013
|
+
const pauseActions = react.useMemo(() => ({
|
|
2014
|
+
...actions,
|
|
2015
|
+
isPaused: isManuallyPaused,
|
|
2016
|
+
togglePlayPause: () => {
|
|
2017
|
+
const video = videoRef.current;
|
|
2018
|
+
if (!video) return;
|
|
2019
|
+
if (isManuallyPaused) {
|
|
2020
|
+
setIsManuallyPaused(false);
|
|
2021
|
+
video.muted = true;
|
|
2022
|
+
video.play().then(() => {
|
|
2023
|
+
requestAnimationFrame(() => {
|
|
2024
|
+
video.muted = isMuted;
|
|
2025
|
+
});
|
|
2026
|
+
}).catch(() => {
|
|
2027
|
+
});
|
|
2028
|
+
} else {
|
|
2029
|
+
setIsManuallyPaused(true);
|
|
2030
|
+
video.pause();
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}), [actions, isManuallyPaused, isMuted]);
|
|
2034
|
+
react.useEffect(() => {
|
|
2035
|
+
return () => {
|
|
2036
|
+
if (muteIndicatorTimer.current) clearTimeout(muteIndicatorTimer.current);
|
|
2037
|
+
};
|
|
2038
|
+
}, []);
|
|
1985
2039
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1986
2040
|
"div",
|
|
1987
2041
|
{
|
|
@@ -1992,7 +2046,8 @@ function VideoSlotInner({
|
|
|
1992
2046
|
background: "#111",
|
|
1993
2047
|
overflow: "hidden"
|
|
1994
2048
|
},
|
|
1995
|
-
|
|
2049
|
+
onPointerDown: handlePointerDown,
|
|
2050
|
+
onClick: handleClick,
|
|
1996
2051
|
children: [
|
|
1997
2052
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1998
2053
|
"video",
|
|
@@ -2000,9 +2055,8 @@ function VideoSlotInner({
|
|
|
2000
2055
|
ref: videoRef,
|
|
2001
2056
|
src: mp4Src,
|
|
2002
2057
|
loop: true,
|
|
2003
|
-
muted: true,
|
|
2058
|
+
muted: isActive ? isMuted : true,
|
|
2004
2059
|
playsInline: true,
|
|
2005
|
-
autoPlay: isActive,
|
|
2006
2060
|
preload: shouldLoadSrc ? "auto" : "none",
|
|
2007
2061
|
style: {
|
|
2008
2062
|
width: "100%",
|
|
@@ -2029,7 +2083,7 @@ function VideoSlotInner({
|
|
|
2029
2083
|
}
|
|
2030
2084
|
}
|
|
2031
2085
|
),
|
|
2032
|
-
|
|
2086
|
+
showMuteIndicator && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2033
2087
|
"div",
|
|
2034
2088
|
{
|
|
2035
2089
|
style: {
|
|
@@ -2037,26 +2091,32 @@ function VideoSlotInner({
|
|
|
2037
2091
|
top: "50%",
|
|
2038
2092
|
left: "50%",
|
|
2039
2093
|
transform: "translate(-50%, -50%)",
|
|
2094
|
+
background: "rgba(0,0,0,0.6)",
|
|
2095
|
+
borderRadius: "50%",
|
|
2096
|
+
width: 64,
|
|
2097
|
+
height: 64,
|
|
2098
|
+
display: "flex",
|
|
2099
|
+
alignItems: "center",
|
|
2100
|
+
justifyContent: "center",
|
|
2101
|
+
fontSize: 28,
|
|
2040
2102
|
pointerEvents: "none",
|
|
2041
|
-
|
|
2042
|
-
opacity: 0.3
|
|
2103
|
+
animation: "reels-sdk-fadeInOut 1.2s ease forwards"
|
|
2043
2104
|
},
|
|
2044
|
-
children:
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
)
|
|
2105
|
+
children: isMuted ? "\u{1F507}" : "\u{1F50A}"
|
|
2106
|
+
}
|
|
2107
|
+
),
|
|
2108
|
+
isActive && isManuallyPaused && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2109
|
+
"div",
|
|
2110
|
+
{
|
|
2111
|
+
style: {
|
|
2112
|
+
position: "absolute",
|
|
2113
|
+
top: "50%",
|
|
2114
|
+
left: "50%",
|
|
2115
|
+
transform: "translate(-50%, -50%)",
|
|
2116
|
+
pointerEvents: "none",
|
|
2117
|
+
animation: "reels-sdk-fadeIn 0.2s ease forwards"
|
|
2118
|
+
},
|
|
2119
|
+
children: renderPauseAction ? renderPauseAction(item, pauseActions) : /* @__PURE__ */ jsxRuntime.jsx(DefaultPauseAction, {})
|
|
2060
2120
|
}
|
|
2061
2121
|
),
|
|
2062
2122
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2064,13 +2124,11 @@ function VideoSlotInner({
|
|
|
2064
2124
|
{
|
|
2065
2125
|
style: {
|
|
2066
2126
|
position: "absolute",
|
|
2067
|
-
bottom:
|
|
2127
|
+
bottom: 80,
|
|
2068
2128
|
left: 16,
|
|
2069
2129
|
right: 80,
|
|
2070
|
-
paddingBottom: 16,
|
|
2071
2130
|
pointerEvents: "none",
|
|
2072
|
-
color: "#fff"
|
|
2073
|
-
zIndex: 10
|
|
2131
|
+
color: "#fff"
|
|
2074
2132
|
},
|
|
2075
2133
|
children: renderOverlay ? renderOverlay(item, actions) : /* @__PURE__ */ jsxRuntime.jsx(DefaultOverlay, { item })
|
|
2076
2134
|
}
|
|
@@ -2078,19 +2136,18 @@ function VideoSlotInner({
|
|
|
2078
2136
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2079
2137
|
"div",
|
|
2080
2138
|
{
|
|
2081
|
-
onClick: (e) => e.stopPropagation(),
|
|
2082
2139
|
style: {
|
|
2083
2140
|
position: "absolute",
|
|
2084
|
-
bottom:
|
|
2141
|
+
bottom: 80,
|
|
2085
2142
|
right: 16,
|
|
2086
|
-
paddingBottom: 16,
|
|
2087
2143
|
display: "flex",
|
|
2088
2144
|
flexDirection: "column",
|
|
2089
2145
|
gap: 20,
|
|
2090
|
-
alignItems: "center"
|
|
2091
|
-
|
|
2092
|
-
|
|
2146
|
+
alignItems: "center"
|
|
2147
|
+
// Actions must be clickable; stop propagation so taps don't
|
|
2148
|
+
// also trigger the video play/pause handler on the container.
|
|
2093
2149
|
},
|
|
2150
|
+
onClick: (e) => e.stopPropagation(),
|
|
2094
2151
|
children: renderActions ? renderActions(item, actions) : /* @__PURE__ */ jsxRuntime.jsx(DefaultActions, { item, actions })
|
|
2095
2152
|
}
|
|
2096
2153
|
),
|
|
@@ -2140,6 +2197,7 @@ function FpsCounter() {
|
|
|
2140
2197
|
}
|
|
2141
2198
|
);
|
|
2142
2199
|
}
|
|
2200
|
+
var RENDER_WINDOW_RADIUS = 3;
|
|
2143
2201
|
var centerStyle = {
|
|
2144
2202
|
height: "100dvh",
|
|
2145
2203
|
display: "flex",
|
|
@@ -2151,7 +2209,7 @@ var centerStyle = {
|
|
|
2151
2209
|
function ReelsFeed({
|
|
2152
2210
|
renderOverlay,
|
|
2153
2211
|
renderActions,
|
|
2154
|
-
|
|
2212
|
+
renderPauseAction,
|
|
2155
2213
|
renderLoading,
|
|
2156
2214
|
renderEmpty,
|
|
2157
2215
|
renderError: _renderError,
|
|
@@ -2159,21 +2217,24 @@ function ReelsFeed({
|
|
|
2159
2217
|
loadMoreThreshold = 5,
|
|
2160
2218
|
onSlotChange,
|
|
2161
2219
|
gestureConfig,
|
|
2162
|
-
snapConfig
|
|
2220
|
+
snapConfig,
|
|
2221
|
+
initialMuted = true,
|
|
2222
|
+
onAutoplayBlocked
|
|
2163
2223
|
}) {
|
|
2164
2224
|
const { items, loading, loadInitial, loadMore, hasMore } = useFeed();
|
|
2225
|
+
const { adapters } = useSDK();
|
|
2165
2226
|
const {
|
|
2166
|
-
activeIndices,
|
|
2167
|
-
warmIndices,
|
|
2168
2227
|
focusedIndex,
|
|
2169
2228
|
prefetchIndex,
|
|
2229
|
+
preloadQueue,
|
|
2170
2230
|
setFocusedIndexImmediate,
|
|
2171
2231
|
setTotalItems,
|
|
2172
2232
|
shouldRenderVideo,
|
|
2173
2233
|
isWarmAllocated,
|
|
2174
2234
|
setPrefetchIndex
|
|
2175
2235
|
} = useResource();
|
|
2176
|
-
const [isMuted, setIsMuted] = react.useState(
|
|
2236
|
+
const [isMuted, setIsMuted] = react.useState(initialMuted);
|
|
2237
|
+
const [isDragMuted, setIsDragMuted] = react.useState(false);
|
|
2177
2238
|
const containerRef = react.useRef(null);
|
|
2178
2239
|
const slotCacheRef = react.useRef(/* @__PURE__ */ new Map());
|
|
2179
2240
|
const activeIndexRef = react.useRef(0);
|
|
@@ -2189,6 +2250,14 @@ function ReelsFeed({
|
|
|
2189
2250
|
react.useEffect(() => {
|
|
2190
2251
|
setTotalItems(items.length);
|
|
2191
2252
|
}, [items.length, setTotalItems]);
|
|
2253
|
+
react.useEffect(() => {
|
|
2254
|
+
for (const idx of preloadQueue) {
|
|
2255
|
+
const item = items[idx];
|
|
2256
|
+
if (item && isVideoItem(item) && item.source.type === "hls") {
|
|
2257
|
+
adapters.videoLoader?.preloadMetadata?.(item.source.url);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}, [preloadQueue, items, adapters.videoLoader]);
|
|
2192
2261
|
react.useEffect(() => {
|
|
2193
2262
|
if (items.length - focusedIndex <= loadMoreThreshold && hasMore && !loading) {
|
|
2194
2263
|
loadMore();
|
|
@@ -2209,7 +2278,7 @@ function ReelsFeed({
|
|
|
2209
2278
|
const observer = new MutationObserver(rebuild);
|
|
2210
2279
|
observer.observe(container, { childList: true, subtree: true });
|
|
2211
2280
|
return () => observer.disconnect();
|
|
2212
|
-
}, [items.length]);
|
|
2281
|
+
}, [items.length, focusedIndex]);
|
|
2213
2282
|
const containerHeight = react.useRef(
|
|
2214
2283
|
typeof window !== "undefined" ? window.innerHeight : 800
|
|
2215
2284
|
);
|
|
@@ -2300,6 +2369,12 @@ function ReelsFeed({
|
|
|
2300
2369
|
animateBounceBack(targets);
|
|
2301
2370
|
setPrefetchIndex(null);
|
|
2302
2371
|
}, [animateBounceBack, setPrefetchIndex]);
|
|
2372
|
+
const handleDragStart = react.useCallback(() => {
|
|
2373
|
+
setIsDragMuted(true);
|
|
2374
|
+
}, []);
|
|
2375
|
+
const handleDragEnd = react.useCallback(() => {
|
|
2376
|
+
setTimeout(() => setIsDragMuted(false), 50);
|
|
2377
|
+
}, []);
|
|
2303
2378
|
const { bind } = usePointerGesture({
|
|
2304
2379
|
axis: "y",
|
|
2305
2380
|
velocityThreshold: gestureConfig?.velocityThreshold ?? 0.3,
|
|
@@ -2312,7 +2387,9 @@ function ReelsFeed({
|
|
|
2312
2387
|
},
|
|
2313
2388
|
onDragThreshold: handleDragThreshold,
|
|
2314
2389
|
onSnap: handleSnap,
|
|
2315
|
-
onBounceBack: handleBounceBack
|
|
2390
|
+
onBounceBack: handleBounceBack,
|
|
2391
|
+
onDragStart: handleDragStart,
|
|
2392
|
+
onDragEnd: handleDragEnd
|
|
2316
2393
|
});
|
|
2317
2394
|
const getInitialTransformPx = react.useCallback(
|
|
2318
2395
|
(index) => {
|
|
@@ -2354,58 +2431,58 @@ function ReelsFeed({
|
|
|
2354
2431
|
70% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
|
2355
2432
|
100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
|
|
2356
2433
|
}
|
|
2434
|
+
@keyframes reels-sdk-fadeIn {
|
|
2435
|
+
from { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
|
|
2436
|
+
to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
|
2437
|
+
}
|
|
2357
2438
|
@keyframes reels-sdk-spin {
|
|
2358
2439
|
to { transform: rotate(360deg); }
|
|
2359
2440
|
}
|
|
2360
2441
|
` }),
|
|
2361
|
-
(() => {
|
|
2362
|
-
const
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2442
|
+
items.map((item, index) => {
|
|
2443
|
+
const distFromFocus = Math.abs(index - focusedIndex);
|
|
2444
|
+
const wrapperStyle = {
|
|
2445
|
+
position: "absolute",
|
|
2446
|
+
inset: 0,
|
|
2447
|
+
contain: "layout style paint",
|
|
2448
|
+
willChange: distFromFocus <= 1 ? "transform" : "auto",
|
|
2449
|
+
transform: getInitialTransformPx(index)
|
|
2450
|
+
};
|
|
2451
|
+
if (distFromFocus > RENDER_WINDOW_RADIUS) {
|
|
2452
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot-index": index, style: wrapperStyle }, item.id);
|
|
2368
2453
|
}
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
renderPauseIndicator
|
|
2402
|
-
}
|
|
2403
|
-
) : null
|
|
2404
|
-
},
|
|
2405
|
-
item.id
|
|
2406
|
-
);
|
|
2407
|
-
});
|
|
2408
|
-
})()
|
|
2454
|
+
const isActive = index === focusedIndex;
|
|
2455
|
+
const isPrefetch = index === prefetchIndex;
|
|
2456
|
+
const isWarm = isWarmAllocated(index);
|
|
2457
|
+
const isVisible = shouldRenderVideo(index) || isPrefetch;
|
|
2458
|
+
const bufferTier = isActive ? "active" : isWarm ? "warm" : "hot";
|
|
2459
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2460
|
+
"div",
|
|
2461
|
+
{
|
|
2462
|
+
"data-slot-index": index,
|
|
2463
|
+
style: wrapperStyle,
|
|
2464
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2465
|
+
VideoSlot,
|
|
2466
|
+
{
|
|
2467
|
+
item,
|
|
2468
|
+
index,
|
|
2469
|
+
isActive,
|
|
2470
|
+
isPrefetch,
|
|
2471
|
+
isPreloaded: !isActive && !isPrefetch && isVisible,
|
|
2472
|
+
bufferTier,
|
|
2473
|
+
isMuted: isMuted || isDragMuted,
|
|
2474
|
+
onToggleMute: handleToggleMute,
|
|
2475
|
+
onAutoplayBlocked,
|
|
2476
|
+
showFps: showFps && isActive,
|
|
2477
|
+
renderOverlay,
|
|
2478
|
+
renderActions,
|
|
2479
|
+
renderPauseAction
|
|
2480
|
+
}
|
|
2481
|
+
)
|
|
2482
|
+
},
|
|
2483
|
+
item.id
|
|
2484
|
+
);
|
|
2485
|
+
})
|
|
2409
2486
|
]
|
|
2410
2487
|
}
|
|
2411
2488
|
);
|
|
@@ -2660,6 +2737,8 @@ var MockVideoLoader = class {
|
|
|
2660
2737
|
this.preloaded.clear();
|
|
2661
2738
|
this.loading.clear();
|
|
2662
2739
|
}
|
|
2740
|
+
preloadMetadata(_url) {
|
|
2741
|
+
}
|
|
2663
2742
|
};
|
|
2664
2743
|
var MockDataSource = class {
|
|
2665
2744
|
constructor(options = {}) {
|
|
@@ -3034,6 +3113,7 @@ exports.DEFAULT_PLAYER_CONFIG = DEFAULT_PLAYER_CONFIG;
|
|
|
3034
3113
|
exports.DEFAULT_RESOURCE_CONFIG = DEFAULT_RESOURCE_CONFIG;
|
|
3035
3114
|
exports.DefaultActions = DefaultActions;
|
|
3036
3115
|
exports.DefaultOverlay = DefaultOverlay;
|
|
3116
|
+
exports.DefaultPauseAction = DefaultPauseAction;
|
|
3037
3117
|
exports.DefaultSkeleton = DefaultSkeleton;
|
|
3038
3118
|
exports.FeedManager = FeedManager;
|
|
3039
3119
|
exports.HttpDataSource = HttpDataSource;
|