Skip to content

Commit

Permalink
feat: Add playback state management and user connection handling in sync
Browse files Browse the repository at this point in the history
  • Loading branch information
Ipmake committed Jan 23, 2025
1 parent 23e632a commit 2995195
Show file tree
Hide file tree
Showing 12 changed files with 664 additions and 49 deletions.
51 changes: 50 additions & 1 deletion backend/src/common/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ io?.on('connection', async (socket) => {
host: isHost
} satisfies PerPlexed.Sync.Ready);

io?.to(room).emit('EVNT_USER_JOIN', {
uid: user.uuid,
socket: socket.id,
name: user.friendlyName,
avatar: user.thumb
} satisfies PerPlexed.Sync.Member);

AddEvents(socket, isHost, room);

socket.on('disconnect', () => {
console.log(`SYNC [${socket.id}] disconnected`);

Expand All @@ -95,12 +104,52 @@ io?.on('connection', async (socket) => {
io?.sockets.sockets.get(client)?.disconnect();
});
}
} else {
io?.to(room).emit('EVNT_USER_LEAVE', {
uid: user.uuid,
socket: socket.id,
name: user.friendlyName,
avatar: user.thumb
} satisfies PerPlexed.Sync.Member);
}
});
})

function AddEvents(socket: Socket, isHost: boolean) {
function AddEvents(socket: Socket, isHost: boolean, room: string) {
const user = socket.data.user as PerPlexed.PlexTV.User;

socket.onAny((event, ...args) => {
if(!event.startsWith('SYNC_')) return;

console.log(`SYNC [${socket.id}] emitting HOST ${event} to ${room}`);
io?.to(room).emit(`HOST_${event}`, ...args);
});

socket.onAny((event, ...args) => {
if(!isHost) return;
if(!event.startsWith('RES_')) return;

console.log(`SYNC [${socket.id}] emitting ${event} to ${room}`);
io?.to(room).emit(`${event}`, {
uid: user.uuid,
socket: socket.id,
name: user.friendlyName,
avatar: user.thumb
} satisfies PerPlexed.Sync.Member, ...args);
});

socket.onAny((event, ...args) => {
if(!event.startsWith("EVNT_")) return;

console.log(`SYNC [${socket.id}] emitting EVENT ${event} to ${room}`);
io?.to(room).emit(`${event}`, {
uid: user.uuid,
socket: socket.id,
name: user.friendlyName,
avatar: user.thumb
} satisfies PerPlexed.Sync.Member, ...args);
})

}

function GenerateRoomID() {
Expand Down
15 changes: 14 additions & 1 deletion backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,27 @@ export namespace PerPlexed {

export namespace Sync {
export interface SocketError {
type: string;
type: string;
message: string;
}

export interface Ready {
room: string;
host: boolean;
}

export interface PlayBackState {
key?: string;
state: string;
time?: number;
}

export interface Member {
uid: string;
socket: string;
name: string;
avatar: string;
}
}

export namespace PlexTV {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useWatchListCache } from "./states/WatchListCache";
import Startup, { useStartupState } from "./pages/Startup";
import PerPlexedSync from "./components/PerPlexedSync";
import WaitingRoom from "./pages/WaitingRoom";
import ToastManager from "./components/ToastManager";

function AppManager() {
const { loading } = useStartupState();
Expand Down Expand Up @@ -64,6 +65,7 @@ function App() {
<>
<BigReader />
<PerPlexedSync />
<ToastManager />
<Routes>
<Route path="*" element={<AppBar />} />
<Route path="/watch/:itemID" element={<></>} />
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/common/NumberExtra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function absoluteDifference(num1: number, num2: number): number {
return Math.abs(num1 - num2);
}
51 changes: 35 additions & 16 deletions frontend/src/components/AppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { getAllLibraries, getSearch, getTranscodeImageURL } from "../plex";
import MetaScreen from "./MetaScreen";
import { useUserSessionStore } from "../states/UserSession";
import {
Favorite,
Fullscreen,
Logout,
People,
Expand All @@ -37,6 +38,7 @@ import {
} from "@mui/icons-material";
import { useSyncInterfaceState } from "./PerPlexedSync";
import { useSyncSessionState } from "../states/SyncSessionState";
import { config } from "..";

const BarSide: SxProps<Theme> = {
display: "flex",
Expand Down Expand Up @@ -109,8 +111,7 @@ function Appbar() {
vertical: "top",
horizontal: "center",
}}
sx={{
}}
sx={{}}
>
<Typography
sx={{
Expand All @@ -128,16 +129,30 @@ function Appbar() {

<MenuItem
onClick={() => {
useSyncInterfaceState.getState().setOpen(true);
setAnchorEl(null)
setAnchorEl(null);
window.open("https://github.com/sponsors/Ipmake", "_blank");
}}
>
<ListItemIcon>
<People fontSize="small" />
<Favorite fontSize="small" />
</ListItemIcon>
<ListItemText>Watch2Gether</ListItemText>
<ListItemText>Support</ListItemText>
</MenuItem>

{!config.DISABLE_PERPLEXED_SYNC && (
<MenuItem
onClick={() => {
useSyncInterfaceState.getState().setOpen(true);
setAnchorEl(null);
}}
>
<ListItemIcon>
<People fontSize="small" />
</ListItemIcon>
<ListItemText>Watch2Gether</ListItemText>
</MenuItem>
)}

<MenuItem
onClick={() => {
// toggle Fullscreen
Expand All @@ -153,7 +168,7 @@ function Appbar() {

<MenuItem
onClick={() => {
setAnchorEl(null)
setAnchorEl(null);
// navigate("/settings");
}}
disabled
Expand Down Expand Up @@ -389,37 +404,41 @@ function SearchBar() {
break;
case "ArrowDown":
e.preventDefault();
if(searchResults.length === 0) return;
if (searchResults.length === 0) return;
setSelectedIndex((prev) =>
prev === null ? 0 : Math.min(prev + 1, searchResults.length - 1)
);
break;
case "ArrowUp":
e.preventDefault();
if(searchResults.length === 0) return;
if(selectedIndex === 0) return setSelectedIndex(null);
if (searchResults.length === 0) return;
if (selectedIndex === 0) return setSelectedIndex(null);

setSelectedIndex((prev) =>
prev === null ? 0 : Math.max(prev - 1, 0)
);
break;
case "Tab":
e.preventDefault();
if(searchResults.length === 0) return;
if (searchResults.length === 0) return;
// if it gets to the last item, then set to null
if(selectedIndex === searchResults.length - 1) return setSelectedIndex(null);
if (selectedIndex === searchResults.length - 1)
return setSelectedIndex(null);
setSelectedIndex((prev) =>
prev === null ? 0 : Math.min(prev + 1, searchResults.length - 1)
);
break;
case "Enter":
if(searchValue.length === 0) return;
if (searchValue.length === 0) return;

if (selectedIndex !== null && searchResults.length > 0) {
if (searchResults[selectedIndex].Metadata?.ratingKey) {
setSearchParams(new URLSearchParams({
mid: searchResults[selectedIndex].Metadata?.ratingKey || '',
}));
setSearchParams(
new URLSearchParams({
mid:
searchResults[selectedIndex].Metadata?.ratingKey || "",
})
);
} else if (searchResults[selectedIndex].Directory) {
navigate(
`/library/${searchResults[selectedIndex].Directory?.librarySectionID}/dir/genre/${searchResults[selectedIndex].Directory?.id}`
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/PerPlexedSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ function PerPlexedSync() {
setPage("load");
const res = await useSyncSessionState
.getState()
.connect(inputRoom);
.connect(inputRoom, navigate);

console.log(res);

Expand Down Expand Up @@ -292,7 +292,7 @@ function PerPlexedSync() {
color="primary"
onClick={async () => {
setPage("load");
const res = await useSyncSessionState.getState().connect();
const res = await useSyncSessionState.getState().connect(undefined, navigate);
if (res !== true) {
setError(res.message);
setPage("home");
Expand Down
Loading

0 comments on commit 2995195

Please sign in to comment.