From 2305ff54db9be5db4ee0287785f33bb5ea75c093 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sun, 1 Jun 2025 11:59:21 -0700 Subject: [PATCH] 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. --- pkg/messages/messages.go | 1 + src/App.vue | 26 ++++++++++++++++++-------- src/components/VideoFeed.vue | 11 +++++++---- src/lib/LocalStorage.js | 1 + src/lib/VideoFlag.js | 1 + src/lib/WebRTC.js | 22 +++++++++++++++++++++- web/templates/about.html | 31 +++++++++++++++++++++++++++++++ 7 files changed, 80 insertions(+), 13 deletions(-) diff --git a/pkg/messages/messages.go b/pkg/messages/messages.go index ed1cd2a..1477dbf 100644 --- a/pkg/messages/messages.go +++ b/pkg/messages/messages.go @@ -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. diff --git a/src/App.vue b/src/App.vue index 4cdba81..4893770 100644 --- a/src/App.vue +++ b/src/App.vue @@ -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 -

- 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). -

-

@@ -2839,7 +2835,7 @@ export default { -

+

@@ -2854,6 +2850,18 @@ export default { from this device.

+ +
+ +

+ The 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 your own webcam. + Learn more +

+
@@ -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" diff --git a/src/components/VideoFeed.vue b/src/components/VideoFeed.vue index 3aa4868..8b69e0b 100644 --- a/src/components/VideoFeed.vue +++ b/src/components/VideoFeed.vue @@ -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"> -
+
@@ -268,6 +268,9 @@ video { } /* Watermark image */ +.is-no-watermark { + display: none; +} .watermark { position: absolute; top: 0; diff --git a/src/lib/LocalStorage.js b/src/lib/LocalStorage.js index 70d4caa..5644740 100644 --- a/src/lib/LocalStorage.js +++ b/src/lib/LocalStorage.js @@ -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 diff --git a/src/lib/VideoFlag.js b/src/lib/VideoFlag.js index d00499f..5866e66 100644 --- a/src/lib/VideoFlag.js +++ b/src/lib/VideoFlag.js @@ -8,6 +8,7 @@ const VideoFlag = { MutualOpen: 1 << 5, VipOnly: 1 << 6, Invited: 1 << 7, + NoWatermark: 1 << 8, }; export default VideoFlag; diff --git a/src/lib/WebRTC.js b/src/lib/WebRTC.js index 1c047df..ea25b39 100644 --- a/src/lib/WebRTC.js +++ b/src/lib/WebRTC.js @@ -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 * **********************************/ diff --git a/web/templates/about.html b/web/templates/about.html index 19fb8dc..61fe2e5 100644 --- a/web/templates/about.html +++ b/web/templates/about.html @@ -470,6 +470,37 @@ full screen view.

+

+ What are the QR codes on top of webcams? + +

+ +

+ 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. +

+ +

+ 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. +

+ +

+ 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 who exactly 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. +

+ +

+ If you do not care about the risk that anyone could record your webcam, then you + may "opt out" of the QR code watermark being applied to your own video. The setting for + this can be found in the Chat Settings "Camera" tab. +

+