@cloudflare/realtimekit-ui 1.0.4-staging.5 → 1.0.5-staging.1
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/browser.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/realtimekit-ui.cjs.js +1 -1
- package/dist/cjs/rtk-livestream-indicator_3.cjs.entry.js +101 -9
- package/dist/collection/components/rtk-livestream-player/rtk-livestream-player.css +66 -2
- package/dist/collection/components/rtk-livestream-player/rtk-livestream-player.js +104 -9
- package/dist/components/{p-734d61ed.js → p-1745c048.js} +105 -10
- package/dist/components/rtk-grid.js +1 -1
- package/dist/components/rtk-livestream-player.js +1 -1
- package/dist/docs/docs-components.json +1 -1
- package/dist/esm/loader.js +102 -10
- package/dist/esm/realtimekit-ui.js +1 -1
- package/dist/esm/rtk-livestream-indicator_3.entry.js +101 -9
- package/dist/realtimekit-ui/{p-65830fdd.entry.js → p-31af32f0.entry.js} +1 -1
- package/dist/realtimekit-ui/realtimekit-ui.esm.js +1 -1
- package/dist/types/components/rtk-livestream-player/rtk-livestream-player.d.ts +11 -0
- package/package.json +1 -1
|
@@ -35672,7 +35672,7 @@ function formatSecondsToHHMMSS(seconds) {
|
|
|
35672
35672
|
: `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
35673
35673
|
}
|
|
35674
35674
|
|
|
35675
|
-
const rtkLivestreamPlayerCss = ":host{line-height:initial;font-family:var(--rtk-font-family, sans-serif);font-feature-settings:normal;font-variation-settings:normal}p{margin:var(--rtk-space-0, 0px);padding:var(--rtk-space-0, 0px)}:host{display:flex;height:100%;max-height:100%;min-height:100%;width:100%;min-width:100%;max-width:100%;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity))}.player-container{position:relative;margin-left:var(--rtk-space-4, 16px);margin-right:var(--rtk-space-4, 16px);margin-top:var(--rtk-space-4, 16px);margin-bottom:var(--rtk-space-0, 0px);display:flex;flex-grow:1;align-items:center;justify-content:center;border-radius:var(--rtk-border-radius-md, 8px)}.loader{position:absolute;z-index:10;height:100%;width:100%;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));display:flex;flex-direction:column;align-items:center;justify-content:center}p{margin-top:var(--rtk-space-1, 4px);margin-bottom:var(--rtk-space-1, 4px);font-size:16px;color:rgb(var(--rtk-colors-text-700, 255 255 255 / 0.64))}.unmute-popup{position:absolute;z-index:30 !important;display:flex;width:var(--rtk-space-72, 288px);flex-direction:column;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-800, 30 30 30) / var(--tw-bg-opacity));padding:var(--rtk-space-4, 16px);text-align:center;max-width:70%}.unmute-popup h3{margin:var(--rtk-space-0, 0px);font-size:16px;font-weight:500}.unmute-popup p{margin-top:var(--rtk-space-3, 12px);margin-bottom:var(--rtk-space-3, 12px);font-size:14px}.control-bar{position:absolute;bottom:0;left:16px;right:16px;display:flex;height:auto;
|
|
35675
|
+
const rtkLivestreamPlayerCss = ":host{line-height:initial;font-family:var(--rtk-font-family, sans-serif);font-feature-settings:normal;font-variation-settings:normal}p{margin:var(--rtk-space-0, 0px);padding:var(--rtk-space-0, 0px)}:host{display:flex;height:100%;max-height:100%;min-height:100%;width:100%;min-width:100%;max-width:100%;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity))}.player-container{position:relative;margin-left:var(--rtk-space-4, 16px);margin-right:var(--rtk-space-4, 16px);margin-top:var(--rtk-space-4, 16px);margin-bottom:var(--rtk-space-0, 0px);display:flex;flex-grow:1;align-items:center;justify-content:center;border-radius:var(--rtk-border-radius-md, 8px)}.loader{position:absolute;z-index:10;height:100%;width:100%;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));display:flex;flex-direction:column;align-items:center;justify-content:center}p{margin-top:var(--rtk-space-1, 4px);margin-bottom:var(--rtk-space-1, 4px);font-size:16px;color:rgb(var(--rtk-colors-text-700, 255 255 255 / 0.64))}.unmute-popup{position:absolute;z-index:30 !important;display:flex;width:var(--rtk-space-72, 288px);flex-direction:column;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-800, 30 30 30) / var(--tw-bg-opacity));padding:var(--rtk-space-4, 16px);text-align:center;max-width:70%}.unmute-popup h3{margin:var(--rtk-space-0, 0px);font-size:16px;font-weight:500}.unmute-popup p{margin-top:var(--rtk-space-3, 12px);margin-bottom:var(--rtk-space-3, 12px);font-size:14px}.control-bar{position:absolute;bottom:0;left:16px;right:16px;display:flex;height:auto;align-items:center;padding:12px 16px;z-index:30;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));border-radius:6px;border-radius:var(--rtk-border-radius-md, 8px);background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / 0.8);gap:12px}.timings{color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)))}.control-btn{border:none;margin-right:var(--rtk-space-2, 8px);border-radius:var(--rtk-border-radius-sm, 4px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)));cursor:pointer;font-size:24px;height:30px;width:30px}.fullscreen-btn{margin-right:20px;height:30px}.control-btn:hover{opacity:0.8}.control-btn:focus{outline:none}.control-groups{display:flex;align-items:center;gap:12px;flex-shrink:0}#livestream-video,.livestream-video{position:absolute;top:0;left:0;width:100% !important;height:100% !important;max-width:none !important;max-height:none !important;min-width:100% !important;min-height:100% !important;-o-object-fit:fill !important;object-fit:fill !important;z-index:10;border-radius:var(--rtk-border-radius-md, 8px);border-width:0px}:host:not(:fullscreen) .video-container{padding:16px 16px 0 16px}:host(:fullscreen) .video-container,:host(:-webkit-full-screen) .video-container,:host(:-moz-full-screen) .video-container{padding:0}.level-select{border-radius:var(--rtk-border-radius-sm, 4px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)));border:none;padding:5px 10px;font-size:14px;height:30px;cursor:pointer;border-radius:5px;margin-right:10px}.level-select:focus{outline:none}.level-select option{border-radius:var(--rtk-border-radius-sm, 4px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)))}.volume-control-holder{display:flex;justify-content:center;align-items:center}.seekbar-container{flex:1;min-width:100px;padding:0 12px;display:flex;align-items:center}.seekbar{width:100%;height:20px;cursor:pointer;display:flex;align-items:center}.seekbar-track{position:relative;width:100%;height:4px;border-radius:9999px;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-600, 60 60 60) / var(--tw-bg-opacity))}.seekbar-progress{position:absolute;top:0;left:0;height:100%;border-radius:9999px;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));transition:width 0.1s ease}.seekbar-handle{position:absolute;top:50%;width:12px;height:12px;border-radius:9999px;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));transform:translate(-50%, -50%);transition:left 0.1s ease;opacity:0}.seekbar:hover .seekbar-handle{opacity:1}.seekbar:hover .seekbar-track{height:6px}.seekbar:hover .seekbar-handle{width:14px;height:14px}";
|
|
35676
35676
|
const RtkLivestreamPlayerStyle0 = rtkLivestreamPlayerCss;
|
|
35677
35677
|
|
|
35678
35678
|
var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
@@ -35704,21 +35704,42 @@ const RtkLivestreamPlayer = class {
|
|
|
35704
35704
|
this.currentTime = 0;
|
|
35705
35705
|
this.duration = 0;
|
|
35706
35706
|
this.hideControls = true;
|
|
35707
|
+
this.isDragging = false;
|
|
35708
|
+
this.seekPosition = 0;
|
|
35709
|
+
this.isSeeking = false;
|
|
35707
35710
|
this.hideControlsTimeout = null;
|
|
35711
|
+
this.seekingTimeout = null;
|
|
35708
35712
|
this.livestreamUpdateListener = (state) => {
|
|
35709
35713
|
this.playbackUrl = this.meeting.livestream.playbackUrl;
|
|
35710
35714
|
this.livestreamState = state;
|
|
35711
35715
|
};
|
|
35712
35716
|
this.updateProgress = () => {
|
|
35713
|
-
|
|
35717
|
+
// During seeking, avoid updating currentTime to prevent fluctuations
|
|
35718
|
+
if (!this.isSeeking) {
|
|
35719
|
+
this.currentTime = this.videoRef.currentTime;
|
|
35720
|
+
}
|
|
35714
35721
|
};
|
|
35715
35722
|
this.updateHlsStatsPeriodically = () => {
|
|
35716
|
-
var _a, _b;
|
|
35717
|
-
//
|
|
35718
|
-
|
|
35723
|
+
var _a, _b, _c;
|
|
35724
|
+
// Use HLS seekable ranges to get actual duration instead of currentTime + latency
|
|
35725
|
+
// This prevents duration from fluctuating when seeking
|
|
35726
|
+
if (((_a = this.videoRef) === null || _a === void 0 ? void 0 : _a.seekable) && this.videoRef.seekable.length > 0) {
|
|
35727
|
+
this.duration = this.videoRef.seekable.end(this.videoRef.seekable.length - 1);
|
|
35728
|
+
}
|
|
35729
|
+
else {
|
|
35730
|
+
// Fallback to currentTime + latency if seekable ranges aren't available
|
|
35731
|
+
this.duration = (((_b = this.videoRef) === null || _b === void 0 ? void 0 : _b.currentTime) || 0) + (((_c = this.hls) === null || _c === void 0 ? void 0 : _c.latency) || 0);
|
|
35732
|
+
}
|
|
35719
35733
|
};
|
|
35720
35734
|
this.fastForwardToLatest = () => {
|
|
35721
|
-
|
|
35735
|
+
var _a;
|
|
35736
|
+
// Use seekable range for more accurate live edge positioning
|
|
35737
|
+
if (((_a = this.videoRef) === null || _a === void 0 ? void 0 : _a.seekable) && this.videoRef.seekable.length > 0) {
|
|
35738
|
+
this.videoRef.currentTime = this.videoRef.seekable.end(this.videoRef.seekable.length - 1) - 1;
|
|
35739
|
+
}
|
|
35740
|
+
else {
|
|
35741
|
+
this.videoRef.currentTime = this.duration - 1; // Fallback
|
|
35742
|
+
}
|
|
35722
35743
|
};
|
|
35723
35744
|
this.togglePlay = () => {
|
|
35724
35745
|
if (this.videoRef.paused) {
|
|
@@ -35751,6 +35772,74 @@ const RtkLivestreamPlayer = class {
|
|
|
35751
35772
|
this.hideControls = true;
|
|
35752
35773
|
}, 5000);
|
|
35753
35774
|
};
|
|
35775
|
+
this.seekToPosition = (position) => {
|
|
35776
|
+
if (!this.videoRef)
|
|
35777
|
+
return;
|
|
35778
|
+
// Clamp position to valid range
|
|
35779
|
+
const clampedPosition = Math.max(0, Math.min(position, this.duration));
|
|
35780
|
+
// Set seeking state to prevent currentTime fluctuations
|
|
35781
|
+
this.isSeeking = true;
|
|
35782
|
+
// Update currentTime immediately for UI feedback
|
|
35783
|
+
this.currentTime = clampedPosition;
|
|
35784
|
+
try {
|
|
35785
|
+
this.videoRef.currentTime = clampedPosition;
|
|
35786
|
+
// Clear any existing timeout
|
|
35787
|
+
if (this.seekingTimeout) {
|
|
35788
|
+
clearTimeout(this.seekingTimeout);
|
|
35789
|
+
}
|
|
35790
|
+
// Reset seeking state after a short delay to allow video to stabilize
|
|
35791
|
+
this.seekingTimeout = setTimeout(() => {
|
|
35792
|
+
this.isSeeking = false;
|
|
35793
|
+
// Update currentTime one final time to ensure accuracy
|
|
35794
|
+
this.currentTime = this.videoRef.currentTime;
|
|
35795
|
+
}, 200);
|
|
35796
|
+
}
|
|
35797
|
+
catch (error) {
|
|
35798
|
+
this.isSeeking = false;
|
|
35799
|
+
this.meeting.__internals__.logger.warn('rtk-livestream-player:: Seek failed', { error });
|
|
35800
|
+
}
|
|
35801
|
+
};
|
|
35802
|
+
this.onSeekbarMouseDown = (event) => {
|
|
35803
|
+
event.preventDefault();
|
|
35804
|
+
this.isDragging = true;
|
|
35805
|
+
this.updateSeekPosition(event);
|
|
35806
|
+
document.addEventListener('mousemove', this.onSeekbarMouseMove);
|
|
35807
|
+
document.addEventListener('mouseup', this.onSeekbarMouseUp);
|
|
35808
|
+
};
|
|
35809
|
+
this.onSeekbarMouseMove = (event) => {
|
|
35810
|
+
if (!this.isDragging)
|
|
35811
|
+
return;
|
|
35812
|
+
this.updateSeekPosition(event);
|
|
35813
|
+
};
|
|
35814
|
+
this.onSeekbarMouseUp = (event) => {
|
|
35815
|
+
if (!this.isDragging)
|
|
35816
|
+
return;
|
|
35817
|
+
this.isDragging = false;
|
|
35818
|
+
this.updateSeekPosition(event);
|
|
35819
|
+
this.seekToPosition(this.seekPosition);
|
|
35820
|
+
document.removeEventListener('mousemove', this.onSeekbarMouseMove);
|
|
35821
|
+
document.removeEventListener('mouseup', this.onSeekbarMouseUp);
|
|
35822
|
+
};
|
|
35823
|
+
this.onSeekbarClick = (event) => {
|
|
35824
|
+
if (this.isDragging)
|
|
35825
|
+
return;
|
|
35826
|
+
this.updateSeekPosition(event);
|
|
35827
|
+
this.seekToPosition(this.seekPosition);
|
|
35828
|
+
};
|
|
35829
|
+
this.updateSeekPosition = (event) => {
|
|
35830
|
+
const seekbar = event.currentTarget;
|
|
35831
|
+
const rect = seekbar.getBoundingClientRect();
|
|
35832
|
+
const clickX = event.clientX - rect.left;
|
|
35833
|
+
const progress = Math.max(0, Math.min(1, clickX / rect.width));
|
|
35834
|
+
// Map progress to duration
|
|
35835
|
+
this.seekPosition = progress * this.duration;
|
|
35836
|
+
};
|
|
35837
|
+
this.getSeekbarProgress = () => {
|
|
35838
|
+
if (this.isDragging) {
|
|
35839
|
+
return this.duration > 0 ? this.seekPosition / this.duration : 0;
|
|
35840
|
+
}
|
|
35841
|
+
return this.duration > 0 ? this.currentTime / this.duration : 0;
|
|
35842
|
+
};
|
|
35754
35843
|
this.getLoadingState = () => {
|
|
35755
35844
|
let loadingMessage = '';
|
|
35756
35845
|
let isLoading = false;
|
|
@@ -35820,7 +35909,7 @@ const RtkLivestreamPlayer = class {
|
|
|
35820
35909
|
});
|
|
35821
35910
|
window.rtk_hls = this.hls;
|
|
35822
35911
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Loading source`);
|
|
35823
|
-
this.hls.loadSource(this.playbackUrl);
|
|
35912
|
+
this.hls.loadSource(this.playbackUrl + '?dvrEnabled=true');
|
|
35824
35913
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Attaching video element to HLS`);
|
|
35825
35914
|
this.hls.attachMedia(this.videoRef);
|
|
35826
35915
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Waiting async for HLS manifest parsing`);
|
|
@@ -35838,7 +35927,7 @@ const RtkLivestreamPlayer = class {
|
|
|
35838
35927
|
setTimeout(() => {
|
|
35839
35928
|
if (this.playbackUrl && this.livestreamState === 'LIVESTREAMING') {
|
|
35840
35929
|
this.meeting.__internals__.logger.info('rtk-livestream-player:: Retrying playbackUrl');
|
|
35841
|
-
this.hls.loadSource(this.playbackUrl);
|
|
35930
|
+
this.hls.loadSource(this.playbackUrl + '?dvrEnabled=true');
|
|
35842
35931
|
}
|
|
35843
35932
|
}, 5000);
|
|
35844
35933
|
return;
|
|
@@ -35931,6 +36020,9 @@ const RtkLivestreamPlayer = class {
|
|
|
35931
36020
|
this.meeting.livestream.removeListener('livestreamUpdate', this.livestreamUpdateListener);
|
|
35932
36021
|
this.videoRef.removeEventListener('timeupdate', this.updateProgress);
|
|
35933
36022
|
clearInterval(this.statsIntervalTimer);
|
|
36023
|
+
if (this.seekingTimeout) {
|
|
36024
|
+
clearTimeout(this.seekingTimeout);
|
|
36025
|
+
}
|
|
35934
36026
|
this.videoRef = null;
|
|
35935
36027
|
if (this.hls) {
|
|
35936
36028
|
this.hls.destroy();
|
|
@@ -35962,7 +36054,7 @@ const RtkLivestreamPlayer = class {
|
|
|
35962
36054
|
// <!-- Control Bar -->
|
|
35963
36055
|
index$1.h("div", { class: "control-bar" }, index$1.h("div", { class: "control-groups" }, index$1.h("rtk-icon", { id: "playPause", onClick: this.togglePlay, size: "lg", class: "control-btn", icon: this.playerState === uiStore.PlayerState.PLAYING
|
|
35964
36056
|
? this.iconPack.pause
|
|
35965
|
-
: this.iconPack.play }), index$1.h("rtk-icon", { size: "lg", class: "control-btn", icon: this.iconPack.fastForward, onClick: this.fastForwardToLatest }), index$1.h("span", { class: "timings" }, formatSecondsToHHMMSS(this.currentTime), " /", ' ', formatSecondsToHHMMSS(this.duration))), index$1.h("div", { class: "control-groups" }, index$1.h("select", { class: "level-select", onChange: (e) => this.changeQuality(parseInt(e.target.value)) }, this.qualityLevels.map((level) => (index$1.h("option", { value: level.level, selected: this.selectedQuality === level.level }, level.resolution)))), index$1.h("rtk-fullscreen-toggle", { id: "fullscreen", class: "control-btn fullscreen-btn", targetElement: this.videoContainerRef, size: "sm", iconPack: this.iconPack, t: this.t, ref: (fullScreenToggle) => {
|
|
36057
|
+
: this.iconPack.play }), index$1.h("rtk-icon", { size: "lg", class: "control-btn", icon: this.iconPack.fastForward, onClick: this.fastForwardToLatest }), index$1.h("span", { class: "timings" }, formatSecondsToHHMMSS(this.currentTime), " /", ' ', formatSecondsToHHMMSS(this.duration))), index$1.h("div", { class: "seekbar-container" }, index$1.h("div", { class: "seekbar", onMouseDown: this.onSeekbarMouseDown, onClick: this.onSeekbarClick }, index$1.h("div", { class: "seekbar-track" }, index$1.h("div", { class: "seekbar-progress", style: { width: `${this.getSeekbarProgress() * 100}%` } }), index$1.h("div", { class: "seekbar-handle", style: { left: `${this.getSeekbarProgress() * 100}%` } })))), index$1.h("div", { class: "control-groups" }, index$1.h("select", { class: "level-select", onChange: (e) => this.changeQuality(parseInt(e.target.value)) }, this.qualityLevels.map((level) => (index$1.h("option", { value: level.level, selected: this.selectedQuality === level.level }, level.resolution)))), index$1.h("rtk-fullscreen-toggle", { id: "fullscreen", class: "control-btn fullscreen-btn", targetElement: this.videoContainerRef, size: "sm", iconPack: this.iconPack, t: this.t, ref: (fullScreenToggle) => {
|
|
35966
36058
|
var _a;
|
|
35967
36059
|
// Create a <style> element
|
|
35968
36060
|
const style = document.createElement('style');
|
|
@@ -94,11 +94,11 @@ p {
|
|
|
94
94
|
right: 16px;
|
|
95
95
|
display: flex;
|
|
96
96
|
height: auto;
|
|
97
|
-
justify-content: space-between;
|
|
98
97
|
align-items: center;
|
|
99
98
|
padding: 12px 16px;
|
|
100
99
|
z-index: 30; /* Higher z-index to ensure it's above the video */ --tw-bg-opacity: 1; background-color: rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));
|
|
101
100
|
border-radius: 6px; /* rounded-md fallback */ border-radius: var(--rtk-border-radius-md, 8px); background-color: rgba(var(--rtk-colors-background-900, 26 26 26) / 0.8);
|
|
101
|
+
gap: 12px;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
.timings {
|
|
@@ -135,7 +135,8 @@ p {
|
|
|
135
135
|
.control-groups{
|
|
136
136
|
display: flex;
|
|
137
137
|
align-items: center;
|
|
138
|
-
|
|
138
|
+
gap: 12px;
|
|
139
|
+
flex-shrink: 0;
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
#livestream-video,
|
|
@@ -198,4 +199,67 @@ p {
|
|
|
198
199
|
display: flex;
|
|
199
200
|
justify-content: center;
|
|
200
201
|
align-items: center;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Seekbar Styles */
|
|
205
|
+
.seekbar-container {
|
|
206
|
+
flex: 1;
|
|
207
|
+
min-width: 100px;
|
|
208
|
+
padding: 0 12px;
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.seekbar {
|
|
214
|
+
width: 100%;
|
|
215
|
+
height: 20px;
|
|
216
|
+
cursor: pointer;
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.seekbar-track {
|
|
222
|
+
position: relative;
|
|
223
|
+
width: 100%;
|
|
224
|
+
height: 4px;
|
|
225
|
+
border-radius: 9999px;
|
|
226
|
+
--tw-bg-opacity: 1;
|
|
227
|
+
background-color: rgba(var(--rtk-colors-background-600, 60 60 60) / var(--tw-bg-opacity));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.seekbar-progress {
|
|
231
|
+
position: absolute;
|
|
232
|
+
top: 0;
|
|
233
|
+
left: 0;
|
|
234
|
+
height: 100%;
|
|
235
|
+
border-radius: 9999px;
|
|
236
|
+
--tw-bg-opacity: 1;
|
|
237
|
+
background-color: rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));
|
|
238
|
+
transition: width 0.1s ease;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.seekbar-handle {
|
|
242
|
+
position: absolute;
|
|
243
|
+
top: 50%;
|
|
244
|
+
width: 12px;
|
|
245
|
+
height: 12px;
|
|
246
|
+
border-radius: 9999px;
|
|
247
|
+
--tw-bg-opacity: 1;
|
|
248
|
+
background-color: rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));
|
|
249
|
+
transform: translate(-50%, -50%);
|
|
250
|
+
transition: left 0.1s ease;
|
|
251
|
+
opacity: 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.seekbar:hover .seekbar-handle {
|
|
255
|
+
opacity: 1;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.seekbar:hover .seekbar-track {
|
|
259
|
+
height: 6px;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.seekbar:hover .seekbar-handle {
|
|
263
|
+
width: 14px;
|
|
264
|
+
height: 14px;
|
|
201
265
|
}
|
|
@@ -32,21 +32,42 @@ export class RtkLivestreamPlayer {
|
|
|
32
32
|
this.currentTime = 0;
|
|
33
33
|
this.duration = 0;
|
|
34
34
|
this.hideControls = true;
|
|
35
|
+
this.isDragging = false;
|
|
36
|
+
this.seekPosition = 0;
|
|
37
|
+
this.isSeeking = false;
|
|
35
38
|
this.hideControlsTimeout = null;
|
|
39
|
+
this.seekingTimeout = null;
|
|
36
40
|
this.livestreamUpdateListener = (state) => {
|
|
37
41
|
this.playbackUrl = this.meeting.livestream.playbackUrl;
|
|
38
42
|
this.livestreamState = state;
|
|
39
43
|
};
|
|
40
44
|
this.updateProgress = () => {
|
|
41
|
-
|
|
45
|
+
// During seeking, avoid updating currentTime to prevent fluctuations
|
|
46
|
+
if (!this.isSeeking) {
|
|
47
|
+
this.currentTime = this.videoRef.currentTime;
|
|
48
|
+
}
|
|
42
49
|
};
|
|
43
50
|
this.updateHlsStatsPeriodically = () => {
|
|
44
|
-
var _a, _b;
|
|
45
|
-
//
|
|
46
|
-
|
|
51
|
+
var _a, _b, _c;
|
|
52
|
+
// Use HLS seekable ranges to get actual duration instead of currentTime + latency
|
|
53
|
+
// This prevents duration from fluctuating when seeking
|
|
54
|
+
if (((_a = this.videoRef) === null || _a === void 0 ? void 0 : _a.seekable) && this.videoRef.seekable.length > 0) {
|
|
55
|
+
this.duration = this.videoRef.seekable.end(this.videoRef.seekable.length - 1);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Fallback to currentTime + latency if seekable ranges aren't available
|
|
59
|
+
this.duration = (((_b = this.videoRef) === null || _b === void 0 ? void 0 : _b.currentTime) || 0) + (((_c = this.hls) === null || _c === void 0 ? void 0 : _c.latency) || 0);
|
|
60
|
+
}
|
|
47
61
|
};
|
|
48
62
|
this.fastForwardToLatest = () => {
|
|
49
|
-
|
|
63
|
+
var _a;
|
|
64
|
+
// Use seekable range for more accurate live edge positioning
|
|
65
|
+
if (((_a = this.videoRef) === null || _a === void 0 ? void 0 : _a.seekable) && this.videoRef.seekable.length > 0) {
|
|
66
|
+
this.videoRef.currentTime = this.videoRef.seekable.end(this.videoRef.seekable.length - 1) - 1;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.videoRef.currentTime = this.duration - 1; // Fallback
|
|
70
|
+
}
|
|
50
71
|
};
|
|
51
72
|
this.togglePlay = () => {
|
|
52
73
|
if (this.videoRef.paused) {
|
|
@@ -79,6 +100,74 @@ export class RtkLivestreamPlayer {
|
|
|
79
100
|
this.hideControls = true;
|
|
80
101
|
}, 5000);
|
|
81
102
|
};
|
|
103
|
+
this.seekToPosition = (position) => {
|
|
104
|
+
if (!this.videoRef)
|
|
105
|
+
return;
|
|
106
|
+
// Clamp position to valid range
|
|
107
|
+
const clampedPosition = Math.max(0, Math.min(position, this.duration));
|
|
108
|
+
// Set seeking state to prevent currentTime fluctuations
|
|
109
|
+
this.isSeeking = true;
|
|
110
|
+
// Update currentTime immediately for UI feedback
|
|
111
|
+
this.currentTime = clampedPosition;
|
|
112
|
+
try {
|
|
113
|
+
this.videoRef.currentTime = clampedPosition;
|
|
114
|
+
// Clear any existing timeout
|
|
115
|
+
if (this.seekingTimeout) {
|
|
116
|
+
clearTimeout(this.seekingTimeout);
|
|
117
|
+
}
|
|
118
|
+
// Reset seeking state after a short delay to allow video to stabilize
|
|
119
|
+
this.seekingTimeout = setTimeout(() => {
|
|
120
|
+
this.isSeeking = false;
|
|
121
|
+
// Update currentTime one final time to ensure accuracy
|
|
122
|
+
this.currentTime = this.videoRef.currentTime;
|
|
123
|
+
}, 200);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
this.isSeeking = false;
|
|
127
|
+
this.meeting.__internals__.logger.warn('rtk-livestream-player:: Seek failed', { error });
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
this.onSeekbarMouseDown = (event) => {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
this.isDragging = true;
|
|
133
|
+
this.updateSeekPosition(event);
|
|
134
|
+
document.addEventListener('mousemove', this.onSeekbarMouseMove);
|
|
135
|
+
document.addEventListener('mouseup', this.onSeekbarMouseUp);
|
|
136
|
+
};
|
|
137
|
+
this.onSeekbarMouseMove = (event) => {
|
|
138
|
+
if (!this.isDragging)
|
|
139
|
+
return;
|
|
140
|
+
this.updateSeekPosition(event);
|
|
141
|
+
};
|
|
142
|
+
this.onSeekbarMouseUp = (event) => {
|
|
143
|
+
if (!this.isDragging)
|
|
144
|
+
return;
|
|
145
|
+
this.isDragging = false;
|
|
146
|
+
this.updateSeekPosition(event);
|
|
147
|
+
this.seekToPosition(this.seekPosition);
|
|
148
|
+
document.removeEventListener('mousemove', this.onSeekbarMouseMove);
|
|
149
|
+
document.removeEventListener('mouseup', this.onSeekbarMouseUp);
|
|
150
|
+
};
|
|
151
|
+
this.onSeekbarClick = (event) => {
|
|
152
|
+
if (this.isDragging)
|
|
153
|
+
return;
|
|
154
|
+
this.updateSeekPosition(event);
|
|
155
|
+
this.seekToPosition(this.seekPosition);
|
|
156
|
+
};
|
|
157
|
+
this.updateSeekPosition = (event) => {
|
|
158
|
+
const seekbar = event.currentTarget;
|
|
159
|
+
const rect = seekbar.getBoundingClientRect();
|
|
160
|
+
const clickX = event.clientX - rect.left;
|
|
161
|
+
const progress = Math.max(0, Math.min(1, clickX / rect.width));
|
|
162
|
+
// Map progress to duration
|
|
163
|
+
this.seekPosition = progress * this.duration;
|
|
164
|
+
};
|
|
165
|
+
this.getSeekbarProgress = () => {
|
|
166
|
+
if (this.isDragging) {
|
|
167
|
+
return this.duration > 0 ? this.seekPosition / this.duration : 0;
|
|
168
|
+
}
|
|
169
|
+
return this.duration > 0 ? this.currentTime / this.duration : 0;
|
|
170
|
+
};
|
|
82
171
|
this.getLoadingState = () => {
|
|
83
172
|
let loadingMessage = '';
|
|
84
173
|
let isLoading = false;
|
|
@@ -148,7 +237,7 @@ export class RtkLivestreamPlayer {
|
|
|
148
237
|
});
|
|
149
238
|
window.rtk_hls = this.hls;
|
|
150
239
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Loading source`);
|
|
151
|
-
this.hls.loadSource(this.playbackUrl);
|
|
240
|
+
this.hls.loadSource(this.playbackUrl + '?dvrEnabled=true');
|
|
152
241
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Attaching video element to HLS`);
|
|
153
242
|
this.hls.attachMedia(this.videoRef);
|
|
154
243
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Waiting async for HLS manifest parsing`);
|
|
@@ -166,7 +255,7 @@ export class RtkLivestreamPlayer {
|
|
|
166
255
|
setTimeout(() => {
|
|
167
256
|
if (this.playbackUrl && this.livestreamState === 'LIVESTREAMING') {
|
|
168
257
|
this.meeting.__internals__.logger.info('rtk-livestream-player:: Retrying playbackUrl');
|
|
169
|
-
this.hls.loadSource(this.playbackUrl);
|
|
258
|
+
this.hls.loadSource(this.playbackUrl + '?dvrEnabled=true');
|
|
170
259
|
}
|
|
171
260
|
}, 5000);
|
|
172
261
|
return;
|
|
@@ -259,6 +348,9 @@ export class RtkLivestreamPlayer {
|
|
|
259
348
|
this.meeting.livestream.removeListener('livestreamUpdate', this.livestreamUpdateListener);
|
|
260
349
|
this.videoRef.removeEventListener('timeupdate', this.updateProgress);
|
|
261
350
|
clearInterval(this.statsIntervalTimer);
|
|
351
|
+
if (this.seekingTimeout) {
|
|
352
|
+
clearTimeout(this.seekingTimeout);
|
|
353
|
+
}
|
|
262
354
|
this.videoRef = null;
|
|
263
355
|
if (this.hls) {
|
|
264
356
|
this.hls.destroy();
|
|
@@ -290,7 +382,7 @@ export class RtkLivestreamPlayer {
|
|
|
290
382
|
// <!-- Control Bar -->
|
|
291
383
|
h("div", { class: "control-bar" }, h("div", { class: "control-groups" }, h("rtk-icon", { id: "playPause", onClick: this.togglePlay, size: "lg", class: "control-btn", icon: this.playerState === PlayerState.PLAYING
|
|
292
384
|
? this.iconPack.pause
|
|
293
|
-
: this.iconPack.play }), h("rtk-icon", { size: "lg", class: "control-btn", icon: this.iconPack.fastForward, onClick: this.fastForwardToLatest }), h("span", { class: "timings" }, formatSecondsToHHMMSS(this.currentTime), " /", ' ', formatSecondsToHHMMSS(this.duration))), h("div", { class: "control-groups" }, h("select", { class: "level-select", onChange: (e) => this.changeQuality(parseInt(e.target.value)) }, this.qualityLevels.map((level) => (h("option", { value: level.level, selected: this.selectedQuality === level.level }, level.resolution)))), h("rtk-fullscreen-toggle", { id: "fullscreen", class: "control-btn fullscreen-btn", targetElement: this.videoContainerRef, size: "sm", iconPack: this.iconPack, t: this.t, ref: (fullScreenToggle) => {
|
|
385
|
+
: this.iconPack.play }), h("rtk-icon", { size: "lg", class: "control-btn", icon: this.iconPack.fastForward, onClick: this.fastForwardToLatest }), h("span", { class: "timings" }, formatSecondsToHHMMSS(this.currentTime), " /", ' ', formatSecondsToHHMMSS(this.duration))), h("div", { class: "seekbar-container" }, h("div", { class: "seekbar", onMouseDown: this.onSeekbarMouseDown, onClick: this.onSeekbarClick }, h("div", { class: "seekbar-track" }, h("div", { class: "seekbar-progress", style: { width: `${this.getSeekbarProgress() * 100}%` } }), h("div", { class: "seekbar-handle", style: { left: `${this.getSeekbarProgress() * 100}%` } })))), h("div", { class: "control-groups" }, h("select", { class: "level-select", onChange: (e) => this.changeQuality(parseInt(e.target.value)) }, this.qualityLevels.map((level) => (h("option", { value: level.level, selected: this.selectedQuality === level.level }, level.resolution)))), h("rtk-fullscreen-toggle", { id: "fullscreen", class: "control-btn fullscreen-btn", targetElement: this.videoContainerRef, size: "sm", iconPack: this.iconPack, t: this.t, ref: (fullScreenToggle) => {
|
|
294
386
|
var _a;
|
|
295
387
|
// Create a <style> element
|
|
296
388
|
const style = document.createElement('style');
|
|
@@ -438,7 +530,10 @@ export class RtkLivestreamPlayer {
|
|
|
438
530
|
"selectedQuality": {},
|
|
439
531
|
"currentTime": {},
|
|
440
532
|
"duration": {},
|
|
441
|
-
"hideControls": {}
|
|
533
|
+
"hideControls": {},
|
|
534
|
+
"isDragging": {},
|
|
535
|
+
"seekPosition": {},
|
|
536
|
+
"isSeeking": {}
|
|
442
537
|
};
|
|
443
538
|
}
|
|
444
539
|
static get events() {
|
|
@@ -35616,7 +35616,7 @@ function formatSecondsToHHMMSS(seconds) {
|
|
|
35616
35616
|
: `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
35617
35617
|
}
|
|
35618
35618
|
|
|
35619
|
-
const rtkLivestreamPlayerCss = ":host{line-height:initial;font-family:var(--rtk-font-family, sans-serif);font-feature-settings:normal;font-variation-settings:normal}p{margin:var(--rtk-space-0, 0px);padding:var(--rtk-space-0, 0px)}:host{display:flex;height:100%;max-height:100%;min-height:100%;width:100%;min-width:100%;max-width:100%;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity))}.player-container{position:relative;margin-left:var(--rtk-space-4, 16px);margin-right:var(--rtk-space-4, 16px);margin-top:var(--rtk-space-4, 16px);margin-bottom:var(--rtk-space-0, 0px);display:flex;flex-grow:1;align-items:center;justify-content:center;border-radius:var(--rtk-border-radius-md, 8px)}.loader{position:absolute;z-index:10;height:100%;width:100%;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));display:flex;flex-direction:column;align-items:center;justify-content:center}p{margin-top:var(--rtk-space-1, 4px);margin-bottom:var(--rtk-space-1, 4px);font-size:16px;color:rgb(var(--rtk-colors-text-700, 255 255 255 / 0.64))}.unmute-popup{position:absolute;z-index:30 !important;display:flex;width:var(--rtk-space-72, 288px);flex-direction:column;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-800, 30 30 30) / var(--tw-bg-opacity));padding:var(--rtk-space-4, 16px);text-align:center;max-width:70%}.unmute-popup h3{margin:var(--rtk-space-0, 0px);font-size:16px;font-weight:500}.unmute-popup p{margin-top:var(--rtk-space-3, 12px);margin-bottom:var(--rtk-space-3, 12px);font-size:14px}.control-bar{position:absolute;bottom:0;left:16px;right:16px;display:flex;height:auto;
|
|
35619
|
+
const rtkLivestreamPlayerCss = ":host{line-height:initial;font-family:var(--rtk-font-family, sans-serif);font-feature-settings:normal;font-variation-settings:normal}p{margin:var(--rtk-space-0, 0px);padding:var(--rtk-space-0, 0px)}:host{display:flex;height:100%;max-height:100%;min-height:100%;width:100%;min-width:100%;max-width:100%;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity))}.player-container{position:relative;margin-left:var(--rtk-space-4, 16px);margin-right:var(--rtk-space-4, 16px);margin-top:var(--rtk-space-4, 16px);margin-bottom:var(--rtk-space-0, 0px);display:flex;flex-grow:1;align-items:center;justify-content:center;border-radius:var(--rtk-border-radius-md, 8px)}.loader{position:absolute;z-index:10;height:100%;width:100%;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));display:flex;flex-direction:column;align-items:center;justify-content:center}p{margin-top:var(--rtk-space-1, 4px);margin-bottom:var(--rtk-space-1, 4px);font-size:16px;color:rgb(var(--rtk-colors-text-700, 255 255 255 / 0.64))}.unmute-popup{position:absolute;z-index:30 !important;display:flex;width:var(--rtk-space-72, 288px);flex-direction:column;border-radius:var(--rtk-border-radius-md, 8px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-800, 30 30 30) / var(--tw-bg-opacity));padding:var(--rtk-space-4, 16px);text-align:center;max-width:70%}.unmute-popup h3{margin:var(--rtk-space-0, 0px);font-size:16px;font-weight:500}.unmute-popup p{margin-top:var(--rtk-space-3, 12px);margin-bottom:var(--rtk-space-3, 12px);font-size:14px}.control-bar{position:absolute;bottom:0;left:16px;right:16px;display:flex;height:auto;align-items:center;padding:12px 16px;z-index:30;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / var(--tw-bg-opacity));border-radius:6px;border-radius:var(--rtk-border-radius-md, 8px);background-color:rgba(var(--rtk-colors-background-900, 26 26 26) / 0.8);gap:12px}.timings{color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)))}.control-btn{border:none;margin-right:var(--rtk-space-2, 8px);border-radius:var(--rtk-border-radius-sm, 4px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)));cursor:pointer;font-size:24px;height:30px;width:30px}.fullscreen-btn{margin-right:20px;height:30px}.control-btn:hover{opacity:0.8}.control-btn:focus{outline:none}.control-groups{display:flex;align-items:center;gap:12px;flex-shrink:0}#livestream-video,.livestream-video{position:absolute;top:0;left:0;width:100% !important;height:100% !important;max-width:none !important;max-height:none !important;min-width:100% !important;min-height:100% !important;-o-object-fit:fill !important;object-fit:fill !important;z-index:10;border-radius:var(--rtk-border-radius-md, 8px);border-width:0px}:host:not(:fullscreen) .video-container{padding:16px 16px 0 16px}:host(:fullscreen) .video-container,:host(:-webkit-full-screen) .video-container,:host(:-moz-full-screen) .video-container{padding:0}.level-select{border-radius:var(--rtk-border-radius-sm, 4px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)));border:none;padding:5px 10px;font-size:14px;height:30px;cursor:pointer;border-radius:5px;margin-right:10px}.level-select:focus{outline:none}.level-select option{border-radius:var(--rtk-border-radius-sm, 4px);--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));color:rgb(var(--rtk-colors-text-on-brand-1000, var(--rtk-colors-text-1000, 255 255 255)))}.volume-control-holder{display:flex;justify-content:center;align-items:center}.seekbar-container{flex:1;min-width:100px;padding:0 12px;display:flex;align-items:center}.seekbar{width:100%;height:20px;cursor:pointer;display:flex;align-items:center}.seekbar-track{position:relative;width:100%;height:4px;border-radius:9999px;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-background-600, 60 60 60) / var(--tw-bg-opacity))}.seekbar-progress{position:absolute;top:0;left:0;height:100%;border-radius:9999px;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));transition:width 0.1s ease}.seekbar-handle{position:absolute;top:50%;width:12px;height:12px;border-radius:9999px;--tw-bg-opacity:1;background-color:rgba(var(--rtk-colors-brand-500, 33 96 253) / var(--tw-bg-opacity));transform:translate(-50%, -50%);transition:left 0.1s ease;opacity:0}.seekbar:hover .seekbar-handle{opacity:1}.seekbar:hover .seekbar-track{height:6px}.seekbar:hover .seekbar-handle{width:14px;height:14px}";
|
|
35620
35620
|
const RtkLivestreamPlayerStyle0 = rtkLivestreamPlayerCss;
|
|
35621
35621
|
|
|
35622
35622
|
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
@@ -35650,21 +35650,42 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35650
35650
|
this.currentTime = 0;
|
|
35651
35651
|
this.duration = 0;
|
|
35652
35652
|
this.hideControls = true;
|
|
35653
|
+
this.isDragging = false;
|
|
35654
|
+
this.seekPosition = 0;
|
|
35655
|
+
this.isSeeking = false;
|
|
35653
35656
|
this.hideControlsTimeout = null;
|
|
35657
|
+
this.seekingTimeout = null;
|
|
35654
35658
|
this.livestreamUpdateListener = (state) => {
|
|
35655
35659
|
this.playbackUrl = this.meeting.livestream.playbackUrl;
|
|
35656
35660
|
this.livestreamState = state;
|
|
35657
35661
|
};
|
|
35658
35662
|
this.updateProgress = () => {
|
|
35659
|
-
|
|
35663
|
+
// During seeking, avoid updating currentTime to prevent fluctuations
|
|
35664
|
+
if (!this.isSeeking) {
|
|
35665
|
+
this.currentTime = this.videoRef.currentTime;
|
|
35666
|
+
}
|
|
35660
35667
|
};
|
|
35661
35668
|
this.updateHlsStatsPeriodically = () => {
|
|
35662
|
-
var _a, _b;
|
|
35663
|
-
//
|
|
35664
|
-
|
|
35669
|
+
var _a, _b, _c;
|
|
35670
|
+
// Use HLS seekable ranges to get actual duration instead of currentTime + latency
|
|
35671
|
+
// This prevents duration from fluctuating when seeking
|
|
35672
|
+
if (((_a = this.videoRef) === null || _a === void 0 ? void 0 : _a.seekable) && this.videoRef.seekable.length > 0) {
|
|
35673
|
+
this.duration = this.videoRef.seekable.end(this.videoRef.seekable.length - 1);
|
|
35674
|
+
}
|
|
35675
|
+
else {
|
|
35676
|
+
// Fallback to currentTime + latency if seekable ranges aren't available
|
|
35677
|
+
this.duration = (((_b = this.videoRef) === null || _b === void 0 ? void 0 : _b.currentTime) || 0) + (((_c = this.hls) === null || _c === void 0 ? void 0 : _c.latency) || 0);
|
|
35678
|
+
}
|
|
35665
35679
|
};
|
|
35666
35680
|
this.fastForwardToLatest = () => {
|
|
35667
|
-
|
|
35681
|
+
var _a;
|
|
35682
|
+
// Use seekable range for more accurate live edge positioning
|
|
35683
|
+
if (((_a = this.videoRef) === null || _a === void 0 ? void 0 : _a.seekable) && this.videoRef.seekable.length > 0) {
|
|
35684
|
+
this.videoRef.currentTime = this.videoRef.seekable.end(this.videoRef.seekable.length - 1) - 1;
|
|
35685
|
+
}
|
|
35686
|
+
else {
|
|
35687
|
+
this.videoRef.currentTime = this.duration - 1; // Fallback
|
|
35688
|
+
}
|
|
35668
35689
|
};
|
|
35669
35690
|
this.togglePlay = () => {
|
|
35670
35691
|
if (this.videoRef.paused) {
|
|
@@ -35697,6 +35718,74 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35697
35718
|
this.hideControls = true;
|
|
35698
35719
|
}, 5000);
|
|
35699
35720
|
};
|
|
35721
|
+
this.seekToPosition = (position) => {
|
|
35722
|
+
if (!this.videoRef)
|
|
35723
|
+
return;
|
|
35724
|
+
// Clamp position to valid range
|
|
35725
|
+
const clampedPosition = Math.max(0, Math.min(position, this.duration));
|
|
35726
|
+
// Set seeking state to prevent currentTime fluctuations
|
|
35727
|
+
this.isSeeking = true;
|
|
35728
|
+
// Update currentTime immediately for UI feedback
|
|
35729
|
+
this.currentTime = clampedPosition;
|
|
35730
|
+
try {
|
|
35731
|
+
this.videoRef.currentTime = clampedPosition;
|
|
35732
|
+
// Clear any existing timeout
|
|
35733
|
+
if (this.seekingTimeout) {
|
|
35734
|
+
clearTimeout(this.seekingTimeout);
|
|
35735
|
+
}
|
|
35736
|
+
// Reset seeking state after a short delay to allow video to stabilize
|
|
35737
|
+
this.seekingTimeout = setTimeout(() => {
|
|
35738
|
+
this.isSeeking = false;
|
|
35739
|
+
// Update currentTime one final time to ensure accuracy
|
|
35740
|
+
this.currentTime = this.videoRef.currentTime;
|
|
35741
|
+
}, 200);
|
|
35742
|
+
}
|
|
35743
|
+
catch (error) {
|
|
35744
|
+
this.isSeeking = false;
|
|
35745
|
+
this.meeting.__internals__.logger.warn('rtk-livestream-player:: Seek failed', { error });
|
|
35746
|
+
}
|
|
35747
|
+
};
|
|
35748
|
+
this.onSeekbarMouseDown = (event) => {
|
|
35749
|
+
event.preventDefault();
|
|
35750
|
+
this.isDragging = true;
|
|
35751
|
+
this.updateSeekPosition(event);
|
|
35752
|
+
document.addEventListener('mousemove', this.onSeekbarMouseMove);
|
|
35753
|
+
document.addEventListener('mouseup', this.onSeekbarMouseUp);
|
|
35754
|
+
};
|
|
35755
|
+
this.onSeekbarMouseMove = (event) => {
|
|
35756
|
+
if (!this.isDragging)
|
|
35757
|
+
return;
|
|
35758
|
+
this.updateSeekPosition(event);
|
|
35759
|
+
};
|
|
35760
|
+
this.onSeekbarMouseUp = (event) => {
|
|
35761
|
+
if (!this.isDragging)
|
|
35762
|
+
return;
|
|
35763
|
+
this.isDragging = false;
|
|
35764
|
+
this.updateSeekPosition(event);
|
|
35765
|
+
this.seekToPosition(this.seekPosition);
|
|
35766
|
+
document.removeEventListener('mousemove', this.onSeekbarMouseMove);
|
|
35767
|
+
document.removeEventListener('mouseup', this.onSeekbarMouseUp);
|
|
35768
|
+
};
|
|
35769
|
+
this.onSeekbarClick = (event) => {
|
|
35770
|
+
if (this.isDragging)
|
|
35771
|
+
return;
|
|
35772
|
+
this.updateSeekPosition(event);
|
|
35773
|
+
this.seekToPosition(this.seekPosition);
|
|
35774
|
+
};
|
|
35775
|
+
this.updateSeekPosition = (event) => {
|
|
35776
|
+
const seekbar = event.currentTarget;
|
|
35777
|
+
const rect = seekbar.getBoundingClientRect();
|
|
35778
|
+
const clickX = event.clientX - rect.left;
|
|
35779
|
+
const progress = Math.max(0, Math.min(1, clickX / rect.width));
|
|
35780
|
+
// Map progress to duration
|
|
35781
|
+
this.seekPosition = progress * this.duration;
|
|
35782
|
+
};
|
|
35783
|
+
this.getSeekbarProgress = () => {
|
|
35784
|
+
if (this.isDragging) {
|
|
35785
|
+
return this.duration > 0 ? this.seekPosition / this.duration : 0;
|
|
35786
|
+
}
|
|
35787
|
+
return this.duration > 0 ? this.currentTime / this.duration : 0;
|
|
35788
|
+
};
|
|
35700
35789
|
this.getLoadingState = () => {
|
|
35701
35790
|
let loadingMessage = '';
|
|
35702
35791
|
let isLoading = false;
|
|
@@ -35766,7 +35855,7 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35766
35855
|
});
|
|
35767
35856
|
window.rtk_hls = this.hls;
|
|
35768
35857
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Loading source`);
|
|
35769
|
-
this.hls.loadSource(this.playbackUrl);
|
|
35858
|
+
this.hls.loadSource(this.playbackUrl + '?dvrEnabled=true');
|
|
35770
35859
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Attaching video element to HLS`);
|
|
35771
35860
|
this.hls.attachMedia(this.videoRef);
|
|
35772
35861
|
this.meeting.__internals__.logger.info(`rtk-livestream-player:: Waiting async for HLS manifest parsing`);
|
|
@@ -35784,7 +35873,7 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35784
35873
|
setTimeout(() => {
|
|
35785
35874
|
if (this.playbackUrl && this.livestreamState === 'LIVESTREAMING') {
|
|
35786
35875
|
this.meeting.__internals__.logger.info('rtk-livestream-player:: Retrying playbackUrl');
|
|
35787
|
-
this.hls.loadSource(this.playbackUrl);
|
|
35876
|
+
this.hls.loadSource(this.playbackUrl + '?dvrEnabled=true');
|
|
35788
35877
|
}
|
|
35789
35878
|
}, 5000);
|
|
35790
35879
|
return;
|
|
@@ -35877,6 +35966,9 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35877
35966
|
this.meeting.livestream.removeListener('livestreamUpdate', this.livestreamUpdateListener);
|
|
35878
35967
|
this.videoRef.removeEventListener('timeupdate', this.updateProgress);
|
|
35879
35968
|
clearInterval(this.statsIntervalTimer);
|
|
35969
|
+
if (this.seekingTimeout) {
|
|
35970
|
+
clearTimeout(this.seekingTimeout);
|
|
35971
|
+
}
|
|
35880
35972
|
this.videoRef = null;
|
|
35881
35973
|
if (this.hls) {
|
|
35882
35974
|
this.hls.destroy();
|
|
@@ -35908,7 +36000,7 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35908
36000
|
// <!-- Control Bar -->
|
|
35909
36001
|
h("div", { class: "control-bar" }, h("div", { class: "control-groups" }, h("rtk-icon", { id: "playPause", onClick: this.togglePlay, size: "lg", class: "control-btn", icon: this.playerState === PlayerState.PLAYING
|
|
35910
36002
|
? this.iconPack.pause
|
|
35911
|
-
: this.iconPack.play }), h("rtk-icon", { size: "lg", class: "control-btn", icon: this.iconPack.fastForward, onClick: this.fastForwardToLatest }), h("span", { class: "timings" }, formatSecondsToHHMMSS(this.currentTime), " /", ' ', formatSecondsToHHMMSS(this.duration))), h("div", { class: "control-groups" }, h("select", { class: "level-select", onChange: (e) => this.changeQuality(parseInt(e.target.value)) }, this.qualityLevels.map((level) => (h("option", { value: level.level, selected: this.selectedQuality === level.level }, level.resolution)))), h("rtk-fullscreen-toggle", { id: "fullscreen", class: "control-btn fullscreen-btn", targetElement: this.videoContainerRef, size: "sm", iconPack: this.iconPack, t: this.t, ref: (fullScreenToggle) => {
|
|
36003
|
+
: this.iconPack.play }), h("rtk-icon", { size: "lg", class: "control-btn", icon: this.iconPack.fastForward, onClick: this.fastForwardToLatest }), h("span", { class: "timings" }, formatSecondsToHHMMSS(this.currentTime), " /", ' ', formatSecondsToHHMMSS(this.duration))), h("div", { class: "seekbar-container" }, h("div", { class: "seekbar", onMouseDown: this.onSeekbarMouseDown, onClick: this.onSeekbarClick }, h("div", { class: "seekbar-track" }, h("div", { class: "seekbar-progress", style: { width: `${this.getSeekbarProgress() * 100}%` } }), h("div", { class: "seekbar-handle", style: { left: `${this.getSeekbarProgress() * 100}%` } })))), h("div", { class: "control-groups" }, h("select", { class: "level-select", onChange: (e) => this.changeQuality(parseInt(e.target.value)) }, this.qualityLevels.map((level) => (h("option", { value: level.level, selected: this.selectedQuality === level.level }, level.resolution)))), h("rtk-fullscreen-toggle", { id: "fullscreen", class: "control-btn fullscreen-btn", targetElement: this.videoContainerRef, size: "sm", iconPack: this.iconPack, t: this.t, ref: (fullScreenToggle) => {
|
|
35912
36004
|
var _a;
|
|
35913
36005
|
// Create a <style> element
|
|
35914
36006
|
const style = document.createElement('style');
|
|
@@ -35953,7 +36045,10 @@ const RtkLivestreamPlayer = /*@__PURE__*/ proxyCustomElement(class RtkLivestream
|
|
|
35953
36045
|
"selectedQuality": [32],
|
|
35954
36046
|
"currentTime": [32],
|
|
35955
36047
|
"duration": [32],
|
|
35956
|
-
"hideControls": [32]
|
|
36048
|
+
"hideControls": [32],
|
|
36049
|
+
"isDragging": [32],
|
|
36050
|
+
"seekPosition": [32],
|
|
36051
|
+
"isSeeking": [32]
|
|
35957
36052
|
}, undefined, {
|
|
35958
36053
|
"livestreamState": ["updateLivestreamId"],
|
|
35959
36054
|
"meeting": ["meetingChanged"]
|