feat(player): add distinct buffered progress bar and adjust skip segment color
This commit is contained in:
@@ -75,6 +75,7 @@ const initPlayer = (): void => {
|
|||||||
const durationDisplay = container.querySelector('[data-duration]') as HTMLElement
|
const durationDisplay = container.querySelector('[data-duration]') as HTMLElement
|
||||||
const progressWrap = container.querySelector('[data-progress-wrap]') as HTMLElement
|
const progressWrap = container.querySelector('[data-progress-wrap]') as HTMLElement
|
||||||
const progress = container.querySelector('[data-progress]') as HTMLElement
|
const progress = container.querySelector('[data-progress]') as HTMLElement
|
||||||
|
const buffered = container.querySelector('[data-buffered]') as HTMLElement
|
||||||
const scrubber = container.querySelector('[data-scrubber]') as HTMLElement
|
const scrubber = container.querySelector('[data-scrubber]') as HTMLElement
|
||||||
const segmentsTrack = container.querySelector('[data-segments]') as HTMLElement
|
const segmentsTrack = container.querySelector('[data-segments]') as HTMLElement
|
||||||
const subtitleSelect = container.querySelector('[data-subtitle-select]') as HTMLSelectElement
|
const subtitleSelect = container.querySelector('[data-subtitle-select]') as HTMLSelectElement
|
||||||
@@ -316,7 +317,7 @@ const initPlayer = (): void => {
|
|||||||
const left = (segment.start / bounds.duration) * 100
|
const left = (segment.start / bounds.duration) * 100
|
||||||
const width = ((segment.end - segment.start) / bounds.duration) * 100
|
const width = ((segment.end - segment.start) / bounds.duration) * 100
|
||||||
const bar = document.createElement('div')
|
const bar = document.createElement('div')
|
||||||
bar.className = 'absolute top-0 h-full bg-yellow-400'
|
bar.className = 'absolute top-0 h-full bg-white/70'
|
||||||
bar.style.left = `${left}%`
|
bar.style.left = `${left}%`
|
||||||
bar.style.width = `${width}%`
|
bar.style.width = `${width}%`
|
||||||
segmentsTrack.appendChild(bar)
|
segmentsTrack.appendChild(bar)
|
||||||
@@ -347,6 +348,7 @@ const initPlayer = (): void => {
|
|||||||
const bounds = timelineBounds()
|
const bounds = timelineBounds()
|
||||||
if (bounds.duration <= 0) {
|
if (bounds.duration <= 0) {
|
||||||
progress.style.width = '0%'
|
progress.style.width = '0%'
|
||||||
|
if (buffered) buffered.style.width = '0%'
|
||||||
if (scrubber) scrubber.style.left = '0%'
|
if (scrubber) scrubber.style.left = '0%'
|
||||||
timeDisplay.textContent = '00:00'
|
timeDisplay.textContent = '00:00'
|
||||||
if (durationDisplay) durationDisplay.textContent = '00:00'
|
if (durationDisplay) durationDisplay.textContent = '00:00'
|
||||||
@@ -359,6 +361,18 @@ const initPlayer = (): void => {
|
|||||||
if (scrubber) scrubber.style.left = `${pct}%`
|
if (scrubber) scrubber.style.left = `${pct}%`
|
||||||
timeDisplay.textContent = formatTime(currentDisplayTime)
|
timeDisplay.textContent = formatTime(currentDisplayTime)
|
||||||
if (durationDisplay) durationDisplay.textContent = formatTime(bounds.duration)
|
if (durationDisplay) durationDisplay.textContent = formatTime(bounds.duration)
|
||||||
|
|
||||||
|
if (buffered && video) {
|
||||||
|
let maxBuffered = 0
|
||||||
|
for (let i = 0; i < video.buffered.length; i++) {
|
||||||
|
if (video.buffered.start(i) <= currentTime + 1) { // Adding small tolerance
|
||||||
|
maxBuffered = Math.max(maxBuffered, video.buffered.end(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bufferedDisplayTime = displayTimeFromAbsolute(maxBuffered)
|
||||||
|
const bufferedPct = Math.max(0, Math.min(100, (bufferedDisplayTime / bounds.duration) * 100))
|
||||||
|
buffered.style.width = `${bufferedPct}%`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const seekBy = (delta: number): void => {
|
const seekBy = (delta: number): void => {
|
||||||
@@ -772,6 +786,10 @@ const initPlayer = (): void => {
|
|||||||
if (loading) loading.style.display = 'none'
|
if (loading) loading.style.display = 'none'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
video.addEventListener('progress', () => {
|
||||||
|
updateTimeline(video.currentTime)
|
||||||
|
})
|
||||||
|
|
||||||
video.addEventListener('timeupdate', () => {
|
video.addEventListener('timeupdate', () => {
|
||||||
updateTimeline(video.currentTime)
|
updateTimeline(video.currentTime)
|
||||||
updateSubtitleRender(displayTimeFromAbsolute(video.currentTime))
|
updateSubtitleRender(displayTimeFromAbsolute(video.currentTime))
|
||||||
|
|||||||
@@ -87,7 +87,8 @@
|
|||||||
<div data-preview-popover class="pointer-events-none absolute bottom-full mb-2 -translate-x-1/2 bg-white px-2 py-1 text-xs font-bold text-black shadow-md opacity-0 transition-opacity duration-200">
|
<div data-preview-popover class="pointer-events-none absolute bottom-full mb-2 -translate-x-1/2 bg-white px-2 py-1 text-xs font-bold text-black shadow-md opacity-0 transition-opacity duration-200">
|
||||||
<span data-preview-time>0:00</span>
|
<span data-preview-time>0:00</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative flex h-1.5 w-full items-center rounded-full bg-white/30 transition-all group-hover/progress:h-2">
|
<div class="relative flex h-1.5 w-full items-center rounded-full bg-white/20 transition-all group-hover/progress:h-2">
|
||||||
|
<div data-buffered class="absolute left-0 top-0 h-full rounded-full bg-white/30 z-0" style="width: 0%"></div>
|
||||||
<div data-progress class="bg-accent relative z-10 h-full rounded-full" style="width: 0%"></div>
|
<div data-progress class="bg-accent relative z-10 h-full rounded-full" style="width: 0%"></div>
|
||||||
<div data-segments class="absolute inset-0 z-20 pointer-events-none overflow-hidden rounded-full"></div>
|
<div data-segments class="absolute inset-0 z-20 pointer-events-none overflow-hidden rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user