pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

watchparty goes to next episode with host

Pas 83840594 bf530902

+136 -17
+118
src/components/player/internals/Backend/WatchPartyReporter.tsx
··· 1 1 import { t } from "i18next"; 2 2 import { useEffect, useRef } from "react"; 3 + import { useNavigate } from "react-router-dom"; 3 4 4 5 import { getRoomStatuses, sendPlayerStatus } from "@/backend/player/status"; 5 6 import { usePlayerStatusPolling } from "@/components/player/hooks/usePlayerStatusPolling"; ··· 24 25 const lastReportTime = useRef<number>(0); 25 26 const lastReportedStateRef = useRef<string>(""); 26 27 const contentValidatedRef = useRef<boolean>(false); 28 + const hostEpisodeRef = useRef<{ seasonId?: number; episodeId?: number }>({}); 29 + const navigate = useNavigate(); 27 30 28 31 // Auth data 29 32 const account = useAuthStore((s) => s.account); ··· 45 48 useEffect(() => { 46 49 if (!watchPartyEnabled) { 47 50 contentValidatedRef.current = false; 51 + hostEpisodeRef.current = {}; 48 52 } 49 53 }, [watchPartyEnabled]); 50 54 ··· 93 97 ? parseInt(meta.episode.tmdbId, 10) 94 98 : undefined; 95 99 100 + // Initialize host episode tracking 101 + if (hostSeasonId && hostEpisodeId) { 102 + hostEpisodeRef.current = { 103 + seasonId: hostSeasonId, 104 + episodeId: hostEpisodeId, 105 + }; 106 + } 107 + 96 108 // Validate episode match (if host has this info) 97 109 if ( 98 110 (hostSeasonId && ··· 142 154 backendUrl, 143 155 account, 144 156 disable, 157 + ]); 158 + 159 + // Monitor for episode changes from host and auto-navigate guests 160 + useEffect(() => { 161 + if ( 162 + !watchPartyEnabled || 163 + !roomCode || 164 + isHost || 165 + !meta?.tmdbId || 166 + meta.type !== "show" 167 + ) { 168 + return; 169 + } 170 + 171 + const checkForEpisodeChange = async () => { 172 + try { 173 + const roomData = await getRoomStatuses(backendUrl, account, roomCode); 174 + const users = Object.values(roomData.users).flat(); 175 + const hostUser = users.find((user) => user.isHost); 176 + 177 + if (!hostUser || hostUser.content.type !== "TV Show") return; 178 + 179 + const hostSeasonId = hostUser.content.seasonId; 180 + const hostEpisodeId = hostUser.content.episodeId; 181 + 182 + // Initialize host episode ref on first check 183 + if ( 184 + !hostEpisodeRef.current.seasonId && 185 + !hostEpisodeRef.current.episodeId 186 + ) { 187 + hostEpisodeRef.current = { 188 + seasonId: hostSeasonId, 189 + episodeId: hostEpisodeId, 190 + }; 191 + return; 192 + } 193 + 194 + // Check if host has changed episodes 195 + const hasHostChangedEpisode = 196 + hostSeasonId !== hostEpisodeRef.current.seasonId || 197 + hostEpisodeId !== hostEpisodeRef.current.episodeId; 198 + 199 + if (hasHostChangedEpisode && hostSeasonId && hostEpisodeId) { 200 + // Update our reference 201 + hostEpisodeRef.current = { 202 + seasonId: hostSeasonId, 203 + episodeId: hostEpisodeId, 204 + }; 205 + 206 + // Check if we're already on the correct episode 207 + const currentSeasonId = meta.season?.tmdbId 208 + ? parseInt(meta.season.tmdbId, 10) 209 + : undefined; 210 + const currentEpisodeId = meta.episode?.tmdbId 211 + ? parseInt(meta.episode.tmdbId, 10) 212 + : undefined; 213 + 214 + if ( 215 + currentSeasonId === hostSeasonId && 216 + currentEpisodeId === hostEpisodeId 217 + ) { 218 + // Already on the correct episode 219 + return; 220 + } 221 + 222 + // Navigate to the new episode 223 + // eslint-disable-next-line no-console 224 + console.log("Host changed episode, following to new episode:", { 225 + seasonId: hostSeasonId, 226 + episodeId: hostEpisodeId, 227 + }); 228 + 229 + const url = new URL( 230 + `/media/tmdb-tv-${meta.tmdbId}/${hostSeasonId}/${hostEpisodeId}`, 231 + window.location.origin, 232 + ); 233 + url.searchParams.set("watchparty", roomCode); 234 + 235 + // Reset content validation so it re-validates on the new episode 236 + contentValidatedRef.current = false; 237 + 238 + navigate(url.pathname + url.search); 239 + } 240 + } catch (error) { 241 + console.error("Failed to check for episode change:", error); 242 + } 243 + }; 244 + 245 + // Check every 3 seconds for episode changes 246 + const interval = setInterval(checkForEpisodeChange, 3000); 247 + 248 + // Initial check 249 + checkForEpisodeChange(); 250 + 251 + return () => clearInterval(interval); 252 + }, [ 253 + watchPartyEnabled, 254 + roomCode, 255 + isHost, 256 + meta?.tmdbId, 257 + meta?.season?.tmdbId, 258 + meta?.episode?.tmdbId, 259 + meta?.type, 260 + backendUrl, 261 + account, 262 + navigate, 145 263 ]); 146 264 147 265 useEffect(() => {
+18 -17
src/components/player/internals/WatchPartyResetter.tsx
··· 11 11 const meta = usePlayerStore((s) => s.meta); 12 12 const { disable } = useWatchPartyStore(); 13 13 14 - // Store the current meta to track changes 15 - const previousMetaRef = useRef<string | null>(null); 14 + // Store the current base media to track changes 15 + const previousBaseMediaRef = useRef<string | null>(null); 16 16 17 - // Memoize the metaId calculation 18 - const metaId = useMemo(() => { 17 + // Memoize the base media ID (without episode details for shows) 18 + // This allows episode changes within the same show to keep the room active 19 + const baseMediaId = useMemo(() => { 19 20 if (!meta) return null; 20 21 21 - return meta.type === "show" 22 - ? `${meta.type}-${meta.tmdbId}-s${meta.season?.tmdbId || "0"}-e${meta.episode?.tmdbId || "0"}` 23 - : `${meta.type}-${meta.tmdbId}`; 22 + // For shows, only track the show ID, not the episode 23 + // This allows episode navigation within the same show 24 + return `${meta.type}-${meta.tmdbId}`; 24 25 }, [meta]); 25 26 26 27 useEffect(() => { 27 - // If meta exists but has changed, reset watch party 28 + // If base media has changed (different show/movie), reset watch party 28 29 if ( 29 - metaId && 30 - previousMetaRef.current && 31 - metaId !== previousMetaRef.current 30 + baseMediaId && 31 + previousBaseMediaRef.current && 32 + baseMediaId !== previousBaseMediaRef.current 32 33 ) { 33 34 // eslint-disable-next-line no-console 34 - console.log("Media changed, disabling watch party:", { 35 - previous: previousMetaRef.current, 36 - current: metaId, 35 + console.log("Base media changed, disabling watch party:", { 36 + previous: previousBaseMediaRef.current, 37 + current: baseMediaId, 37 38 }); 38 39 disable(); 39 40 } 40 41 41 - // Update the ref with current meta 42 - previousMetaRef.current = metaId; 42 + // Update the ref with current base media 43 + previousBaseMediaRef.current = baseMediaId; 43 44 44 45 // Also reset when component unmounts (player exited) 45 46 return () => { 46 47 disable(); 47 48 }; 48 - }, [metaId, disable]); 49 + }, [baseMediaId, disable]); 49 50 50 51 return null; // This component doesn't render anything 51 52 }