forked from lavender/watch-party
		
	implement a viewer list
This commit is contained in:
		
							parent
							
								
									951007df2a
								
							
						
					
					
						commit
						72c212a100
					
				
					 6 changed files with 72 additions and 10 deletions
				
			
		|  | @ -29,14 +29,9 @@ | ||||||
|           maxlength="50" |           maxlength="50" | ||||||
|           required |           required | ||||||
|         /> |         /> | ||||||
|          | 
 | ||||||
|         <label for="join-session-colour">Colour:</label> |         <label for="join-session-colour">Colour:</label> | ||||||
|         <input |         <input type="color" id="join-session-colour" value="#7ed0ff" required /> | ||||||
|           type="color" |  | ||||||
|           id="join-session-colour" |  | ||||||
|           value="#7ed0ff" |  | ||||||
|           required |  | ||||||
|         /> |  | ||||||
| 
 | 
 | ||||||
|         <label for="join-session-id">Session ID:</label> |         <label for="join-session-id">Session ID:</label> | ||||||
|         <input |         <input | ||||||
|  | @ -55,6 +50,7 @@ | ||||||
| 
 | 
 | ||||||
|     <div id="video-container"></div> |     <div id="video-container"></div> | ||||||
|     <div id="chatbox-container"> |     <div id="chatbox-container"> | ||||||
|  |       <div id="viewer-list"></div> | ||||||
|       <div id="chatbox"></div> |       <div id="chatbox"></div> | ||||||
|       <form id="chatbox-send"> |       <form id="chatbox-send"> | ||||||
|         <input type="text" placeholder="Message..." /> |         <input type="text" placeholder="Message..." /> | ||||||
|  |  | ||||||
|  | @ -267,3 +267,20 @@ const beep = () => { | ||||||
|   oscillator.start(context.currentTime); |   oscillator.start(context.currentTime); | ||||||
|   oscillator.stop(context.currentTime + 0.22); |   oscillator.stop(context.currentTime + 0.22); | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export const updateViewerList = (viewers) => { | ||||||
|  |   const listContainer = document.querySelector("#viewer-list"); | ||||||
|  | 
 | ||||||
|  |   // empty out the current list
 | ||||||
|  |   listContainer.innerHTML = ""; | ||||||
|  | 
 | ||||||
|  |   // display the updated list
 | ||||||
|  |   for (const viewer of viewers) { | ||||||
|  |     const viewerElem = document.createElement("div"); | ||||||
|  |     const content = document.createElement("strong"); | ||||||
|  |     content.textContent = viewer.nickname; | ||||||
|  |     content.style = `color: #${viewer.colour}`; | ||||||
|  |     viewerElem.appendChild(content); | ||||||
|  |     listContainer.appendChild(viewerElem); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { setupVideo } from "./video.mjs?v=8"; | import { setupVideo } from "./video.mjs?v=8"; | ||||||
| import { setupChat, logEventToChat } from "./chat.mjs?v=8"; | import { setupChat, logEventToChat, updateViewerList } from "./chat.mjs?v=8"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @param {string} sessionId |  * @param {string} sessionId | ||||||
|  | @ -70,6 +70,9 @@ const setupIncomingEvents = (video, socket) => { | ||||||
|             setDebounce(); |             setDebounce(); | ||||||
|             setVideoTime(event.data); |             setVideoTime(event.data); | ||||||
|             break; |             break; | ||||||
|  |           case "UpdateViewerList": | ||||||
|  |             updateViewerList(event.data); | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -161,6 +161,16 @@ button.small-button { | ||||||
|   overflow-y: scroll; |   overflow-y: scroll; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #viewer-list { | ||||||
|  |   padding: 0.5em 2em; | ||||||
|  |   /* TODO: turn this into max-height instead of fixed height without breaking the chatbox height */ | ||||||
|  |   height: 4em; | ||||||
|  |   overflow-y: scroll; | ||||||
|  |   color: rgb(126, 208, 255); | ||||||
|  |   border-bottom: var(--fg); | ||||||
|  |   border-bottom-style: solid; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #chatbox-container { | #chatbox-container { | ||||||
|   background-color: #222; |   background-color: #222; | ||||||
| } | } | ||||||
|  | @ -196,6 +206,6 @@ button.small-button { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   #chatbox { |   #chatbox { | ||||||
|     height: calc(100vh - 5em) !important; |     height: calc(100vh - 5em - 4em) !important; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,13 @@ | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| 
 | 
 | ||||||
|  | #[derive(Clone, Serialize, Deserialize)] | ||||||
|  | pub struct Viewer { | ||||||
|  |     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub nickname: Option<String>, | ||||||
|  |     #[serde(default, skip_serializing_if = "Option::is_none")] | ||||||
|  |     pub colour: Option<String>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Clone, Serialize, Deserialize)] | #[derive(Clone, Serialize, Deserialize)] | ||||||
| #[serde(tag = "op", content = "data")] | #[serde(tag = "op", content = "data")] | ||||||
| pub enum WatchEventData { | pub enum WatchEventData { | ||||||
|  | @ -17,6 +25,7 @@ pub enum WatchEventData { | ||||||
|     UserLeave, |     UserLeave, | ||||||
|     ChatMessage(String), |     ChatMessage(String), | ||||||
|     Ping(String), |     Ping(String), | ||||||
|  |     UpdateViewerList(Vec<Viewer>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Serialize, Deserialize)] | #[derive(Clone, Serialize, Deserialize)] | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ use uuid::Uuid; | ||||||
| use warp::ws::{Message, WebSocket}; | use warp::ws::{Message, WebSocket}; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     events::{WatchEvent, WatchEventData}, |     events::{Viewer, WatchEvent, WatchEventData}, | ||||||
|     utils::truncate_str, |     utils::truncate_str, | ||||||
|     watch_session::{get_session, handle_watch_event_data}, |     watch_session::{get_session, handle_watch_event_data}, | ||||||
| }; | }; | ||||||
|  | @ -74,6 +74,8 @@ pub async fn ws_subscribe(session_uuid: Uuid, nickname: String, colour: String, | ||||||
|     ) |     ) | ||||||
|     .await; |     .await; | ||||||
| 
 | 
 | ||||||
|  |     update_viewer_list(session_uuid).await; | ||||||
|  | 
 | ||||||
|     while let Some(Ok(message)) = viewer_ws_rx.next().await { |     while let Some(Ok(message)) = viewer_ws_rx.next().await { | ||||||
|         let event: WatchEventData = match message |         let event: WatchEventData = match message | ||||||
|             .to_str() |             .to_str() | ||||||
|  | @ -113,6 +115,7 @@ pub async fn ws_subscribe(session_uuid: Uuid, nickname: String, colour: String, | ||||||
|     .await; |     .await; | ||||||
| 
 | 
 | ||||||
|     CONNECTED_VIEWERS.write().await.remove(&viewer_id); |     CONNECTED_VIEWERS.write().await.remove(&viewer_id); | ||||||
|  |     update_viewer_list(session_uuid).await; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub async fn ws_publish(session_uuid: Uuid, skip_viewer_id: Option<usize>, event: WatchEvent) { | pub async fn ws_publish(session_uuid: Uuid, skip_viewer_id: Option<usize>, event: WatchEvent) { | ||||||
|  | @ -127,3 +130,27 @@ pub async fn ws_publish(session_uuid: Uuid, skip_viewer_id: Option<usize>, event | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | async fn update_viewer_list(session_uuid: Uuid) { | ||||||
|  |     let mut viewers = Vec::new(); | ||||||
|  | 
 | ||||||
|  |     for viewer in CONNECTED_VIEWERS.read().await.values() { | ||||||
|  |         if viewer.session == session_uuid { | ||||||
|  |             viewers.push(Viewer { | ||||||
|  |                 nickname: viewer.nickname.clone(), | ||||||
|  |                 colour: viewer.colour.clone(), | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ws_publish( | ||||||
|  |         session_uuid, | ||||||
|  |         None, | ||||||
|  |         WatchEvent::new( | ||||||
|  |             String::from("server"), | ||||||
|  |             String::from(""), | ||||||
|  |             WatchEventData::UpdateViewerList(viewers), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  |     .await; | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue