feat(ws): barebones SetPlayhead event
This commit is contained in:
parent
5f81ed1756
commit
728f2d67d0
|
|
@ -5,14 +5,17 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
|
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/../.vscode/settings.json" beforeDir="false" afterPath="$PROJECT_DIR$/../.vscode/settings.json" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/cmd/watchtogether/build.sh" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/../frontend/src/interfaces/SocketEvents.ts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/cmd/watchtogether/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/watchtogether/main.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/internal/ws/handlers.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/handlers.go" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/internal/ws/handlers.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/handlers.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/package.json" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/internal/ws/hub.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/hub.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/src/hooks/useWS.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/hooks/useWS.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/internal/ws/message.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/ws/message.go" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend/src/components/Container.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Container.tsx" 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/interfaces/Identity.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/interfaces/Identity.ts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/pages/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" />
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/src/ws/websocket.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/ws/websocket.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/yarn.lock" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/yarn.lock" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
VERSION=v1.0.0
|
||||||
|
COMMIT_HASH=$(git rev-parse --short HEAD)
|
||||||
|
ENVIRONMENT=$ENV
|
||||||
|
BUILDSTRING="$VERSION-$COMMIT_HASH-$ENVIRONMENT"
|
||||||
|
echo The environment is "$ENVIRONMENT"
|
||||||
|
echo Building watch together backend "$VERSION-$COMMIT_HASH"
|
||||||
|
if [[ "$ENVIRONMENT" == "dev" ]]; then
|
||||||
|
go build -gcflags="all=-N -l" -ldflags "-X github.com/qpixel/watchtogether/cmd/watchtogether/main.VERSION=${BUILDSTRING} -X github.com/qpixel/watchtogether/cmd/watchtogether/main.ENVIRONMENT=${ENVIRONMENT}";
|
||||||
|
else
|
||||||
|
go build -ldflags "-X github.com/qpixel/watchtogether/cmd/watchtogether/main.VERSION=${BUILDSTRING} -X github.com/ubergeek77/uberbot/v2/core.ENVIRONMENT=${ENVIRONMENT}";
|
||||||
|
fi
|
||||||
|
|
@ -10,6 +10,11 @@ import (
|
||||||
|
|
||||||
var log = tlog.NewTaggedLogger("Logger", tlog.NewColor("38;5;111"))
|
var log = tlog.NewTaggedLogger("Logger", tlog.NewColor("38;5;111"))
|
||||||
|
|
||||||
|
var (
|
||||||
|
VERSION string
|
||||||
|
ENVIRONMENT string
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
hub := ws.NewHub()
|
hub := ws.NewHub()
|
||||||
|
|
@ -47,7 +52,8 @@ func main() {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
log.Infof("starting backend")
|
||||||
|
log.Infof("running version %s. environment: %s", VERSION, ENVIRONMENT)
|
||||||
err := http.ListenAndServe(":8080", r)
|
err := http.ListenAndServe(":8080", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("%s", err.Error())
|
log.Errorf("%s", err.Error())
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ func handleIdentifyEvent(message *Message) {
|
||||||
Type: Identify,
|
Type: Identify,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"admin": true,
|
"admin": true,
|
||||||
"playlist": "http://cdnapi.kaltura.com/p/1878761/sp/187876100/playManifest/entryId/1_usagz19w/flavorIds/1_5spqkazq,1_nslowvhp,1_boih5aji,1_qahc37ag/format/applehttp/protocol/http/a.m3u8",
|
"playlist": "http://localhost:8081/BelleOpening.m3u8",
|
||||||
|
"controller": true,
|
||||||
"playhead": 0,
|
"playhead": 0,
|
||||||
"user": d["user"],
|
"user": d["user"],
|
||||||
},
|
},
|
||||||
|
|
@ -42,5 +43,21 @@ func handleGetPlayhead(message *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSetPlayhead(message *Message) {
|
func handleSetPlayhead(message *Message) {
|
||||||
|
d := message.Data.(map[string]interface{})
|
||||||
|
m := Message{
|
||||||
|
MessageData: MessageData{
|
||||||
|
Type: SetPlayhead,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"playhead": d["playhead"],
|
||||||
|
"paused": d["paused"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
log.Infof("Received SetPlayhead event. playhead is at %s", d["playhead"])
|
||||||
|
for client := range message.Client.hub.Clients {
|
||||||
|
if client == message.Client {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
client.send <- m.SerializeMessage().Data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ func (h *Hub) handleMessage(rm RawMessage) {
|
||||||
handleIdentifyEvent(&m)
|
handleIdentifyEvent(&m)
|
||||||
case Ping:
|
case Ping:
|
||||||
handlePingEvent(&m)
|
handlePingEvent(&m)
|
||||||
case Position:
|
case GetPlayhead:
|
||||||
handleGetPlayhead(&m)
|
handleGetPlayhead(&m)
|
||||||
case SetPosition:
|
case SetPlayhead:
|
||||||
handleSetPlayhead(&m)
|
handleSetPlayhead(&m)
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ const (
|
||||||
Ping MessageTypes = iota
|
Ping MessageTypes = iota
|
||||||
Pong
|
Pong
|
||||||
Identify
|
Identify
|
||||||
Position
|
GetPlayhead
|
||||||
SetPosition
|
SetPlayhead
|
||||||
)
|
)
|
||||||
|
|
||||||
type MessageData struct {
|
type MessageData struct {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
import { Flex, useColorMode, FlexProps } from '@chakra-ui/react'
|
import React, { FC } from "react";
|
||||||
|
import { Flex, useColorMode, FlexProps } from "@chakra-ui/react";
|
||||||
|
|
||||||
export const Container = (props: FlexProps) => {
|
export const Container: FC<FlexProps> = (props: FlexProps) => {
|
||||||
const { colorMode } = useColorMode()
|
const { colorMode } = useColorMode();
|
||||||
|
|
||||||
const bgColor = { light: 'gray.50', dark: 'gray.900' }
|
const bgColor = { light: "gray.50", dark: "gray.900" };
|
||||||
|
|
||||||
const color = { light: 'black', dark: 'white' }
|
const color = { light: "black", dark: "white" };
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
alignItems="center"
|
|
||||||
justifyContent="flex-start"
|
justifyContent="flex-start"
|
||||||
bg={bgColor[colorMode]}
|
bg={bgColor[colorMode]}
|
||||||
color={color[colorMode]}
|
color={color[colorMode]}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Container.defaultProps = {
|
||||||
|
alignItems: "center",
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,90 @@
|
||||||
import React, { FC } from "react";
|
import { Box, css } from "@chakra-ui/react";
|
||||||
|
import React, { FC, useRef, useState } from "react";
|
||||||
import ReactPlayer, { Config, ReactPlayerProps } from "react-player";
|
import ReactPlayer, { Config, ReactPlayerProps } from "react-player";
|
||||||
|
import { MessageTypes } from "../interfaces/IMessage";
|
||||||
|
import Message from "../util/Message";
|
||||||
|
import MessageUtil from "../util/MessageUtil";
|
||||||
|
import PlayerSocket from "../ws/websocket";
|
||||||
|
|
||||||
type PlayerProps = { id: string } & ReactPlayerProps;
|
type PlayerProps = {
|
||||||
|
id: string;
|
||||||
|
socket: PlayerSocket;
|
||||||
|
} & ReactPlayerProps;
|
||||||
|
|
||||||
|
interface ProgressProps {
|
||||||
|
played: number;
|
||||||
|
playedSeconds: number;
|
||||||
|
loaded: number;
|
||||||
|
loadedSeconds: number;
|
||||||
|
}
|
||||||
|
|
||||||
const Player: FC<PlayerProps> = (props) => {
|
const Player: FC<PlayerProps> = (props) => {
|
||||||
|
const playerRef = useRef<ReactPlayer>(null);
|
||||||
|
const [paused, setPaused] = useState<boolean>(false);
|
||||||
|
const { socket } = props;
|
||||||
const config: Config = {
|
const config: Config = {
|
||||||
file: {
|
file: {
|
||||||
forceHLS: true,
|
forceHLS: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return <ReactPlayer url={props.id} config={config} {...props} />;
|
const onProgress = (state: ProgressProps) => {
|
||||||
|
if (paused) {
|
||||||
|
socket?.send(
|
||||||
|
MessageUtil.encode(
|
||||||
|
new Message(MessageTypes.SetPlayhead, {
|
||||||
|
playhead: state.playedSeconds,
|
||||||
|
paused: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
socket?.send(
|
||||||
|
MessageUtil.encode(
|
||||||
|
new Message(MessageTypes.SetPlayhead, {
|
||||||
|
playhead: state.playedSeconds,
|
||||||
|
paused: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const onPause = () => {
|
||||||
|
setPaused(true);
|
||||||
|
socket?.send(
|
||||||
|
MessageUtil.encode(
|
||||||
|
new Message(MessageTypes.SetPlayhead, {
|
||||||
|
playhead: playerRef.current.getCurrentTime(),
|
||||||
|
paused: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const onPlay = () => {
|
||||||
|
setPaused(false);
|
||||||
|
socket?.send(
|
||||||
|
MessageUtil.encode(
|
||||||
|
new Message(MessageTypes.SetPlayhead, {
|
||||||
|
playhead: playerRef.current.getCurrentTime(),
|
||||||
|
paused: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Box height="100vh" width="100vw">
|
||||||
|
<ReactPlayer
|
||||||
|
url={props.id}
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
config={config}
|
||||||
|
controls
|
||||||
|
onPlay={onPlay}
|
||||||
|
onPause={onPause}
|
||||||
|
onProgress={onProgress}
|
||||||
|
ref={playerRef}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Player;
|
export default Player;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import IUser from "./IUser";
|
import IUser from "./IUser";
|
||||||
|
|
||||||
interface IdentityData {
|
interface IdentityData {
|
||||||
|
admin?: boolean;
|
||||||
|
controller?: boolean;
|
||||||
clientID?: string;
|
clientID?: string;
|
||||||
playlist?: string;
|
playlist?: string;
|
||||||
playHead?: number;
|
playHead?: number;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
enum SocketEvents {
|
||||||
|
Identify = "Identify",
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SocketEvents;
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Socket } from "dgram";
|
||||||
import { GetServerSideProps, NextPage } from "next";
|
import { GetServerSideProps, NextPage } from "next";
|
||||||
import { User } from "next-auth";
|
import { User } from "next-auth";
|
||||||
import { getSession } from "next-auth/react";
|
import { getSession } from "next-auth/react";
|
||||||
|
|
@ -5,36 +6,42 @@ import dynamic from "next/dynamic";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import ReactPlayer from "react-player";
|
import ReactPlayer from "react-player";
|
||||||
|
import { BaseReactPlayerProps } from "react-player/base";
|
||||||
import { Container } from "../components/Container";
|
import { Container } from "../components/Container";
|
||||||
import useWS from "../hooks/useWS";
|
import useWS from "../hooks/useWS";
|
||||||
import IdentityData from "../interfaces/Identity";
|
import IdentityData from "../interfaces/Identity";
|
||||||
import { MessageTypes } from "../interfaces/IMessage";
|
import { MessageTypes } from "../interfaces/IMessage";
|
||||||
|
import SocketEvents from "../interfaces/SocketEvents";
|
||||||
import isBrowser from "../util/isBrowser";
|
import isBrowser from "../util/isBrowser";
|
||||||
|
import Message from "../util/Message";
|
||||||
|
import MessageUtil from "../util/MessageUtil";
|
||||||
|
|
||||||
const Player = dynamic(() => import("../components/Player"), { ssr: false });
|
const Player = dynamic(() => import("../components/Player"), { ssr: false });
|
||||||
|
|
||||||
interface PlayerPageProps {
|
interface PlayerPageProps {
|
||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
|
// types for the function
|
||||||
|
|
||||||
const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => {
|
const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => {
|
||||||
const playerRef = useRef<ReactPlayer>();
|
// const playerRef = useRef<ReactPlayer>();
|
||||||
const socket = useWS({ user });
|
const socket = useWS({ user });
|
||||||
const [id, setID] = useState<string>("");
|
const [id, setID] = useState<string>("");
|
||||||
|
const [identity, setIdentity] = useState<IdentityData>();
|
||||||
if (isBrowser() && typeof socket !== "undefined") {
|
if (isBrowser() && typeof socket !== "undefined") {
|
||||||
socket.emitter.on("Identify", (e: IdentityData) => {
|
socket.emitter.on(SocketEvents.Identify, (e: IdentityData) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
setID(e.playlist);
|
setID(e.playlist);
|
||||||
|
setIdentity(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Watch Together</title>
|
<title>Watch Together</title>
|
||||||
</Head>
|
</Head>
|
||||||
<Container height="100vh">
|
<Container height="100vh" background={"#000"}>
|
||||||
<Player id={id} ref={playerRef} />
|
<Player id={id} socket={socket} />
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue