Last active
October 1, 2022 03:40
-
-
Save vegerot/5ac0405f2166e7b2c5470b07e0c56710 to your computer and use it in GitHub Desktop.
Notify you when someone in a Zoom call says something
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Steps to use this: | |
1. Join a Zoom call from the web | |
2. Enable Live Transcription | |
3. Open the console (Cmd + Opt + J) | |
4. Paste this code into the console | |
*/ | |
// In order to be able to paste this script multiple times in the console, | |
// check if it's already been defined and disconnect it | |
var observeDomNodeAdditions; | |
if (typeof observeDomNodeAdditions !== 'undefined') observeDomNodeAdditions.disconnect() | |
observeDomNodeAdditions = new MutationObserver(mutations => { | |
for (let mutation of mutations) { | |
for (let addedNode of Array.from(mutation.addedNodes)) { | |
if (addedNode instanceof HTMLElement) { | |
// unfortunately these are the only details we get | |
if (addedNode.tagName === 'DIV') { | |
// it takes a few frames for the transcript node to appear after this node appears | |
setTimeout(() => { | |
// makes TypeScript happy | |
if (!(addedNode instanceof HTMLElement)) { | |
throw new Error('impossible') | |
} | |
let subtitlesElement = addedNode.querySelector('#live-transcription-subtitle'); | |
if (subtitlesElement) { | |
observeTranscriptTextChanges.observe(subtitlesElement, {characterData: true, subtree: true}) | |
} | |
}, 100) | |
} | |
} | |
} | |
for (let removedNode of Array.from(mutation.removedNodes)) { | |
if (removedNode instanceof HTMLElement) { | |
if (removedNode.querySelector('#live-transcription-subtitle')) { | |
console.log("removed", {removedNode}) | |
observeTranscriptTextChanges.disconnect() | |
} | |
} | |
} | |
} | |
}) | |
/** | |
When somebody's talking | |
```html | |
<div class="meeting-client-inner"> | |
<div id="wc-content"></div> | |
<div | |
class="join-dialog" | |
role="presentation" | |
style="bottom: 52px; width: 1792px;" | |
></div> | |
<div></div> | |
<div> | |
<div | |
class="live-transcription-subtitle__box react-draggable" | |
style="touch-action: none; bottom: 68px; transform: translate(0px, 0px);" | |
> | |
<div | |
id="live-transcription-subtitle" | |
class="live-transcription-subtitle__item" | |
> | |
Would someone from List Service please respond? | |
</div> | |
</div> | |
</div> | |
<div></div> | |
</div>; | |
``` | |
When nobody's talking | |
```html | |
<div class="meeting-client-inner"> | |
<div id="wc-content"></div> | |
<div | |
class="join-dialog" | |
role="presentation" | |
style="bottom: 52px; width: 1792px;" | |
></div> | |
</div>; | |
``` | |
*/ | |
observeDomNodeAdditions.observe(document.querySelector('.meeting-client-inner'), {childList: true, subtree: true, }) | |
let keywords = [ | |
"list", | |
"regist", | |
"regest", | |
"heart", | |
"favorite" | |
] | |
let observeTranscriptTextChanges = new MutationObserver(mutations => { | |
for (let mutation of mutations) { | |
let text = mutation.target.textContent | |
if (text) { | |
respondToKeyWords(text) | |
} | |
} | |
}) | |
function respondToKeyWords(text) { | |
for (let keyword of keywords) { | |
if (text.toLowerCase().includes(keyword)) { | |
let msg = new SpeechSynthesisUtterance(`I heard the word`) | |
debouncedSpeak(msg) | |
debouncedLog(text) | |
} | |
} | |
} | |
function debounce(func, timeout = 1000){ | |
let timer = 0; | |
return function(...args) { | |
clearTimeout(timer); | |
timer = setTimeout(() => { func.apply(this, args); }, timeout); | |
}; | |
} | |
let debouncedSpeak = debounce((...args)=>window.speechSynthesis.speak(...args), 1000) | |
let debouncedLog = debounce((...args)=>console.log(...args), 1000) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment