Setting to Opt-Out of QR Code Watermark

* Add a NoWatermark video flag so users can opt-out of the QR code being
  shown over their webcam when others watch their video.
* The setting can be found in the Chat Settings 'Camera' tab, and must be
  opted in (default is to protect cameras with watermarks).
* Update the About page and QR code info modal with instructions.
This commit is contained in:
Noah 2025-06-01 11:59:21 -07:00
parent 4179cba30a
commit 2305ff54db
7 changed files with 80 additions and 13 deletions

View File

@ -140,6 +140,7 @@ const (
VideoFlagMutualOpen // viewer wants to auto-open viewers' cameras
VideoFlagOnlyVIP // can only shows as active to VIP members
VideoFlagInvited // user invites another to watch their camera
VideoFlagNoWatermark // user opts out of QR code watermark protection
)
// Presence message templates.

View File

@ -739,6 +739,9 @@ export default {
if (settings.autoMuteWebcams === true) {
this.webcam.autoMuteWebcams = true;
}
if (settings.videoNoWatermark === true) {
this.webcam.noWatermark = true;
}
// Misc preferences
if (settings.usePolling != undefined) {
@ -2726,13 +2729,6 @@ export default {
Camera Settings
</h3>
<p class="block mb-1 is-size-7">
The settings on this tab will be relevant only when you are already
broadcasting your camera. They allow you to modify your broadcast settings
while you are already live (for example, to change your mutual camera
preference or select another audio/video device to broadcast from).
</p>
<p class="block mb-1" v-if="config.permitNSFW">
<label class="label">Explicit webcam options</label>
</p>
@ -2839,7 +2835,7 @@ export default {
</div>
</div>
<p class="block mb-1" v-if="webcam.videoDevices.length > 0">
<p class="block mb-1">
<label class="label">Miscellaneous</label>
</p>
@ -2854,6 +2850,18 @@ export default {
from this device.
</p>
</div>
<div class="field mb-1">
<label class="checkbox">
<input type="checkbox" v-model="webcam.noWatermark">
Do not protect my video from screen recording
</label>
<p class="help">
The <i class="fa fa-qrcode"></i> QR codes are a safety feature against people screen recording your camera.
If you accept that risk, this setting can remove the QR code from <em>your own</em> webcam.
<a href="/about#watermarks" target="_blank">Learn more <i class="fa fa-external-link"></i></a>
</p>
</div>
</div>
<!-- Misc preferences -->
@ -3428,6 +3436,7 @@ export default {
:is-source-muted="webcam.muted"
:is-speaking="WebRTC.speaking[username]"
:watermark-image="webcam.watermark"
:is-no-watermark="webcam.noWatermark"
@mute-video="muteMe()"
@popout="popoutVideo"
@open-profile="showProfileModal"
@ -3448,6 +3457,7 @@ export default {
:is-watching-me="isWatchingMe(username)"
:is-frozen="WebRTC.frozenStreamDetected[username]"
:watermark-image="webcam.watermark"
:is-no-watermark="isUsernameCamNoWatermark(username)"
@reopen-video="openVideoByUsername"
@mute-video="muteVideo"
@popout="popoutVideo"

View File

@ -13,6 +13,7 @@ export default {
isFrozen: Boolean, // video is detected as frozen
isSpeaking: Boolean, // video is registering audio
watermarkImage: Image, // watermark image to overlay (nullable)
isNoWatermark: Boolean, // camera does not want watermark protection
},
components: {
Slider,
@ -137,9 +138,8 @@ export default {
"The QR code contains the current viewer's username, the website's name, and the current date/time. The " +
"idea is that if a webcam is recorded and then leaked online, the QR code would connect it directly back to who exactly " +
"recorded it, and when.\n\n" +
"There are two QR codes on each video: the one in the bottom-right corner is intentionally made visible and obvious " +
"to everybody, and a second (subtle) copy of the code spans across the center/middle of the video and pulsates in " +
"transparency over time.",
"Notice: if you do not care about this risk, you may remove the QR code from *your own* video so that it doesn't get " +
"in the way of the action when other people watch your camera. This setting can be found in the Chat Settings 'Webcam' tab.",
backgroundDismissable: true,
});
},
@ -185,7 +185,7 @@ export default {
:muted="localVideo"></video>
<!-- Watermark layer -->
<div>
<div :class="{'is-no-watermark': isNoWatermark}">
<img :src="watermarkImage" class="watermark" ref="watermarkImage" oncontextmenu="return false">
<img :src="watermarkImage" class="corner-watermark seethru invert-color" ref="watermarkSmallImage" @click="showWatermarkInfo()" oncontextmenu="return false">
</div>
@ -268,6 +268,9 @@ video {
}
/* Watermark image */
.is-no-watermark {
display: none;
}
.watermark {
position: absolute;
top: 0;

View File

@ -19,6 +19,7 @@ const keys = {
'rememberExpresslyClosed': Boolean,
'autoMuteWebcams': Boolean, // automatically mute other peoples' webcam audio feeds
'videoAutoShare': Boolean, // automatically share your webcam on page load
'videoNoWatermark': Boolean, // user does not want watermark protection
// Booleans
'usePolling': Boolean, // use the polling API instead of WebSocket

View File

@ -8,6 +8,7 @@ const VideoFlag = {
MutualOpen: 1 << 5,
VipOnly: 1 << 6,
Invited: 1 << 7,
NoWatermark: 1 << 8,
};
export default VideoFlag;

View File

@ -75,6 +75,7 @@ class WebRTCController {
mutualOpen: false, // user wants to open video mutually
nonExplicit: false, // user prefers not to see explicit cameras
vipOnly: false, // only show camera to fellow VIP users
noWatermark: false, // user opts out of their own QR code watermark
rememberExpresslyClosed: true, // remember cams we expressly closed
autoMuteWebcams: false, // auto-mute other cameras' audio channels
@ -247,6 +248,12 @@ class WebRTCController {
}
}
},
"webcam.noWatermark": function () {
LocalStorage.set('videoNoWatermark', this.webcam.noWatermark);
if (this.webcam.active) {
this.sendMe();
}
},
"webcam.rememberExpresslyClosed": function () {
LocalStorage.set('rememberExpresslyClosed', this.webcam.rememberExpresslyClosed);
},
@ -273,6 +280,7 @@ class WebRTCController {
if (this.webcam.mutualOpen) status |= this.VideoFlag.MutualOpen;
if (this.webcam.nonExplicit) status |= this.VideoFlag.NonExplicit;
if (this.webcam.vipOnly && this.isVIP) status |= this.VideoFlag.VipOnly;
if (this.webcam.noWatermark) status |= this.VideoFlag.NoWatermark;
return status;
},
anyVideosOpen() {
@ -669,9 +677,13 @@ class WebRTCController {
`My camera is: ${this.webcam.active ? 'active': 'not active'}`,
);
// If the user leaves our watching list, play the sound.
if (this.webcam.watching[msg.username] != undefined) {
this.playSound("Unwatch");
}
// The user has closed our video feed.
delete (this.webcam.watching[msg.username]);
this.playSound("Unwatch");
this.cleanupPeerConnections();
},
sendWatch(username, watching) {
@ -702,6 +714,14 @@ class WebRTCController {
return false;
},
isUsernameCamNoWatermark(username) {
// returns true if the user is broadcasting and has the NoWatermark flag set.
if (this.whoMap[username] != undefined && this.whoMap[username].video & this.VideoFlag.NoWatermark) {
return true;
}
return false;
},
/**********************************
* Front-end methods and handlers *
**********************************/

View File

@ -470,6 +470,37 @@
full screen view.
</p>
<h3 id="watermarks">
<i class="fa fa-qrcode mr-2"></i> What are the QR codes on top of webcams?
<a href="#watermarks" class="fa fa-paragraph is-size-6"></a>
</h3>
<p>
Most webcams will display a QR code in the corner by default, as well as a translucent copy of the
QR code over the center/middle of the video.
</p>
<p>
These QR codes (or 'watermarks') are a safety feature to deter people from screen recording each
other's webcams on here. There is no technical measure that a web page could take to prevent
screen recording from being possible (or to even detect that it is happening), so the QR code
watermarks instead will "tag" the recorded video with the current viewer's username and the
current date.
</p>
<p>
The idea is that if a webcam recording ends up leaked online, the QR code will be captured in
the video and it can be used to trace back <strong>who exactly</strong> recorded that webcam
and when, so that the user may be banned from the chat room and/or be reported to a relevant law
enforcement agency as necessary for spreading non-consensual 'revenge porn' online.
</p>
<p>
<strong>If you do not care about the risk that anyone could record your webcam,</strong> then you
may "opt out" of the QR code watermark being applied to <em>your own</em> video. The setting for
this can be found in the Chat Settings "Camera" tab.
</p>
<hr>
<h1 id="browsers">