Sort the WhoList + Mutual Video options
* The who list now sorts alphabetically instead of random * New user controls when they share video: * Require users to also be sharing before they open ours * We auto-open a viewer's video when they open ours
This commit is contained in:
parent
3f6e2193c8
commit
4a2fc9c923
|
@ -261,6 +261,8 @@ func (s *Server) OnMe(sub *Subscriber, msg Message) {
|
|||
}
|
||||
|
||||
sub.VideoActive = msg.VideoActive
|
||||
sub.VideoMutual = msg.VideoMutual
|
||||
sub.VideoMutualOpen = msg.VideoMutualOpen
|
||||
sub.VideoNSFW = msg.NSFW
|
||||
sub.ChatStatus = msg.ChatStatus
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@ type Message struct {
|
|||
WhoList []WhoList `json:"whoList,omitempty"`
|
||||
|
||||
// Sent on `me` actions along with Username
|
||||
VideoActive bool `json:"videoActive,omitempty"` // user tells us their cam status
|
||||
ChatStatus string `json:"status,omitempty"` // online vs. away
|
||||
NSFW bool `json:"nsfw,omitempty"` // user tags their video NSFW
|
||||
VideoActive bool `json:"videoActive,omitempty"` // user tells us their cam status
|
||||
VideoMutual bool `json:"videoMutual,omitempty"` // user wants mutual viewers
|
||||
VideoMutualOpen bool `json:"videoMutualOpen,omitempty"`
|
||||
ChatStatus string `json:"status,omitempty"` // online vs. away
|
||||
NSFW bool `json:"nsfw,omitempty"` // user tags their video NSFW
|
||||
|
||||
// Sent on `open` actions along with the (other) Username.
|
||||
OpenSecret string `json:"openSecret,omitempty"`
|
||||
|
@ -66,10 +68,12 @@ const (
|
|||
|
||||
// WhoList is a member entry in the chat room.
|
||||
type WhoList struct {
|
||||
Username string `json:"username"`
|
||||
VideoActive bool `json:"videoActive,omitempty"`
|
||||
NSFW bool `json:"nsfw,omitempty"`
|
||||
Status string `json:"status"`
|
||||
Username string `json:"username"`
|
||||
VideoActive bool `json:"videoActive,omitempty"`
|
||||
VideoMutual bool `json:"videoMutual,omitempty"`
|
||||
VideoMutualOpen bool `json:"videoMutualOpen,omitempty"`
|
||||
NSFW bool `json:"nsfw,omitempty"`
|
||||
Status string `json:"status"`
|
||||
|
||||
// JWT auth extra settings.
|
||||
Operator bool `json:"op"`
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -20,18 +21,20 @@ import (
|
|||
// Subscriber represents a connected WebSocket session.
|
||||
type Subscriber struct {
|
||||
// User properties
|
||||
ID int // ID assigned by server
|
||||
Username string
|
||||
VideoActive bool
|
||||
VideoNSFW bool
|
||||
ChatStatus string
|
||||
JWTClaims *jwt.Claims
|
||||
authenticated bool // has passed the login step
|
||||
conn *websocket.Conn
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
messages chan []byte
|
||||
closeSlow func()
|
||||
ID int // ID assigned by server
|
||||
Username string
|
||||
VideoActive bool
|
||||
VideoMutual bool
|
||||
VideoMutualOpen bool
|
||||
VideoNSFW bool
|
||||
ChatStatus string
|
||||
JWTClaims *jwt.Claims
|
||||
authenticated bool // has passed the login step
|
||||
conn *websocket.Conn
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
messages chan []byte
|
||||
closeSlow func()
|
||||
|
||||
muteMu sync.RWMutex
|
||||
booted map[string]struct{} // usernames booted off your camera
|
||||
|
@ -308,8 +311,16 @@ func (s *Server) SendTo(username string, msg Message) error {
|
|||
func (s *Server) SendWhoList() {
|
||||
var (
|
||||
subscribers = s.IterSubscribers()
|
||||
usernames = []string{} // distinct and sorted usernames
|
||||
userSub = map[string]*Subscriber{}
|
||||
)
|
||||
|
||||
for _, sub := range subscribers {
|
||||
usernames = append(usernames, sub.Username)
|
||||
userSub[sub.Username] = sub
|
||||
}
|
||||
sort.Strings(usernames)
|
||||
|
||||
// Build the WhoList for each subscriber.
|
||||
// TODO: it's the only way to fake videoActive for booted user views.
|
||||
for _, sub := range subscribers {
|
||||
|
@ -318,16 +329,19 @@ func (s *Server) SendWhoList() {
|
|||
}
|
||||
|
||||
var users = []WhoList{}
|
||||
for _, user := range subscribers {
|
||||
for _, un := range usernames {
|
||||
user := userSub[un]
|
||||
if user.ChatStatus == "hidden" {
|
||||
continue
|
||||
}
|
||||
|
||||
who := WhoList{
|
||||
Username: user.Username,
|
||||
Status: user.ChatStatus,
|
||||
VideoActive: user.VideoActive,
|
||||
NSFW: user.VideoNSFW,
|
||||
Username: user.Username,
|
||||
Status: user.ChatStatus,
|
||||
VideoActive: user.VideoActive,
|
||||
VideoMutual: user.VideoMutual,
|
||||
VideoMutualOpen: user.VideoMutualOpen,
|
||||
NSFW: user.VideoNSFW,
|
||||
}
|
||||
|
||||
// If this person had booted us, force their camera to "off"
|
||||
|
|
|
@ -250,3 +250,8 @@ body {
|
|||
top: 14px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
/* Cursors */
|
||||
.cursor-notallowed {
|
||||
cursor: not-allowed;
|
||||
}
|
|
@ -91,6 +91,8 @@ const app = Vue.createApp({
|
|||
stream: null, // MediaStream object
|
||||
muted: false, // our outgoing mic is muted, not by default
|
||||
nsfw: false, // user has flagged their camera to be NSFW
|
||||
mutual: false, // user wants viewers to share their own videos
|
||||
mutualOpen: false, // user wants to open video mutually
|
||||
|
||||
// Who all is watching me? map of users.
|
||||
watching: {},
|
||||
|
@ -331,6 +333,8 @@ const app = Vue.createApp({
|
|||
this.ws.conn.send(JSON.stringify({
|
||||
action: "me",
|
||||
videoActive: this.webcam.active,
|
||||
videoMutual: this.webcam.mutual,
|
||||
videoMutualOpen: this.webcam.mutualOpen,
|
||||
status: this.status,
|
||||
nsfw: this.webcam.nsfw,
|
||||
}));
|
||||
|
@ -682,6 +686,15 @@ const app = Vue.createApp({
|
|||
});
|
||||
}
|
||||
|
||||
// If we are the offerer, and this member wants to auto-open our camera
|
||||
// then add our own stream to the connection.
|
||||
if (isOfferer && this.whoMap[username].videoMutualOpen && this.webcam.active) {
|
||||
let stream = this.webcam.stream;
|
||||
stream.getTracks().forEach(track => {
|
||||
pc.addTrack(track, stream)
|
||||
});
|
||||
}
|
||||
|
||||
// If we are the offerer, begin the connection.
|
||||
if (isOfferer) {
|
||||
pc.createOffer({
|
||||
|
@ -953,6 +966,14 @@ const app = Vue.createApp({
|
|||
return;
|
||||
}
|
||||
|
||||
// If this user requests mutual viewership...
|
||||
if (user.videoMutual && !this.webcam.active) {
|
||||
this.ChatClient(
|
||||
`<strong>${user.username}</strong> has requested that you should share your own camera too before opening theirs.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendOpen(user.username);
|
||||
|
||||
// Responsive CSS -> go to chat panel to see the camera
|
||||
|
@ -995,6 +1016,16 @@ const app = Vue.createApp({
|
|||
// Inform backend we have closed it.
|
||||
this.sendWatch(username, false);
|
||||
},
|
||||
unMutualVideo() {
|
||||
// If we had our camera on to watch a video of someone who wants mutual cameras,
|
||||
// and then we turn ours off: we should unfollow the ones with mutual video.
|
||||
for (let row of this.whoList) {
|
||||
let username = row.username;
|
||||
if (row.videoMutual && this.WebRTC.pc[username] != undefined) {
|
||||
this.closeVideo(username);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Show who watches our video.
|
||||
showViewers() {
|
||||
|
@ -1052,6 +1083,9 @@ const app = Vue.createApp({
|
|||
this.closeVideo(username, "answerer");
|
||||
}
|
||||
|
||||
// Hang up on mutual cameras.
|
||||
this.unMutualVideo();
|
||||
|
||||
// Tell backend our camera state.
|
||||
this.sendMe();
|
||||
},
|
||||
|
|
|
@ -228,8 +228,8 @@
|
|||
<i class="fa fa-eye"></i> see who is watching will be at the top of the page.
|
||||
</p>
|
||||
|
||||
<p class="block">
|
||||
If your camera will be featuring "<abbr title="Not Safe For Work">NSFW</abbr>" or sexual content, please mark it as such by
|
||||
<p class="block mb-1">
|
||||
If your camera will be featuring "<abbr title="Not Safe For Work">Explicit</abbr>" or sexual content, please mark it as such by
|
||||
clicking on the <i class="fa fa-fire has-text-danger"></i> button or checking the box below to start with it enabled.
|
||||
</p>
|
||||
|
||||
|
@ -237,7 +237,28 @@
|
|||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
v-model="webcam.nsfw">
|
||||
Check this box if your webcam will <em>definitely</em> be NSFW. 😈
|
||||
Check this box if your webcam will <em>definitely</em> be Explicit. 😈
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<p class="block mb-1">
|
||||
<label class="label">Mutual webcam options:</label>
|
||||
</p>
|
||||
|
||||
<div class="field mb-1">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
v-model="webcam.mutual">
|
||||
People must be sharing their own camera before they can open mine
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
:disabled="!webcam.mutual"
|
||||
v-model="webcam.mutualOpen">
|
||||
When someone opens my camera, I also open their camera automatically
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
@ -778,8 +799,12 @@
|
|||
:class="{
|
||||
'is-danger is-outlined': u.videoActive && u.nsfw,
|
||||
'is-info is-outlined': u.videoActive && !u.nsfw,
|
||||
'cursor-notallowed': u.videoActive && u.videoMutual && !webcam.active,
|
||||
}"
|
||||
title="Open video stream"
|
||||
:title="`Open video stream` +
|
||||
(u.videoActive && u.videoMutual ? '; mutual video sharing required' : '') +
|
||||
(u.videoActive && u.videoMutualOpen ? '; will auto-open your video' : '')"
|
||||
|
||||
@click="openVideo(u)">
|
||||
<i class="fa fa-video"></i>
|
||||
</button>
|
||||
|
|
Loading…
Reference in New Issue
Block a user