1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
// ==UserScript==
// @name Google Meet mute indicator
// @namespace unforgivenexception.com
// @version 1.0
// @description Updates the favicon and shows a mute indicator on screen
// @author Paulo Amaral
// @match https://meet.google.com/*
// @grant none
// ==/UserScript==
(function() {
// The emojis that will indicate the state. They will replace the favicon of
// the window. The mute emoji will be displayed large on top of everything
// when on mute.
window.emojiMute = "🙊";
window.emojiSpeaking = "🔊";
// Interval (milliseconds) in which the function to update the UI will be
// repeatedly called
window.intervalUpdateUI = 500;
// Returns a Boolean indicating whether the mute state is activated
function isMute() {
// TODO: optimize me - instead of searching the DOM everytime, find
// element and check the property data-is-muted directly.
return document.querySelectorAll("div[data-is-muted]")[1].getAttribute("data-is-muted") == "true"
}
// Update the window favicon according to the mute state, replacing it with
// the emojis defined on the begining of this code.
function updateFavicon(muteState) {
// Uses a <link rel="icon"> element to set the favicon
// with a inline svg
var id = "faviconLinkElement";
var linkElement = document.getElementById(id);
if (linkElement == null) {
// <link> element not available yet, so creates one.
var headElement = document.getElementsByTagName('head')[0];
linkElement = document.createElement('link');
linkElement.id = (id);
linkElement.rel = "icon";
headElement.appendChild(linkElement);
}
// change the <link> element href to manipulate the favicon
var emoji = (muteState)?window.emojiMute:window.emojiSpeaking;
linkElement.href = "data:image/svg+xml,<svg xmlns=%22http://www.w3.org"+
"/2000/svg%22 viewBox=%220 0 100 100%22><text y=%221em%22 "+
"font-size=%2280%22>"+emoji+"</text></svg>";
}
// Show/hide the floating indicator for mute status (true = show)
function updateFloatingIndicator(muteState) {
var id = "muteIndicator";
var divElement = document.getElementById(id);
if (divElement == null) {
var bodyElement = document.getElementsByTagName('body')[0];
divElement = document.createElement("div");
divElement.id = id;
divElement.style.zIndex = 9999;
divElement.style.display = "none";
divElement.style.position = "absolute";
divElement.style.border = "4px solid black";
divElement.style.borderRadius = "50%";
divElement.style.width = "30vh";
divElement.style.height = "30vh";
divElement.style.textAlign = "center";
divElement.style.backgroundColor = "#ff0000";
divElement.style.opacity = "0.7";
divElement.style.marginLeft = "1vh"
divElement.style.marginTop = "1vh"
var spanElement = document.createElement("span");
spanElement.innerHTML = window.emojiMute;
spanElement.style.fontSize = "20vh"; // 20% of viewport height
divElement.appendChild(spanElement);
bodyElement.appendChild(divElement);
}
divElement.style.display = (muteState)?"block":"none";
}
// This is the main function, which will check the mute state and
// call UI updates accordingly. This function is idempotent.
function updateUI() {
// console.log ("mute indicator updateUI() - ping 💧");
// window.interfaceMuted is the variable used to manage idempotency.
// When it is "undefined", it means the code is running for the first
// time and a UI update is required regardless the current state.
if (isMute()) {
if (!window.interfaceMuted ||
typeof window.interfaceMuted === "undefined") {
// console.log ("YOU ARE MUTED " + window.emojiMute);
updateFavicon(true);
updateFloatingIndicator(true);
window.interfaceMuted = true;
}
} else {
if (window.interfaceMuted ||
typeof window.interfaceMuted === "undefined") {
// console.log ("YOU ARE SPEAKING " + window.emojiSpeaking);
updateFavicon(false);
updateFloatingIndicator(false);
window.interfaceMuted = false;
}
}
}
// Auxiliar function to shutdown UI updates. Must be called manually. States
// and updates won't be reverted, they will just stop happening.
function abortUpdateUI() {
if (window.timerCheckMuteState) {
clearInterval(window.timerCheckMuteState)
}
}
// Run the abort function before kicking off UI updates for idempotency
// purposes. Just in case this code was already running and it is being
// executed again.
abortUpdateUI();
// Runs UI updates repeatedly. Call the function abortUpdateUI()
// in the console to abort.
// TODO: optimize me - call UI updates a few milisseconds after mute buton
// is clicked intead of in a loop.
window.timerCheckMuteState = setInterval(updateUI, window.intervalUpdateUI);
})();
|