Skip to content

Commit

Permalink
Added Player UI
Browse files Browse the repository at this point in the history
  • Loading branch information
robrotheram committed Apr 7, 2024
1 parent c55438b commit 8ae0915
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 172 deletions.
2 changes: 2 additions & 0 deletions pkg/api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"w2g/pkg/controllers"
"w2g/pkg/utils"

_ "net/http/pprof"

"github.com/gorilla/handlers"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func NewDiscordAuth(conf utils.Config, paths []string) DiscordAuth {
}
da.oauthStateString = utils.RandStringRunes(20)
da.store = sessions.NewCookieStore([]byte(conf.SessionSecret))
da.store.MaxAge(86400 * 1)
da.users = make(map[string]User)
da.paths = paths
return da
Expand All @@ -94,7 +95,6 @@ func (da *DiscordAuth) getToken(state string, code string) (*oauth2.Token, error
if state != da.oauthStateString {
return nil, fmt.Errorf("invalid oauth state")
}

token, err := da.oauthConfig.Exchange(context.Background(), code)
if err != nil {
return nil, fmt.Errorf("code exchange failed: %s", err.Error())
Expand Down
28 changes: 15 additions & 13 deletions pkg/api/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ type Client struct {
contoller *controllers.Controller
socket *websocket.Conn
send chan []byte

done chan any
progress media.MediaDuration
running bool
exitCode controllers.PlayerExitCode
done chan any
progress media.MediaDuration
running bool
exitCode controllers.PlayerExitCode
}

const (
Expand Down Expand Up @@ -77,14 +76,20 @@ func (c *Client) Send(event controllers.Event) {
}
}

func (wb *Client) Type() controllers.PlayerType {
return WEBPLAYER
}

func (wb *Client) Id() string {
return wb.id
}

func (wb *Client) Meta() controllers.PlayerMeta {
return controllers.PlayerMeta{
Id: wb.id,
Type: WEBPLAYER,
Running: wb.running,
Progress: wb.progress,
User: wb.user.Username,
}
}

func (wb *Client) Play(url string, start int) (controllers.PlayerExitCode, error) {
wb.progress = media.MediaDuration{
Progress: 0,
Expand All @@ -94,11 +99,8 @@ func (wb *Client) Play(url string, start int) (controllers.PlayerExitCode, error
return wb.exitCode, nil
}

func (wb *Client) Progress() media.MediaDuration {
return wb.progress
}

func (wb *Client) Pause() {}

func (wb *Client) Unpause() {
wb.running = true
}
Expand Down
14 changes: 1 addition & 13 deletions pkg/controllers/betterStackAuditing.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,18 @@ type BetterStackMessage struct {
Status Action `json:"status"`
Message string `json:"message"`
State PlayerState `json:"state"`
Players []string `json:"players"`
}

func (a *BetterStack) Send(event Event) {
if event.Action.Type == UPDATE_DURATION {
return
}

players := []string{}
if event.Players != nil {
for _, v := range event.Players.players {
players = append(players, fmt.Sprintf("%s-%s", v.Type(), v.Id()))
}
}
msg := BetterStackMessage{
Level: "info",
Severity: "low",
Status: event.Action,
Players: players,
State: event.State,
}
if event.State != nil {
msg.State = *event.State
}

jsonData, err := json.Marshal(msg)

if err != nil {
Expand Down
14 changes: 12 additions & 2 deletions pkg/controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ func (c *Controller) Add(url string, top bool, user string) error {
func (c *Controller) Skip(user string) {
if c.running {
c.players.Stop()
c.state.Next()
go c.progress()
go c.duration()
} else {
c.state.Next()
}
Expand Down Expand Up @@ -153,6 +156,13 @@ func (c *Controller) State() *PlayerState {
return c.state
}

func (c *Controller) ServerState() ServerState {
return ServerState{
Players: c.players.GetProgress(),
State: *c.state,
}
}

func (c *Controller) Update(state *PlayerState, user string) {
c.state = state
c.save()
Expand Down Expand Up @@ -229,8 +239,8 @@ func (c *Controller) Notify(action ActionType, user string) {
User: user,
Channel: state.ID,
},
State: state,
Players: c.players,
State: *state,
Players: c.players.GetProgress(),
}
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/controllers/notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ var (
LOOP_ACTION = ActionType("LOOP")
SHUFFLE_ACTION = ActionType("SHUFFLE")
SKIP_ACTION = ActionType("SKIP")
PLAYER_ACTION = ActionType("PlAYER CHANGE")
PLAYER_ACTION = ActionType("PlAYER_CHANGE")
LEAVE_ACTION = ActionType("LEAVE")
)

type Event struct {
ID string `json:"id"`
Action Action `json:"action"`
State *PlayerState `json:"state"`
Players *Players `json:"players"`
State PlayerState `json:"state"`
Message string `json:"message"`
Players []PlayerMeta `json:"players"`
}

type Listener interface {
Expand Down
26 changes: 11 additions & 15 deletions pkg/controllers/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

type PlayerType string
type PlayerMeta struct {
Id string `json:"id"`
User string `json:"user"`
Progress media.MediaDuration `json:"progress"`
Type PlayerType `json:"type"`
Running bool `json:"running"`
Expand All @@ -24,15 +26,13 @@ const (

type Player interface {
Play(string, int) (PlayerExitCode, error)
Progress() media.MediaDuration
Seek(time.Duration)
Type() PlayerType
Id() string
Pause()
Unpause()
Stop()
Close()
Status() bool
Meta() PlayerMeta
Id() string
}

type Players struct {
Expand All @@ -51,7 +51,7 @@ func (p *Players) Empty() bool {
}

func (p *Players) Add(player Player) {
p.players[player.Id()] = player
p.players[player.Meta().Id] = player
}

func (p *Players) Remvoe(id string) {
Expand All @@ -67,22 +67,18 @@ func (p *Players) Seek(seconds time.Duration) {
}
}

func (p *Players) GetProgress() map[string]PlayerMeta {
data := map[string]PlayerMeta{}
func (p *Players) GetProgress() []PlayerMeta {
data := []PlayerMeta{}
for _, player := range p.players {
data[player.Id()] = PlayerMeta{
Progress: player.Progress(),
Type: player.Type(),
Running: player.Status(),
}
data = append(data, player.Meta())
}
return data
}

func (p *Players) Progress() media.MediaDuration {
progress := media.MediaDuration{}
for _, player := range p.players {
prg := player.Progress().Progress
prg := player.Meta().Progress.Progress
if prg > progress.Progress {
progress.Progress = prg
}
Expand All @@ -98,7 +94,7 @@ func (p *Players) Play(url string, start int) {
go func(player Player) {
exit, err := player.Play(url, start)
if err != nil {
log.Warnf("%s player error: %v", player.Type(), err)
log.Warnf("%s player error: %v", player.Meta().Type, err)
}
wg.Done()
if exit == STOP_EXITCODE {
Expand Down Expand Up @@ -135,7 +131,7 @@ func (p *Players) Close() {

func (p *Players) Running() bool {
for _, player := range p.players {
if player.Status() {
if player.Meta().Running {
return true
}
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/controllers/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ type PlayerState struct {
Active bool `json:"active"`
}

type ServerState struct {
Players []PlayerMeta `json:"players"`
State PlayerState
}

func (state *PlayerState) Next() {
if len(state.Queue) > 0 {
state.Current = state.Queue[0]
Expand Down
18 changes: 8 additions & 10 deletions pkg/discord/players/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,18 @@ func (player *DiscordPlayer) playStream() {
}
}

func (player *DiscordPlayer) Type() controllers.PlayerType {
return DISCORD
}

func (player *DiscordPlayer) Id() string {
return player.id
}

func (player *DiscordPlayer) Status() bool {
return player.running
func (player *DiscordPlayer) Meta() controllers.PlayerMeta {
return controllers.PlayerMeta{
Id: player.id,
Type: DISCORD,
User: string(DISCORD),
Running: player.running,
Progress: player.progress,
}
}

func (player *DiscordPlayer) Close() {
Expand Down Expand Up @@ -142,10 +144,6 @@ func (player *DiscordPlayer) Stop() {
player.Finish()
}

func (player *DiscordPlayer) Progress() media.MediaDuration {
return player.progress
}

func (player *DiscordPlayer) Play(url string, startTime int) (controllers.PlayerExitCode, error) {
player.seekTo = -1
if player.running {
Expand Down
72 changes: 72 additions & 0 deletions ui/src/pages/app/components/UserPlayer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useContext, useRef, useState } from "react";
import { useOnClickOutside } from "./nav";
import { GuildContext, PlayerContext } from "./providers";
import { formatTime } from "../watch2gether";
import { toast } from "react-hot-toast";

export const SyncIcon = () => {
return <svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" width={24} height={24} viewBox="0 0 24 24" strokeWidth="3.5" stroke="white" fill="none" strokeLinecap="round" strokeLinejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M3 7h1.948c1.913 0 3.705 .933 4.802 2.5a5.861 5.861 0 0 0 4.802 2.5h6.448" />
<path d="M3 17h1.95a5.854 5.854 0 0 0 4.798 -2.5a5.854 5.854 0 0 1 4.798 -2.5h5.454" />
<path d="M18 15l3 -3l-3 -3" />
</svg>
}

const UserPlayerItem = ({player}) => {
const {setProgress} = useContext(PlayerContext)
const truncate = (input) => {
const size = 12;
if (input.length > size) {
return input.substring(0, size) + '... ';
}
return input;
};
const handleSync = () => {
setProgress(player.progress.progress)
toast.success(`You have synced to ${player.user} position`)
}
return <li className="flex align-middle justify-between items-center">
<span>{truncate(player.user)}: {formatTime(player.progress.progress)}</span>
<button onClick={()=>{handleSync()}} className="rounded-full p-1 border-purple-700 icon-shadow active:bg-purple-700">
<SyncIcon />
</button>
</li>
}
export const UserPlayer = ({players}) => {
const p = players.sort(function(a, b) {
return a.id.localeCompare(b.id);
});
return <div className="z-50 absolute bottom-24 left-2 right-4 md:right-auto w-60 text-white rounded-lg shadow-lg border-purple-950" style={{ background: "rgba(0,0,0,0.8)" }} >
<div className="max-h-60 py-2 rounded-lg overflow-y-auto hide-scrollbar shadow-lg text-violet-200 flex justify-center p-3 text-lg font-medium bg-violet-900 p">
Currently Watching
</div>
<ul className="p-4 flex flex-col gap-1 max-h-48 overflow-y-auto hide-scrollbar">
{p.map(function(player) {
return <UserPlayerItem key={player.id} player={player}/>
})}
</ul>
</div>
}

export const UserPlayerBtn = () => {
const [visable, setVisible] = useState(false)
const {players} = useContext(GuildContext)
const ref = useRef();
useOnClickOutside(ref, () => setVisible(false));

return <div ref={ref}>
<button onClick={()=>{setVisible(!visable)}} className="z-50 hidden absolute w-12 h-12 bottom-4 left-4 rounded-full bg-violet-700 text-white sm:flex justify-center items-center icon-shadow active:bg-purple-700">
<svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" className="icon icon-tabler icons-tabler-outline icon-tabler-eyeglass-2">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M8 4h-2l-3 10v2.5" />
<path d="M16 4h2l3 10v2.5" />
<path d="M10 16l4 0" />
<path d="M17.5 16.5m-3.5 0a3.5 3.5 0 1 0 7 0a3.5 3.5 0 1 0 -7 0" />
<path d="M6.5 16.5m-3.5 0a3.5 3.5 0 1 0 7 0a3.5 3.5 0 1 0 -7 0" />
</svg>
<div className="absolute bottom-0 border-1 border-red-50 right-0 bg-violet-900 w-4 h-4 flex justify-center items-center rounded-full">{players.length}</div>
</button>
{visable && <UserPlayer players={players} />}
</div>
}
Loading

0 comments on commit 8ae0915

Please sign in to comment.