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:
parent
4179cba30a
commit
2305ff54db
|
@ -140,6 +140,7 @@ const (
|
||||||
VideoFlagMutualOpen // viewer wants to auto-open viewers' cameras
|
VideoFlagMutualOpen // viewer wants to auto-open viewers' cameras
|
||||||
VideoFlagOnlyVIP // can only shows as active to VIP members
|
VideoFlagOnlyVIP // can only shows as active to VIP members
|
||||||
VideoFlagInvited // user invites another to watch their camera
|
VideoFlagInvited // user invites another to watch their camera
|
||||||
|
VideoFlagNoWatermark // user opts out of QR code watermark protection
|
||||||
)
|
)
|
||||||
|
|
||||||
// Presence message templates.
|
// Presence message templates.
|
||||||
|
|
26
src/App.vue
26
src/App.vue
|
@ -739,6 +739,9 @@ export default {
|
||||||
if (settings.autoMuteWebcams === true) {
|
if (settings.autoMuteWebcams === true) {
|
||||||
this.webcam.autoMuteWebcams = true;
|
this.webcam.autoMuteWebcams = true;
|
||||||
}
|
}
|
||||||
|
if (settings.videoNoWatermark === true) {
|
||||||
|
this.webcam.noWatermark = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Misc preferences
|
// Misc preferences
|
||||||
if (settings.usePolling != undefined) {
|
if (settings.usePolling != undefined) {
|
||||||
|
@ -2726,13 +2729,6 @@ export default {
|
||||||
Camera Settings
|
Camera Settings
|
||||||
</h3>
|
</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">
|
<p class="block mb-1" v-if="config.permitNSFW">
|
||||||
<label class="label">Explicit webcam options</label>
|
<label class="label">Explicit webcam options</label>
|
||||||
</p>
|
</p>
|
||||||
|
@ -2839,7 +2835,7 @@ export default {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="block mb-1" v-if="webcam.videoDevices.length > 0">
|
<p class="block mb-1">
|
||||||
<label class="label">Miscellaneous</label>
|
<label class="label">Miscellaneous</label>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -2854,6 +2850,18 @@ export default {
|
||||||
from this device.
|
from this device.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<!-- Misc preferences -->
|
<!-- Misc preferences -->
|
||||||
|
@ -3428,6 +3436,7 @@ export default {
|
||||||
:is-source-muted="webcam.muted"
|
:is-source-muted="webcam.muted"
|
||||||
:is-speaking="WebRTC.speaking[username]"
|
:is-speaking="WebRTC.speaking[username]"
|
||||||
:watermark-image="webcam.watermark"
|
:watermark-image="webcam.watermark"
|
||||||
|
:is-no-watermark="webcam.noWatermark"
|
||||||
@mute-video="muteMe()"
|
@mute-video="muteMe()"
|
||||||
@popout="popoutVideo"
|
@popout="popoutVideo"
|
||||||
@open-profile="showProfileModal"
|
@open-profile="showProfileModal"
|
||||||
|
@ -3448,6 +3457,7 @@ export default {
|
||||||
:is-watching-me="isWatchingMe(username)"
|
:is-watching-me="isWatchingMe(username)"
|
||||||
:is-frozen="WebRTC.frozenStreamDetected[username]"
|
:is-frozen="WebRTC.frozenStreamDetected[username]"
|
||||||
:watermark-image="webcam.watermark"
|
:watermark-image="webcam.watermark"
|
||||||
|
:is-no-watermark="isUsernameCamNoWatermark(username)"
|
||||||
@reopen-video="openVideoByUsername"
|
@reopen-video="openVideoByUsername"
|
||||||
@mute-video="muteVideo"
|
@mute-video="muteVideo"
|
||||||
@popout="popoutVideo"
|
@popout="popoutVideo"
|
||||||
|
|
|
@ -13,6 +13,7 @@ export default {
|
||||||
isFrozen: Boolean, // video is detected as frozen
|
isFrozen: Boolean, // video is detected as frozen
|
||||||
isSpeaking: Boolean, // video is registering audio
|
isSpeaking: Boolean, // video is registering audio
|
||||||
watermarkImage: Image, // watermark image to overlay (nullable)
|
watermarkImage: Image, // watermark image to overlay (nullable)
|
||||||
|
isNoWatermark: Boolean, // camera does not want watermark protection
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Slider,
|
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 " +
|
"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 " +
|
"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" +
|
"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 " +
|
"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 " +
|
||||||
"to everybody, and a second (subtle) copy of the code spans across the center/middle of the video and pulsates in " +
|
"in the way of the action when other people watch your camera. This setting can be found in the Chat Settings 'Webcam' tab.",
|
||||||
"transparency over time.",
|
|
||||||
backgroundDismissable: true,
|
backgroundDismissable: true,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -185,7 +185,7 @@ export default {
|
||||||
:muted="localVideo"></video>
|
:muted="localVideo"></video>
|
||||||
|
|
||||||
<!-- Watermark layer -->
|
<!-- Watermark layer -->
|
||||||
<div>
|
<div :class="{'is-no-watermark': isNoWatermark}">
|
||||||
<img :src="watermarkImage" class="watermark" ref="watermarkImage" oncontextmenu="return false">
|
<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">
|
<img :src="watermarkImage" class="corner-watermark seethru invert-color" ref="watermarkSmallImage" @click="showWatermarkInfo()" oncontextmenu="return false">
|
||||||
</div>
|
</div>
|
||||||
|
@ -268,6 +268,9 @@ video {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Watermark image */
|
/* Watermark image */
|
||||||
|
.is-no-watermark {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.watermark {
|
.watermark {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -19,6 +19,7 @@ const keys = {
|
||||||
'rememberExpresslyClosed': Boolean,
|
'rememberExpresslyClosed': Boolean,
|
||||||
'autoMuteWebcams': Boolean, // automatically mute other peoples' webcam audio feeds
|
'autoMuteWebcams': Boolean, // automatically mute other peoples' webcam audio feeds
|
||||||
'videoAutoShare': Boolean, // automatically share your webcam on page load
|
'videoAutoShare': Boolean, // automatically share your webcam on page load
|
||||||
|
'videoNoWatermark': Boolean, // user does not want watermark protection
|
||||||
|
|
||||||
// Booleans
|
// Booleans
|
||||||
'usePolling': Boolean, // use the polling API instead of WebSocket
|
'usePolling': Boolean, // use the polling API instead of WebSocket
|
||||||
|
|
|
@ -8,6 +8,7 @@ const VideoFlag = {
|
||||||
MutualOpen: 1 << 5,
|
MutualOpen: 1 << 5,
|
||||||
VipOnly: 1 << 6,
|
VipOnly: 1 << 6,
|
||||||
Invited: 1 << 7,
|
Invited: 1 << 7,
|
||||||
|
NoWatermark: 1 << 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default VideoFlag;
|
export default VideoFlag;
|
||||||
|
|
|
@ -75,6 +75,7 @@ class WebRTCController {
|
||||||
mutualOpen: false, // user wants to open video mutually
|
mutualOpen: false, // user wants to open video mutually
|
||||||
nonExplicit: false, // user prefers not to see explicit cameras
|
nonExplicit: false, // user prefers not to see explicit cameras
|
||||||
vipOnly: false, // only show camera to fellow VIP users
|
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
|
rememberExpresslyClosed: true, // remember cams we expressly closed
|
||||||
autoMuteWebcams: false, // auto-mute other cameras' audio channels
|
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 () {
|
"webcam.rememberExpresslyClosed": function () {
|
||||||
LocalStorage.set('rememberExpresslyClosed', this.webcam.rememberExpresslyClosed);
|
LocalStorage.set('rememberExpresslyClosed', this.webcam.rememberExpresslyClosed);
|
||||||
},
|
},
|
||||||
|
@ -273,6 +280,7 @@ class WebRTCController {
|
||||||
if (this.webcam.mutualOpen) status |= this.VideoFlag.MutualOpen;
|
if (this.webcam.mutualOpen) status |= this.VideoFlag.MutualOpen;
|
||||||
if (this.webcam.nonExplicit) status |= this.VideoFlag.NonExplicit;
|
if (this.webcam.nonExplicit) status |= this.VideoFlag.NonExplicit;
|
||||||
if (this.webcam.vipOnly && this.isVIP) status |= this.VideoFlag.VipOnly;
|
if (this.webcam.vipOnly && this.isVIP) status |= this.VideoFlag.VipOnly;
|
||||||
|
if (this.webcam.noWatermark) status |= this.VideoFlag.NoWatermark;
|
||||||
return status;
|
return status;
|
||||||
},
|
},
|
||||||
anyVideosOpen() {
|
anyVideosOpen() {
|
||||||
|
@ -669,9 +677,13 @@ class WebRTCController {
|
||||||
`My camera is: ${this.webcam.active ? 'active': 'not active'}`,
|
`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.
|
// The user has closed our video feed.
|
||||||
delete (this.webcam.watching[msg.username]);
|
delete (this.webcam.watching[msg.username]);
|
||||||
this.playSound("Unwatch");
|
|
||||||
this.cleanupPeerConnections();
|
this.cleanupPeerConnections();
|
||||||
},
|
},
|
||||||
sendWatch(username, watching) {
|
sendWatch(username, watching) {
|
||||||
|
@ -702,6 +714,14 @@ class WebRTCController {
|
||||||
return false;
|
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 *
|
* Front-end methods and handlers *
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
|
@ -470,6 +470,37 @@
|
||||||
full screen view.
|
full screen view.
|
||||||
</p>
|
</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>
|
<hr>
|
||||||
|
|
||||||
<h1 id="browsers">
|
<h1 id="browsers">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user