Last active
February 1, 2024 08:30
-
-
Save marek-saji/184024f096be7b9ddf54272d6d225af8 to your computer and use it in GitHub Desktop.
userscript: Zoom Web Client with less clicking
This file contains hidden or 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
// ==UserScript== | |
// @name Zoom Web Client with less clicking | |
// @description Make using Web Client in Zoom a default and require less clicking. | |
// @author Marek ‘saji’ Augustynowicz <[email protected]> | |
// @copyright ISC | |
// @version 1.0.3 | |
// @icon https://st1.zoom.us/zoom.ico | |
// @supportURL https://gist.github.com/marek-saji/184024f096be7b9ddf54272d6d225af8 | |
// | |
// @updateURL https://gist.githubusercontent.com/marek-saji/184024f096be7b9ddf54272d6d225af8/raw | |
// @downloadURL https://gist.githubusercontent.com/marek-saji/184024f096be7b9ddf54272d6d225af8/raw | |
// @grant none | |
// @match https://*.zoom.us/j/* | |
// @match https://*.zoom.us/wc/*/join?* | |
// @match https://*.zoom.us/wc/join/* | |
// ==/UserScript== | |
const JOB_DEBOUNCE_MS = 100; | |
const JOB_MAX_TRIES = 10; | |
function log (...args) | |
{ | |
console.debug('zoom.userscript', ...args); | |
} | |
function debounce (callback) | |
{ | |
let timeoutId; | |
return () => { | |
clearTimeout(timeoutId); | |
timeoutId = setTimeout( | |
() => { callback(); }, | |
JOB_DEBOUNCE_MS | |
); | |
} | |
} | |
/** | |
* Things we want to do rely on DOM elements be present. Re–try wevery time DOM is mutated. | |
* Will stop trying when {@param job} returns true or after trying {@see JOB_MAX_TRIES} times. | |
*/ | |
function tryUntilItWorks (jobs) | |
{ | |
const jobsName = jobs.map(job => job.name).join('+'); | |
log(jobsName, 'queued'); | |
const runJobs = () => { | |
for (const job of jobs) | |
{ | |
log(job.name, 'runs'); | |
if (job()) { | |
log(job.name, 'succeeded'); | |
return true; | |
} | |
} | |
}; | |
if (!runJobs()) | |
{ | |
let tries = 0; | |
const observer = new MutationObserver(debounce(() => { | |
tries += 1; | |
if (tries > JOB_MAX_TRIES) | |
{ | |
log(jobsName, 'tried to run', JOB_MAX_TRIES, 'times without a success. Giving up.'); | |
observer.disconnect(); | |
} | |
else if (runJobs()) | |
{ | |
observer.disconnect(); | |
} | |
})); | |
observer.observe(document.documentElement, { | |
childList: true, | |
subtree: true, | |
}); | |
} | |
} | |
/** | |
* Click “Continue in Browser” | |
*/ | |
function preJoin () | |
{ | |
const joinFromBrowser = document.querySelector('[web_client]'); | |
if (joinFromBrowser) | |
{ | |
joinFromBrowser.click(); | |
return true; | |
} | |
} | |
/** | |
* Escape a full–page iframe 🙄 | |
*/ | |
function escapeIFrame () | |
{ | |
const iframe = document.querySelector('iframe#webclient'); | |
if (iframe?.src) | |
{ | |
window.location.href = iframe.src; | |
return true; | |
} | |
} | |
/** | |
* Make sure audio aud video are enabled and join | |
*/ | |
function join () | |
{ | |
const audioButton = document.getElementById('preview-audio-control-button'); | |
const videoButton = document.getElementById('preview-video-control-button'); | |
const joinButton = document.querySelector('.preview-join-button'); | |
if (audioButton && videoButton && joinButton) | |
{ | |
if (audioButton.getAttribute('aria-label') === 'Unmute') | |
{ | |
audioButton.click(); | |
} | |
if (videoButton.getAttribute('aria-label') === 'Start Video') | |
{ | |
videoButton.click(); | |
} | |
joinButton.click(); | |
tryUntilItWorks([setup]); | |
return true; | |
} | |
} | |
/** | |
* Post–join setup for things Zoom WebClient can’t remember | |
* - Mirror video | |
* - Grid view | |
*/ | |
function setup () | |
{ | |
// video mirror and grid view options might be rendered only after we open menus they are in for the first time | |
// click menu buttons twice to open and close them, which will trigger the render | |
const videoMenuButton = document.querySelector('[aria-label="More video controls"]'); | |
const viewMenuButton = document.querySelector('[aria-label="View"]'); | |
videoMenuButton?.click(); videoMenuButton?.click(); | |
viewMenuButton?.click(); viewMenuButton?.click(); | |
let videoMirrorButton = document.querySelector('[aria-label="Mirror My Video"]'); | |
let galleryViewButton = document.querySelector('[aria-label="Gallery View"]'); | |
if (videoMirrorButton && galleryViewButton) | |
{ | |
if (!videoMirrorButton.classList.contains('video-option-menu__pop-menu--checked')) | |
{ | |
videoMirrorButton.click(); | |
} | |
if (!galleryViewButton.classList.contains('full-screen-widget__pop-menu--checked')) | |
{ | |
galleryViewButton.click(); | |
} | |
return true; | |
} | |
} | |
tryUntilItWorks([preJoin, escapeIFrame, join, setup]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment