|
1 | 1 | import { Button } from "@nextui-org/react"; |
| 2 | +import { Events } from "@superstreamer/player"; |
2 | 3 | import cn from "clsx"; |
3 | | -import { useRef } from "react"; |
| 4 | +import { useEffect, useRef, useState } from "react"; |
4 | 5 | import { Selection } from "./Selection"; |
5 | | -import { usePlayerSelector } from "../context/PlayerContext"; |
| 6 | +import { usePlayer, usePlayerSelector } from "../context/PlayerContext"; |
6 | 7 | import { useSeekbar } from "../hooks/useSeekbar"; |
7 | 8 | import type { ReactNode, RefObject } from "react"; |
8 | 9 |
|
@@ -35,22 +36,45 @@ function PlayButton() { |
35 | 36 | } |
36 | 37 |
|
37 | 38 | function Seekbar() { |
| 39 | + const { player } = usePlayer(); |
38 | 40 | const seekableStart = usePlayerSelector((player) => player.seekableStart); |
39 | 41 | const time = usePlayerSelector((player) => player.time); |
40 | 42 | const duration = usePlayerSelector((player) => player.duration); |
41 | 43 | const seekTo = usePlayerSelector((player) => player.seekTo); |
42 | 44 |
|
| 45 | + const [lastSeekTime, setLastSeekTime] = useState<number | null>(null); |
| 46 | + |
43 | 47 | const seekbar = useSeekbar({ |
44 | 48 | min: seekableStart, |
45 | 49 | max: duration, |
46 | | - onSeeked: seekTo, |
| 50 | + onSeeked: (time) => { |
| 51 | + if (seekTo(time)) { |
| 52 | + setLastSeekTime(time); |
| 53 | + } |
| 54 | + }, |
47 | 55 | }); |
48 | 56 |
|
49 | | - let percentage = Number.isNaN(duration) |
50 | | - ? 0 |
51 | | - : (time - seekableStart) / (duration - seekableStart); |
52 | | - if (percentage < 0) { |
53 | | - percentage = 0; |
| 57 | + useEffect(() => { |
| 58 | + if (!player) { |
| 59 | + return; |
| 60 | + } |
| 61 | + |
| 62 | + const onSeekingChange = () => { |
| 63 | + if (!player.seeking) { |
| 64 | + setLastSeekTime(null); |
| 65 | + } |
| 66 | + }; |
| 67 | + |
| 68 | + player.on(Events.SEEKING_CHANGE, onSeekingChange); |
| 69 | + return () => { |
| 70 | + player.off(Events.SEEKING_CHANGE, onSeekingChange); |
| 71 | + }; |
| 72 | + }, [player]); |
| 73 | + |
| 74 | + const fakeTime = lastSeekTime ?? time; |
| 75 | + let percentage = getPercentage(fakeTime, duration, seekableStart); |
| 76 | + if (seekbar.seeking) { |
| 77 | + percentage = seekbar.x; |
54 | 78 | } |
55 | 79 |
|
56 | 80 | return ( |
@@ -209,3 +233,22 @@ function hms(seconds: number) { |
209 | 233 | "00:00:00" |
210 | 234 | ); |
211 | 235 | } |
| 236 | + |
| 237 | +function getPercentage(time: number, duration: number, seekableStart: number) { |
| 238 | + if (Number.isNaN(duration)) { |
| 239 | + return 0; |
| 240 | + } |
| 241 | + |
| 242 | + let timeRel = time - seekableStart; |
| 243 | + const durationRel = duration - seekableStart; |
| 244 | + |
| 245 | + if (timeRel < 0) { |
| 246 | + timeRel = 0; |
| 247 | + } else if (timeRel > durationRel) { |
| 248 | + timeRel = durationRel; |
| 249 | + } |
| 250 | + |
| 251 | + const percentage = timeRel / durationRel; |
| 252 | + |
| 253 | + return percentage; |
| 254 | +} |
0 commit comments