mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
disable playback speed in watchparty
This commit is contained in:
parent
2b9680313c
commit
e8e9352e88
5 changed files with 51 additions and 33 deletions
|
|
@ -483,7 +483,8 @@
|
|||
},
|
||||
"playback": {
|
||||
"speedLabel": "Playback speed",
|
||||
"title": "Playback settings"
|
||||
"title": "Playback settings",
|
||||
"disabled": "(Disabled in watch party)"
|
||||
},
|
||||
"quality": {
|
||||
"automaticLabel": "Automatic quality",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import classNames from "classnames";
|
||||
import { useCallback } from "react";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
|
|
@ -7,11 +7,13 @@ import { Menu } from "@/components/player/internals/ContextMenu";
|
|||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
import { useWatchPartyStore } from "@/stores/watchParty";
|
||||
|
||||
function ButtonList(props: {
|
||||
options: number[];
|
||||
selected: number;
|
||||
onClick: (v: any) => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-center bg-video-context-light/10 p-1 rounded-lg">
|
||||
|
|
@ -19,11 +21,13 @@ function ButtonList(props: {
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
disabled={props.disabled}
|
||||
className={classNames(
|
||||
"w-full px-2 py-1 rounded-md tabbable",
|
||||
props.selected === option
|
||||
? "bg-video-context-light/20 text-white"
|
||||
: null,
|
||||
props.disabled ? "opacity-50 cursor-not-allowed" : null,
|
||||
)}
|
||||
onClick={() => props.onClick(option)}
|
||||
key={option}
|
||||
|
|
@ -43,14 +47,23 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
|||
const display = usePlayerStore((s) => s.display);
|
||||
const enableThumbnails = usePreferencesStore((s) => s.enableThumbnails);
|
||||
const setEnableThumbnails = usePreferencesStore((s) => s.setEnableThumbnails);
|
||||
const isInWatchParty = useWatchPartyStore((s) => s.enabled);
|
||||
|
||||
const setPlaybackRate = useCallback(
|
||||
(v: number) => {
|
||||
if (isInWatchParty) return; // Don't allow changes in watch party
|
||||
display?.setPlaybackRate(v);
|
||||
},
|
||||
[display],
|
||||
[display, isInWatchParty],
|
||||
);
|
||||
|
||||
// Force 1x speed in watch party
|
||||
useEffect(() => {
|
||||
if (isInWatchParty && display && playbackRate !== 1) {
|
||||
display.setPlaybackRate(1);
|
||||
}
|
||||
}, [isInWatchParty, display, playbackRate]);
|
||||
|
||||
const options = [0.25, 0.5, 1, 1.5, 2];
|
||||
|
||||
return (
|
||||
|
|
@ -62,11 +75,17 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
|||
<div className="space-y-4 mt-3">
|
||||
<Menu.FieldTitle>
|
||||
{t("player.menus.playback.speedLabel")}
|
||||
{isInWatchParty && (
|
||||
<span className="text-sm text-type-secondary ml-2">
|
||||
{t("player.menus.playback.disabled")}
|
||||
</span>
|
||||
)}
|
||||
</Menu.FieldTitle>
|
||||
<ButtonList
|
||||
options={options}
|
||||
selected={playbackRate}
|
||||
selected={isInWatchParty ? 1 : playbackRate}
|
||||
onClick={setPlaybackRate}
|
||||
disabled={isInWatchParty}
|
||||
/>
|
||||
</div>
|
||||
</Menu.Section>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { useOverlayStack } from "@/stores/interface/overlayStack";
|
|||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { useSubtitleStore } from "@/stores/subtitles";
|
||||
import { useEmpheralVolumeStore } from "@/stores/volume";
|
||||
import { useWatchPartyStore } from "@/stores/watchParty";
|
||||
|
||||
export function KeyboardEvents() {
|
||||
const router = useOverlayRouter("");
|
||||
|
|
@ -16,6 +17,7 @@ export function KeyboardEvents() {
|
|||
const mediaPlaying = usePlayerStore((s) => s.mediaPlaying);
|
||||
const time = usePlayerStore((s) => s.progress.time);
|
||||
const { setVolume, toggleMute } = useVolume();
|
||||
const isInWatchParty = useWatchPartyStore((s) => s.enabled);
|
||||
|
||||
const { toggleLastUsed } = useCaptions();
|
||||
const setShowVolume = useEmpheralVolumeStore((s) => s.setShowVolume);
|
||||
|
|
@ -48,7 +50,9 @@ export function KeyboardEvents() {
|
|||
delay,
|
||||
setShowDelayIndicator,
|
||||
setCurrentOverlay,
|
||||
isInWatchParty,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
dataRef.current = {
|
||||
setShowVolume,
|
||||
|
|
@ -67,6 +71,7 @@ export function KeyboardEvents() {
|
|||
delay,
|
||||
setShowDelayIndicator,
|
||||
setCurrentOverlay,
|
||||
isInWatchParty,
|
||||
};
|
||||
}, [
|
||||
setShowVolume,
|
||||
|
|
@ -85,6 +90,7 @@ export function KeyboardEvents() {
|
|||
delay,
|
||||
setShowDelayIndicator,
|
||||
setCurrentOverlay,
|
||||
isInWatchParty,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -116,8 +122,8 @@ export function KeyboardEvents() {
|
|||
);
|
||||
if (keyL === "m") dataRef.current.toggleMute();
|
||||
|
||||
// Video playback speed
|
||||
if (k === ">" || k === "<") {
|
||||
// Video playback speed - disabled in watch party
|
||||
if ((k === ">" || k === "<") && !dataRef.current.isInWatchParty) {
|
||||
const options = [0.25, 0.5, 1, 1.5, 2];
|
||||
let idx = options.indexOf(dataRef.current.mediaPlaying?.playbackRate);
|
||||
if (idx === -1) idx = options.indexOf(1);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ interface RoomUser {
|
|||
isPaused: boolean;
|
||||
time: number;
|
||||
duration: number;
|
||||
playbackRate: number;
|
||||
};
|
||||
content: {
|
||||
title: string;
|
||||
|
|
@ -80,10 +79,6 @@ export function useWatchPartySync(
|
|||
const display = usePlayerStore((s) => s.display);
|
||||
const currentTime = usePlayerStore((s) => s.progress.time);
|
||||
const isPlaying = usePlayerStore((s) => s.mediaPlaying.isPlaying);
|
||||
const currentPlaybackRate = usePlayerStore(
|
||||
(s) => s.mediaPlaying.playbackRate,
|
||||
);
|
||||
|
||||
// Get watch party state
|
||||
const { roomCode, isHost, enabled, enableAsGuest } = useWatchPartyStore();
|
||||
|
||||
|
|
@ -169,10 +164,6 @@ export function useWatchPartySync(
|
|||
const predictedHostTime = getPredictedHostTime();
|
||||
const difference = currentTime - predictedHostTime;
|
||||
|
||||
// Handle playback rate sync
|
||||
const needsPlaybackRateSync =
|
||||
hostUser.player.playbackRate !== currentPlaybackRate;
|
||||
|
||||
// Handle time sync
|
||||
const activeThreshold = isPlaying ? 2 : 5;
|
||||
const needsTimeSync = Math.abs(difference) > activeThreshold;
|
||||
|
|
@ -188,21 +179,10 @@ export function useWatchPartySync(
|
|||
Math.abs(hostUser.player.time - state.previousHostTime) > 5;
|
||||
|
||||
// Sync if needed
|
||||
if (
|
||||
(needsTimeSync ||
|
||||
needsPlayStateSync ||
|
||||
needsJumpSync ||
|
||||
needsPlaybackRateSync) &&
|
||||
!isSyncing
|
||||
) {
|
||||
if ((needsTimeSync || needsPlayStateSync || needsJumpSync) && !isSyncing) {
|
||||
state.syncInProgress = true;
|
||||
setIsSyncing(true);
|
||||
|
||||
// Sync playback rate first if needed
|
||||
if (needsPlaybackRateSync) {
|
||||
display.setPlaybackRate(hostUser.player.playbackRate);
|
||||
}
|
||||
|
||||
// Sync time
|
||||
display.setTime(predictedHostTime);
|
||||
|
||||
|
|
@ -229,7 +209,6 @@ export function useWatchPartySync(
|
|||
hostUser,
|
||||
isHost,
|
||||
currentTime,
|
||||
currentPlaybackRate,
|
||||
display,
|
||||
isSyncing,
|
||||
getPredictedHostTime,
|
||||
|
|
@ -262,7 +241,6 @@ export function useWatchPartySync(
|
|||
isPaused: latestStatus.player.isPaused,
|
||||
time: latestStatus.player.time,
|
||||
duration: latestStatus.player.duration,
|
||||
playbackRate: latestStatus.player.playbackRate,
|
||||
},
|
||||
content: {
|
||||
title: latestStatus.content.title,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
|
||||
interface WatchPartyStore {
|
||||
// Whether the watch party feature is enabled
|
||||
enabled: boolean;
|
||||
|
|
@ -27,6 +29,14 @@ const generateRoomCode = (): string => {
|
|||
return Math.floor(1000 + Math.random() * 9000).toString();
|
||||
};
|
||||
|
||||
// Helper function to reset playback rate to 1x
|
||||
const resetPlaybackRate = () => {
|
||||
const display = usePlayerStore.getState().display;
|
||||
if (display) {
|
||||
display.setPlaybackRate(1);
|
||||
}
|
||||
};
|
||||
|
||||
export const useWatchPartyStore = create<WatchPartyStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
|
|
@ -35,19 +45,23 @@ export const useWatchPartyStore = create<WatchPartyStore>()(
|
|||
isHost: false,
|
||||
showStatusOverlay: false,
|
||||
|
||||
enableAsHost: () =>
|
||||
enableAsHost: () => {
|
||||
resetPlaybackRate();
|
||||
set(() => ({
|
||||
enabled: true,
|
||||
roomCode: generateRoomCode(),
|
||||
isHost: true,
|
||||
})),
|
||||
}));
|
||||
},
|
||||
|
||||
enableAsGuest: (code: string) =>
|
||||
enableAsGuest: (code: string) => {
|
||||
resetPlaybackRate();
|
||||
set(() => ({
|
||||
enabled: true,
|
||||
roomCode: code,
|
||||
isHost: false,
|
||||
})),
|
||||
}));
|
||||
},
|
||||
|
||||
updateRoomCode: (code: string) =>
|
||||
set((state) => ({
|
||||
|
|
|
|||
Loading…
Reference in a new issue