@xhub-reels/sdk 0.1.9 → 0.1.10
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 +82 -17
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +82 -17
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1392,6 +1392,15 @@ function useHls(options) {
|
|
|
1392
1392
|
return;
|
|
1393
1393
|
}
|
|
1394
1394
|
if (!isActive && !isPrefetch) {
|
|
1395
|
+
if (isNative) {
|
|
1396
|
+
if (video.src) {
|
|
1397
|
+
video.removeAttribute("src");
|
|
1398
|
+
video.load();
|
|
1399
|
+
}
|
|
1400
|
+
setIsReady(false);
|
|
1401
|
+
currentSrcRef.current = void 0;
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1395
1404
|
destroy();
|
|
1396
1405
|
setIsReady(false);
|
|
1397
1406
|
canPlayFiredRef.current = false;
|
|
@@ -1399,20 +1408,36 @@ function useHls(options) {
|
|
|
1399
1408
|
return;
|
|
1400
1409
|
}
|
|
1401
1410
|
if (isNative) {
|
|
1402
|
-
if (
|
|
1403
|
-
video.
|
|
1411
|
+
if (currentSrcRef.current === src) {
|
|
1412
|
+
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1413
|
+
setIsReady(true);
|
|
1414
|
+
return void 0;
|
|
1415
|
+
}
|
|
1416
|
+
const handleCanPlayReuse = () => setIsReady(true);
|
|
1417
|
+
video.addEventListener("canplay", handleCanPlayReuse, { once: true });
|
|
1418
|
+
video.addEventListener("loadeddata", handleCanPlayReuse, { once: true });
|
|
1419
|
+
video.addEventListener("playing", handleCanPlayReuse, { once: true });
|
|
1420
|
+
return () => {
|
|
1421
|
+
video.removeEventListener("canplay", handleCanPlayReuse);
|
|
1422
|
+
video.removeEventListener("loadeddata", handleCanPlayReuse);
|
|
1423
|
+
video.removeEventListener("playing", handleCanPlayReuse);
|
|
1424
|
+
};
|
|
1404
1425
|
}
|
|
1426
|
+
video.src = src;
|
|
1427
|
+
currentSrcRef.current = src;
|
|
1405
1428
|
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1406
1429
|
setIsReady(true);
|
|
1407
|
-
|
|
1408
|
-
return;
|
|
1430
|
+
return void 0;
|
|
1409
1431
|
}
|
|
1410
1432
|
setIsReady(false);
|
|
1411
|
-
currentSrcRef.current = src;
|
|
1412
1433
|
const handleCanPlay2 = () => setIsReady(true);
|
|
1413
1434
|
video.addEventListener("canplay", handleCanPlay2, { once: true });
|
|
1435
|
+
video.addEventListener("loadeddata", handleCanPlay2, { once: true });
|
|
1436
|
+
video.addEventListener("playing", handleCanPlay2, { once: true });
|
|
1414
1437
|
return () => {
|
|
1415
1438
|
video.removeEventListener("canplay", handleCanPlay2);
|
|
1439
|
+
video.removeEventListener("loadeddata", handleCanPlay2);
|
|
1440
|
+
video.removeEventListener("playing", handleCanPlay2);
|
|
1416
1441
|
};
|
|
1417
1442
|
}
|
|
1418
1443
|
if (!isHlsSupported) {
|
|
@@ -1499,6 +1524,7 @@ function useHls(options) {
|
|
|
1499
1524
|
}, [bufferTier]);
|
|
1500
1525
|
return {
|
|
1501
1526
|
isHlsJs,
|
|
1527
|
+
isNativeHls: isNative,
|
|
1502
1528
|
isReady,
|
|
1503
1529
|
destroy
|
|
1504
1530
|
};
|
|
@@ -1694,7 +1720,7 @@ function VideoSlotInner({
|
|
|
1694
1720
|
const isHlsSource = sourceType === "hls";
|
|
1695
1721
|
const hlsSrc = isHlsSource && shouldLoadSrc ? src : void 0;
|
|
1696
1722
|
const mp4Src = !isHlsSource && shouldLoadSrc ? src : void 0;
|
|
1697
|
-
const { isReady: hlsReady } = useHls({
|
|
1723
|
+
const { isReady: hlsReady, isNativeHls } = useHls({
|
|
1698
1724
|
src: hlsSrc,
|
|
1699
1725
|
videoRef,
|
|
1700
1726
|
isActive,
|
|
@@ -1733,7 +1759,9 @@ function VideoSlotInner({
|
|
|
1733
1759
|
}, [mp4Src, isActive, isPrefetch, isPreloaded, isHlsSource]);
|
|
1734
1760
|
const isReady = isHlsSource ? hlsReady : mp4Ready;
|
|
1735
1761
|
const [hasPlayedAhead, setHasPlayedAhead] = react.useState(false);
|
|
1762
|
+
const canPlayAhead = isHlsSource && !isNativeHls;
|
|
1736
1763
|
react.useEffect(() => {
|
|
1764
|
+
if (!canPlayAhead) return;
|
|
1737
1765
|
const video = videoRef.current;
|
|
1738
1766
|
if (!video) return;
|
|
1739
1767
|
if (isActive || !isReady) return;
|
|
@@ -1760,7 +1788,7 @@ function VideoSlotInner({
|
|
|
1760
1788
|
return () => {
|
|
1761
1789
|
cancelled = true;
|
|
1762
1790
|
};
|
|
1763
|
-
}, [isActive, isReady, hasPlayedAhead]);
|
|
1791
|
+
}, [canPlayAhead, isActive, isReady, hasPlayedAhead]);
|
|
1764
1792
|
react.useEffect(() => {
|
|
1765
1793
|
setHasPlayedAhead(false);
|
|
1766
1794
|
}, [src]);
|
|
@@ -1771,16 +1799,30 @@ function VideoSlotInner({
|
|
|
1771
1799
|
let onReady = null;
|
|
1772
1800
|
if (isActive) {
|
|
1773
1801
|
wasActiveRef.current = true;
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1802
|
+
const startPlay = () => {
|
|
1803
|
+
if (onReady) {
|
|
1804
|
+
video.removeEventListener("canplay", onReady);
|
|
1805
|
+
video.removeEventListener("loadeddata", onReady);
|
|
1806
|
+
video.removeEventListener("playing", onReady);
|
|
1807
|
+
onReady = null;
|
|
1808
|
+
}
|
|
1809
|
+
video.muted = true;
|
|
1810
|
+
video.play().then(() => {
|
|
1811
|
+
video.muted = isMuted;
|
|
1812
|
+
}).catch(() => {
|
|
1813
|
+
video.muted = isMuted;
|
|
1777
1814
|
});
|
|
1815
|
+
};
|
|
1816
|
+
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1817
|
+
startPlay();
|
|
1778
1818
|
} else {
|
|
1779
|
-
onReady =
|
|
1780
|
-
video.play().catch(() => {
|
|
1781
|
-
});
|
|
1782
|
-
};
|
|
1819
|
+
onReady = startPlay;
|
|
1783
1820
|
video.addEventListener("canplay", onReady, { once: true });
|
|
1821
|
+
video.addEventListener("loadeddata", onReady, { once: true });
|
|
1822
|
+
video.addEventListener("playing", onReady, { once: true });
|
|
1823
|
+
if (video.readyState === HTMLMediaElement.HAVE_NOTHING && isNativeHls && video.src) {
|
|
1824
|
+
video.load();
|
|
1825
|
+
}
|
|
1784
1826
|
}
|
|
1785
1827
|
} else if (wasActiveRef.current) {
|
|
1786
1828
|
video.pause();
|
|
@@ -1791,15 +1833,38 @@ function VideoSlotInner({
|
|
|
1791
1833
|
video.pause();
|
|
1792
1834
|
}
|
|
1793
1835
|
return () => {
|
|
1794
|
-
if (onReady)
|
|
1836
|
+
if (onReady) {
|
|
1837
|
+
video.removeEventListener("canplay", onReady);
|
|
1838
|
+
video.removeEventListener("loadeddata", onReady);
|
|
1839
|
+
video.removeEventListener("playing", onReady);
|
|
1840
|
+
}
|
|
1795
1841
|
};
|
|
1796
|
-
}, [isActive, isMuted, hasPlayedAhead]);
|
|
1842
|
+
}, [isActive, isMuted, hasPlayedAhead, isNativeHls]);
|
|
1797
1843
|
react.useEffect(() => {
|
|
1798
1844
|
const video = videoRef.current;
|
|
1799
1845
|
if (!video) return;
|
|
1800
1846
|
video.muted = isMuted;
|
|
1801
1847
|
}, [isMuted]);
|
|
1802
|
-
const
|
|
1848
|
+
const [isActuallyPlaying, setIsActuallyPlaying] = react.useState(false);
|
|
1849
|
+
react.useEffect(() => {
|
|
1850
|
+
const video = videoRef.current;
|
|
1851
|
+
if (!video) return;
|
|
1852
|
+
const onPlaying = () => setIsActuallyPlaying(true);
|
|
1853
|
+
const onPause = () => setIsActuallyPlaying(false);
|
|
1854
|
+
const onEnded = () => setIsActuallyPlaying(false);
|
|
1855
|
+
video.addEventListener("playing", onPlaying);
|
|
1856
|
+
video.addEventListener("pause", onPause);
|
|
1857
|
+
video.addEventListener("ended", onEnded);
|
|
1858
|
+
return () => {
|
|
1859
|
+
video.removeEventListener("playing", onPlaying);
|
|
1860
|
+
video.removeEventListener("pause", onPause);
|
|
1861
|
+
video.removeEventListener("ended", onEnded);
|
|
1862
|
+
};
|
|
1863
|
+
}, []);
|
|
1864
|
+
react.useEffect(() => {
|
|
1865
|
+
if (!isActive) setIsActuallyPlaying(false);
|
|
1866
|
+
}, [isActive]);
|
|
1867
|
+
const showPosterOverlay = isActive ? !isReady && !isActuallyPlaying : canPlayAhead ? !hasPlayedAhead : !isReady;
|
|
1803
1868
|
const [isPaused, setIsPaused] = react.useState(false);
|
|
1804
1869
|
const handleTap = react.useCallback(() => {
|
|
1805
1870
|
const video = videoRef.current;
|
package/dist/index.d.cts
CHANGED
|
@@ -775,6 +775,12 @@ interface UseHlsOptions {
|
|
|
775
775
|
interface UseHlsReturn {
|
|
776
776
|
/** Whether hls.js is being used (false = native HLS on Safari) */
|
|
777
777
|
isHlsJs: boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Whether the device uses native HLS (Safari / iOS WebView).
|
|
780
|
+
* When true, play-ahead (video.play() on non-active slots) must be skipped —
|
|
781
|
+
* iOS only allows one concurrently-playing video element at a time.
|
|
782
|
+
*/
|
|
783
|
+
isNativeHls: boolean;
|
|
778
784
|
/** Whether the video has buffered enough data to play without black flash */
|
|
779
785
|
isReady: boolean;
|
|
780
786
|
/** Destroy the HLS instance manually (also called automatically on unmount) */
|
package/dist/index.d.ts
CHANGED
|
@@ -775,6 +775,12 @@ interface UseHlsOptions {
|
|
|
775
775
|
interface UseHlsReturn {
|
|
776
776
|
/** Whether hls.js is being used (false = native HLS on Safari) */
|
|
777
777
|
isHlsJs: boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Whether the device uses native HLS (Safari / iOS WebView).
|
|
780
|
+
* When true, play-ahead (video.play() on non-active slots) must be skipped —
|
|
781
|
+
* iOS only allows one concurrently-playing video element at a time.
|
|
782
|
+
*/
|
|
783
|
+
isNativeHls: boolean;
|
|
778
784
|
/** Whether the video has buffered enough data to play without black flash */
|
|
779
785
|
isReady: boolean;
|
|
780
786
|
/** Destroy the HLS instance manually (also called automatically on unmount) */
|
package/dist/index.js
CHANGED
|
@@ -1386,6 +1386,15 @@ function useHls(options) {
|
|
|
1386
1386
|
return;
|
|
1387
1387
|
}
|
|
1388
1388
|
if (!isActive && !isPrefetch) {
|
|
1389
|
+
if (isNative) {
|
|
1390
|
+
if (video.src) {
|
|
1391
|
+
video.removeAttribute("src");
|
|
1392
|
+
video.load();
|
|
1393
|
+
}
|
|
1394
|
+
setIsReady(false);
|
|
1395
|
+
currentSrcRef.current = void 0;
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1389
1398
|
destroy();
|
|
1390
1399
|
setIsReady(false);
|
|
1391
1400
|
canPlayFiredRef.current = false;
|
|
@@ -1393,20 +1402,36 @@ function useHls(options) {
|
|
|
1393
1402
|
return;
|
|
1394
1403
|
}
|
|
1395
1404
|
if (isNative) {
|
|
1396
|
-
if (
|
|
1397
|
-
video.
|
|
1405
|
+
if (currentSrcRef.current === src) {
|
|
1406
|
+
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1407
|
+
setIsReady(true);
|
|
1408
|
+
return void 0;
|
|
1409
|
+
}
|
|
1410
|
+
const handleCanPlayReuse = () => setIsReady(true);
|
|
1411
|
+
video.addEventListener("canplay", handleCanPlayReuse, { once: true });
|
|
1412
|
+
video.addEventListener("loadeddata", handleCanPlayReuse, { once: true });
|
|
1413
|
+
video.addEventListener("playing", handleCanPlayReuse, { once: true });
|
|
1414
|
+
return () => {
|
|
1415
|
+
video.removeEventListener("canplay", handleCanPlayReuse);
|
|
1416
|
+
video.removeEventListener("loadeddata", handleCanPlayReuse);
|
|
1417
|
+
video.removeEventListener("playing", handleCanPlayReuse);
|
|
1418
|
+
};
|
|
1398
1419
|
}
|
|
1420
|
+
video.src = src;
|
|
1421
|
+
currentSrcRef.current = src;
|
|
1399
1422
|
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1400
1423
|
setIsReady(true);
|
|
1401
|
-
|
|
1402
|
-
return;
|
|
1424
|
+
return void 0;
|
|
1403
1425
|
}
|
|
1404
1426
|
setIsReady(false);
|
|
1405
|
-
currentSrcRef.current = src;
|
|
1406
1427
|
const handleCanPlay2 = () => setIsReady(true);
|
|
1407
1428
|
video.addEventListener("canplay", handleCanPlay2, { once: true });
|
|
1429
|
+
video.addEventListener("loadeddata", handleCanPlay2, { once: true });
|
|
1430
|
+
video.addEventListener("playing", handleCanPlay2, { once: true });
|
|
1408
1431
|
return () => {
|
|
1409
1432
|
video.removeEventListener("canplay", handleCanPlay2);
|
|
1433
|
+
video.removeEventListener("loadeddata", handleCanPlay2);
|
|
1434
|
+
video.removeEventListener("playing", handleCanPlay2);
|
|
1410
1435
|
};
|
|
1411
1436
|
}
|
|
1412
1437
|
if (!isHlsSupported) {
|
|
@@ -1493,6 +1518,7 @@ function useHls(options) {
|
|
|
1493
1518
|
}, [bufferTier]);
|
|
1494
1519
|
return {
|
|
1495
1520
|
isHlsJs,
|
|
1521
|
+
isNativeHls: isNative,
|
|
1496
1522
|
isReady,
|
|
1497
1523
|
destroy
|
|
1498
1524
|
};
|
|
@@ -1688,7 +1714,7 @@ function VideoSlotInner({
|
|
|
1688
1714
|
const isHlsSource = sourceType === "hls";
|
|
1689
1715
|
const hlsSrc = isHlsSource && shouldLoadSrc ? src : void 0;
|
|
1690
1716
|
const mp4Src = !isHlsSource && shouldLoadSrc ? src : void 0;
|
|
1691
|
-
const { isReady: hlsReady } = useHls({
|
|
1717
|
+
const { isReady: hlsReady, isNativeHls } = useHls({
|
|
1692
1718
|
src: hlsSrc,
|
|
1693
1719
|
videoRef,
|
|
1694
1720
|
isActive,
|
|
@@ -1727,7 +1753,9 @@ function VideoSlotInner({
|
|
|
1727
1753
|
}, [mp4Src, isActive, isPrefetch, isPreloaded, isHlsSource]);
|
|
1728
1754
|
const isReady = isHlsSource ? hlsReady : mp4Ready;
|
|
1729
1755
|
const [hasPlayedAhead, setHasPlayedAhead] = useState(false);
|
|
1756
|
+
const canPlayAhead = isHlsSource && !isNativeHls;
|
|
1730
1757
|
useEffect(() => {
|
|
1758
|
+
if (!canPlayAhead) return;
|
|
1731
1759
|
const video = videoRef.current;
|
|
1732
1760
|
if (!video) return;
|
|
1733
1761
|
if (isActive || !isReady) return;
|
|
@@ -1754,7 +1782,7 @@ function VideoSlotInner({
|
|
|
1754
1782
|
return () => {
|
|
1755
1783
|
cancelled = true;
|
|
1756
1784
|
};
|
|
1757
|
-
}, [isActive, isReady, hasPlayedAhead]);
|
|
1785
|
+
}, [canPlayAhead, isActive, isReady, hasPlayedAhead]);
|
|
1758
1786
|
useEffect(() => {
|
|
1759
1787
|
setHasPlayedAhead(false);
|
|
1760
1788
|
}, [src]);
|
|
@@ -1765,16 +1793,30 @@ function VideoSlotInner({
|
|
|
1765
1793
|
let onReady = null;
|
|
1766
1794
|
if (isActive) {
|
|
1767
1795
|
wasActiveRef.current = true;
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1796
|
+
const startPlay = () => {
|
|
1797
|
+
if (onReady) {
|
|
1798
|
+
video.removeEventListener("canplay", onReady);
|
|
1799
|
+
video.removeEventListener("loadeddata", onReady);
|
|
1800
|
+
video.removeEventListener("playing", onReady);
|
|
1801
|
+
onReady = null;
|
|
1802
|
+
}
|
|
1803
|
+
video.muted = true;
|
|
1804
|
+
video.play().then(() => {
|
|
1805
|
+
video.muted = isMuted;
|
|
1806
|
+
}).catch(() => {
|
|
1807
|
+
video.muted = isMuted;
|
|
1771
1808
|
});
|
|
1809
|
+
};
|
|
1810
|
+
if (video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
|
|
1811
|
+
startPlay();
|
|
1772
1812
|
} else {
|
|
1773
|
-
onReady =
|
|
1774
|
-
video.play().catch(() => {
|
|
1775
|
-
});
|
|
1776
|
-
};
|
|
1813
|
+
onReady = startPlay;
|
|
1777
1814
|
video.addEventListener("canplay", onReady, { once: true });
|
|
1815
|
+
video.addEventListener("loadeddata", onReady, { once: true });
|
|
1816
|
+
video.addEventListener("playing", onReady, { once: true });
|
|
1817
|
+
if (video.readyState === HTMLMediaElement.HAVE_NOTHING && isNativeHls && video.src) {
|
|
1818
|
+
video.load();
|
|
1819
|
+
}
|
|
1778
1820
|
}
|
|
1779
1821
|
} else if (wasActiveRef.current) {
|
|
1780
1822
|
video.pause();
|
|
@@ -1785,15 +1827,38 @@ function VideoSlotInner({
|
|
|
1785
1827
|
video.pause();
|
|
1786
1828
|
}
|
|
1787
1829
|
return () => {
|
|
1788
|
-
if (onReady)
|
|
1830
|
+
if (onReady) {
|
|
1831
|
+
video.removeEventListener("canplay", onReady);
|
|
1832
|
+
video.removeEventListener("loadeddata", onReady);
|
|
1833
|
+
video.removeEventListener("playing", onReady);
|
|
1834
|
+
}
|
|
1789
1835
|
};
|
|
1790
|
-
}, [isActive, isMuted, hasPlayedAhead]);
|
|
1836
|
+
}, [isActive, isMuted, hasPlayedAhead, isNativeHls]);
|
|
1791
1837
|
useEffect(() => {
|
|
1792
1838
|
const video = videoRef.current;
|
|
1793
1839
|
if (!video) return;
|
|
1794
1840
|
video.muted = isMuted;
|
|
1795
1841
|
}, [isMuted]);
|
|
1796
|
-
const
|
|
1842
|
+
const [isActuallyPlaying, setIsActuallyPlaying] = useState(false);
|
|
1843
|
+
useEffect(() => {
|
|
1844
|
+
const video = videoRef.current;
|
|
1845
|
+
if (!video) return;
|
|
1846
|
+
const onPlaying = () => setIsActuallyPlaying(true);
|
|
1847
|
+
const onPause = () => setIsActuallyPlaying(false);
|
|
1848
|
+
const onEnded = () => setIsActuallyPlaying(false);
|
|
1849
|
+
video.addEventListener("playing", onPlaying);
|
|
1850
|
+
video.addEventListener("pause", onPause);
|
|
1851
|
+
video.addEventListener("ended", onEnded);
|
|
1852
|
+
return () => {
|
|
1853
|
+
video.removeEventListener("playing", onPlaying);
|
|
1854
|
+
video.removeEventListener("pause", onPause);
|
|
1855
|
+
video.removeEventListener("ended", onEnded);
|
|
1856
|
+
};
|
|
1857
|
+
}, []);
|
|
1858
|
+
useEffect(() => {
|
|
1859
|
+
if (!isActive) setIsActuallyPlaying(false);
|
|
1860
|
+
}, [isActive]);
|
|
1861
|
+
const showPosterOverlay = isActive ? !isReady && !isActuallyPlaying : canPlayAhead ? !hasPlayedAhead : !isReady;
|
|
1797
1862
|
const [isPaused, setIsPaused] = useState(false);
|
|
1798
1863
|
const handleTap = useCallback(() => {
|
|
1799
1864
|
const video = videoRef.current;
|