mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 12:06:38 +08:00
支持按用户保存播放器与弹幕偏好
在 user 记录上新增播放器音量、弹幕开关、透明度、字号、显示区域、合并偏好、自定义弹幕源以及 dandanplay 应用凭据字段,并提供 PUT /danmaku/settings 局部更新接口,带取值校验。 返回脱敏后的完整渲染配置,绝不回传应用密钥,仅在响应中标记密钥是否已配置。 结果缓存键加入用户 ID 与凭据指纹,避免不同用户或凭据串用缓存;旧版实例级设置仅作为未登录与迁移期的回退。
This commit is contained in:
@@ -58,6 +58,10 @@ function isEditableTarget(target: EventTarget | null): boolean {
|
||||
|
||||
type PlayerControlsProps = {
|
||||
videoRef: React.RefObject<HTMLVideoElement>
|
||||
/** 用户级播放器音量(0 ~ 1),由播放页从数据库读取。 */
|
||||
volume?: number
|
||||
onVolumeChange?: (volume: number) => void
|
||||
onVolumeCommit?: (volume: number) => void
|
||||
uiVisible: boolean
|
||||
onUiVisibleChange: (visible: boolean) => void
|
||||
subs: SubtitleTrack[]
|
||||
@@ -92,6 +96,9 @@ type PlayerControlsProps = {
|
||||
|
||||
export function PlayerControls({
|
||||
videoRef,
|
||||
volume: volumeProp = 1,
|
||||
onVolumeChange,
|
||||
onVolumeCommit,
|
||||
uiVisible,
|
||||
onUiVisibleChange,
|
||||
subs,
|
||||
@@ -128,8 +135,8 @@ export function PlayerControls({
|
||||
const [playing, setPlaying] = useState(false)
|
||||
const [currentTime, setCurrentTime] = useState(0)
|
||||
const [duration, setDuration] = useState(0)
|
||||
const [volume, setVolume] = useState(1)
|
||||
const [muted, setMuted] = useState(false)
|
||||
const [volume, setVolume] = useState(volumeProp)
|
||||
const [muted, setMuted] = useState(volumeProp === 0)
|
||||
const [fullscreen, setFullscreen] = useState(false)
|
||||
const [pip, setPip] = useState(false)
|
||||
const [controlsHovered, setControlsHovered] = useState(false)
|
||||
@@ -181,6 +188,17 @@ export function PlayerControls({
|
||||
setStageEl(container())
|
||||
}, [container])
|
||||
|
||||
// 音量由播放页按用户持久化;配置加载或切换对象后同步到当前 video。
|
||||
useEffect(() => {
|
||||
const el = video()
|
||||
if (!el) return
|
||||
const next = Math.min(1, Math.max(0, volumeProp))
|
||||
el.volume = next
|
||||
el.muted = next === 0
|
||||
setVolume(next)
|
||||
setMuted(next === 0)
|
||||
}, [video, volumeProp])
|
||||
|
||||
// 点击控制栏外部时关闭字幕菜单
|
||||
useEffect(() => {
|
||||
if (!subtitleMenuOpen) return
|
||||
@@ -336,19 +354,25 @@ export function PlayerControls({
|
||||
else el.pause()
|
||||
}
|
||||
|
||||
const applyAbsoluteSeek = (absolute: number) => {
|
||||
const el = video()
|
||||
if (!el) return
|
||||
if (onSeekAbsolute?.(absolute)) {
|
||||
pendingSeekRef.current = absolute
|
||||
setCurrentTime(absolute)
|
||||
return
|
||||
}
|
||||
const local = Math.max(0, absolute - streamOffset)
|
||||
el.currentTime = local
|
||||
setCurrentTime(streamOffset + local)
|
||||
}
|
||||
applySeekRef.current = applyAbsoluteSeek
|
||||
const applyAbsoluteSeek = useCallback(
|
||||
(absolute: number) => {
|
||||
const el = video()
|
||||
if (!el) return
|
||||
if (onSeekAbsolute?.(absolute)) {
|
||||
pendingSeekRef.current = absolute
|
||||
setCurrentTime(absolute)
|
||||
return
|
||||
}
|
||||
const local = Math.max(0, absolute - streamOffset)
|
||||
el.currentTime = local
|
||||
setCurrentTime(streamOffset + local)
|
||||
},
|
||||
[onSeekAbsolute, streamOffset, video],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
applySeekRef.current = applyAbsoluteSeek
|
||||
}, [applyAbsoluteSeek])
|
||||
|
||||
const handleSeekChange = (v: number) => {
|
||||
setScrubValue(v)
|
||||
@@ -474,10 +498,17 @@ export function PlayerControls({
|
||||
const changeVolume = (v: number) => {
|
||||
const el = video()
|
||||
if (!el) return
|
||||
el.volume = v
|
||||
el.muted = v === 0
|
||||
setVolume(v)
|
||||
setMuted(v === 0)
|
||||
const next = Math.min(1, Math.max(0, v))
|
||||
el.volume = next
|
||||
el.muted = next === 0
|
||||
setVolume(next)
|
||||
setMuted(next === 0)
|
||||
onVolumeChange?.(next)
|
||||
}
|
||||
|
||||
const commitVolume = () => {
|
||||
const el = video()
|
||||
onVolumeCommit?.(el?.volume ?? volume)
|
||||
}
|
||||
|
||||
const toggleMute = () => {
|
||||
@@ -803,6 +834,9 @@ export function PlayerControls({
|
||||
step={0.05}
|
||||
value={muted ? 0 : volume}
|
||||
onChange={(e) => changeVolume(Number(e.target.value))}
|
||||
onPointerUp={commitVolume}
|
||||
onKeyUp={commitVolume}
|
||||
onTouchEnd={commitVolume}
|
||||
className="hidden w-16 accent-rose-500 sm:block"
|
||||
aria-label="音量"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user