Compare commits
3 Commits
7a7e99337f
...
main
| Author | SHA1 | Date |
|---|---|---|
|
|
370e056a2b | |
|
|
55e5136e88 | |
|
|
2586e60f0c |
|
|
@ -0,0 +1,23 @@
|
|||
# watchtogether
|
||||
|
||||
This was a project that I created over 7 days of working while having covid :)
|
||||
|
||||
I probably won't do much with the codebase, but enjoy how I basically figured out how to sync video streams with multiple clients
|
||||
|
||||
## The Stack
|
||||
|
||||
- frontend
|
||||
|
||||
- next js
|
||||
- websockets
|
||||
- chakra-ui
|
||||
- react-player
|
||||
|
||||
- backend
|
||||
|
||||
- go
|
||||
- gorilla/websockets
|
||||
|
||||
## how 2 deploy?
|
||||
|
||||
you don't
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
<component name="ChangeListManager">
|
||||
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Player.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
# backend
|
||||
|
|
@ -1,39 +1 @@
|
|||
# Example app with [chakra-ui](https://github.com/chakra-ui/chakra-ui) and TypeScript
|
||||
|
||||
This example features how to use [chakra-ui](https://github.com/chakra-ui/chakra-ui) as the component library within a Next.js app with TypeScript.
|
||||
|
||||
Next.js and chakra-ui have built-in TypeScript declarations, so we'll get autocompletion for their modules straight away.
|
||||
|
||||
We are connecting the Next.js `_app.js` with `chakra-ui`'s Provider and theme so the pages can have app-wide dark/light mode. We are also creating some components which shows the usage of `chakra-ui`'s style props.
|
||||
|
||||
## Preview
|
||||
|
||||
Preview the example live on [StackBlitz](http://stackblitz.com/):
|
||||
|
||||
[](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-chakra-ui-typescript)
|
||||
|
||||
## Deploy your own
|
||||
|
||||
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
|
||||
|
||||
[](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-chakra-ui-typescript&project-name=with-chakra-ui-typescript&repository-name=with-chakra-ui-typescript)
|
||||
|
||||
## How to use
|
||||
|
||||
### Using `create-next-app`
|
||||
|
||||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example with-chakra-ui-typescript with-chakra-ui-typescript-app
|
||||
# or
|
||||
yarn create next-app --example with-chakra-ui-typescript with-chakra-ui-typescript-app
|
||||
```
|
||||
|
||||
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
|
||||
|
||||
## Notes
|
||||
|
||||
Chakra has supported Gradients and RTL in `v1.1`. To utilize RTL, [add RTL direction and swap](https://chakra-ui.com/docs/features/rtl-support).
|
||||
|
||||
If you don't have multi-direction app, you should make `<Html lang="ar" dir="rtl">` inside `_document.ts`.
|
||||
# frontend
|
||||
|
|
|
|||
|
|
@ -73,9 +73,7 @@ const Player = forwardRef<ReactPlayer, ReactPlayerProps>((props, ref) => {
|
|||
width="100%"
|
||||
height="100%"
|
||||
config={config}
|
||||
controls
|
||||
ref={ref}
|
||||
playing={false}
|
||||
{...props}
|
||||
/>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ const useWS = ({ user }: useWSProps): PlayerSocket | null => {
|
|||
// todo checkout usecallback
|
||||
const [socket, setSocket] = useState<PlayerSocket>(null);
|
||||
useEffect(() => {
|
||||
if (socket !== null) {
|
||||
return;
|
||||
}
|
||||
let internalSocket = new PlayerSocket(user);
|
||||
setSocket(internalSocket);
|
||||
return () => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import IUser from "./IUser";
|
|||
|
||||
interface IdentityData {
|
||||
admin?: boolean;
|
||||
controller?: boolean;
|
||||
hasController?: boolean;
|
||||
clientID?: string;
|
||||
playlist?: string;
|
||||
playhead?: number;
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import { Container } from "../components/Container";
|
|||
import Player from "../components/Player";
|
||||
import useWS from "../hooks/useWS";
|
||||
import IdentityData from "../interfaces/Identity";
|
||||
import { MessageTypes } from "../interfaces/IMessage";
|
||||
import SetPlayheadEvent from "../interfaces/Playhead";
|
||||
import SocketEvents from "../interfaces/SocketEvents";
|
||||
import { isBrowser } from "../util";
|
||||
import PlayerSocket from "../ws/websocket";
|
||||
import Message from "../util/Message";
|
||||
import MessageUtil from "../util/MessageUtil";
|
||||
|
||||
interface PlayerPageProps {
|
||||
user: User;
|
||||
|
|
@ -23,25 +25,74 @@ const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => {
|
|||
const playerRef = useRef<ReactPlayer>();
|
||||
const [id, setID] = useState<string>("");
|
||||
const [identity, setIdentity] = useState<IdentityData>();
|
||||
const [paused, setPaused] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (isBrowser() && typeof socket !== "undefined") {
|
||||
socket?.emitter.once(SocketEvents.Identify, (e: IdentityData) => {
|
||||
setID(e.playlist);
|
||||
setIdentity(e);
|
||||
playerRef?.current.seekTo(e.playhead);
|
||||
setPaused(e.paused);
|
||||
});
|
||||
socket?.emitter.on(SocketEvents.SetPlayhead, (e: SetPlayheadEvent) => {
|
||||
console.log(e);
|
||||
console.log(e.paused);
|
||||
setPaused(e.paused);
|
||||
playerRef.current.seekTo(e.playhead);
|
||||
});
|
||||
}
|
||||
}, [socket]);
|
||||
const onSeek = () => {};
|
||||
const onPlay = () => {
|
||||
if (!identity.admin) return;
|
||||
setPaused(false);
|
||||
socket?.send(
|
||||
MessageUtil.encode(
|
||||
new Message(MessageTypes.SetPlayhead, {
|
||||
playhead: playerRef.current.getCurrentTime(),
|
||||
paused: false,
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
const onSeek = (playedSeconds: number) => {
|
||||
if (!identity.admin) return;
|
||||
socket.send(
|
||||
MessageUtil.encode(
|
||||
new Message(MessageTypes.SetPlayhead, {
|
||||
playhead: playedSeconds,
|
||||
paused: paused,
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
const onPause = () => {
|
||||
console.log("running now");
|
||||
if (!identity.admin) return;
|
||||
setPaused(true);
|
||||
socket?.send(
|
||||
MessageUtil.encode(
|
||||
new Message(MessageTypes.SetPlayhead, {
|
||||
playhead: playerRef.current.getCurrentTime(),
|
||||
paused: true,
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Watch Together</title>
|
||||
</Head>
|
||||
<Container height="100vh" background={"#000"}>
|
||||
<Player ref={playerRef} />
|
||||
<Player
|
||||
url={id}
|
||||
onPlay={onPlay}
|
||||
onPause={onPause}
|
||||
onSeek={onSeek}
|
||||
controls={identity?.hasController}
|
||||
playing={!paused}
|
||||
ref={playerRef}
|
||||
/>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue