Skip to content

Instantly share code, notes, and snippets.

@creasty
Last active August 17, 2022 11:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creasty/1292282bde05b70942b7d5244c0e2608 to your computer and use it in GitHub Desktop.
Save creasty/1292282bde05b70942b7d5244c0e2608 to your computer and use it in GitHub Desktop.
Google Meet Automation (using 'User JavaScript and CSS')

What does it do?

The script automates the following actions.

  1. Mute the camera
  2. Mute the mic — Opted-out by default
  3. Join the meeting
  4. If the meeting title matches a certain pattern, remind you to start recording by opening 'Activities Panel'.
    Activities Panel Screen Shot 2022-05-24 at 14 01 21
  5. Dismiss "Are you still there?" dialog
    Dialog Screen Shot 2022-06-09 at 11 23 16

How to use

  1. Install User JavaScript and CSS extension
  2. Go to the extension options page:
  3. Click on 'Add new site':
  4. Enter name and domain:
  5. Copy & paste the script, and 'Save'
(async () => {
await autoMuteCamera();
// await autoMuteMic();
await autoJoin();
remindToStartRecording(/録画|design sync-?up|輪読会|ブリーフィング|briefing/i);
stayJoined();
})();
//=== Util
//==============================================================================================
async function mut(fn) {
return new Promise((resolve) => {
const observer = new MutationObserver(() => {
const result = fn();
if (typeof result === "undefined") return;
observer.disconnect();
resolve(result);
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
}
async function findAllNodesAsync(selector, filterFn) {
const find = () => {
const nodes = [...document.body.querySelectorAll(selector)];
if (nodes.length === 0) return;
if (filterFn) {
const filtered = nodes.filter(filterFn);
if (filtered.length === 0) return;
return filtered;
}
return nodes;
};
return find() ?? mut(find);
}
async function findNodeAsync(selector, filterFn) {
const nodes = await findAllNodesAsync(selector, filterFn);
return nodes[0];
}
async function getMeetingTitle() {
const id = window.location.pathname.substr(1);
const getTitle = () => {
const m = document.title.match(/^Meet - (.+)$/);
const titleOrId = m?.[1];
if (!titleOrId || titleOrId === id) return;
return titleOrId;
};
return new Promise((resolve) => {
const tick = () => {
const title = getTitle();
if (title) return resolve(title);
setTimeout(tick, 50);
};
tick();
});
}
//=== Actions
//==============================================================================================
async function autoMuteCamera() {
const btn = await findNodeAsync(`div[role="button"][aria-label*="camera"][data-is-muted]`);
if (btn.dataset.isMuted !== "false") return;
btn.click();
console.log("[autoMuteCamera] activated");
}
async function autoMuteMic() {
const btn = await findNodeAsync(`div[role="button"][aria-label*="microphone"][data-is-muted]`);
if (btn.dataset.isMuted !== "false") return;
btn.click();
console.log("[autoMuteMic] activated");
}
async function autoJoin() {
await getMeetingTitle();
await mut(() => {
const el = document.querySelector(`[role="heading"][aria-level="1"]`);
if (!el) return;
const title = el.innerText;
if (!title || title.includes("Ready to join?")) return;
return true;
});
const joinButton = await findNodeAsync(`button`, (node) => node.innerText.includes("Join now"));
joinButton.click();
console.log("[autoJoin] activated");
}
async function remindToStartRecording(meetingTitlePattern) {
const title = await getMeetingTitle();
if (!meetingTitlePattern.test(title)) return;
const activitiesButton = await findNodeAsync(`button[aria-label="Activities"]`);
activitiesButton.click();
console.log("[remindToStartRecording] activated");
}
async function stayJoined() {
const dialog = await findNodeAsync(`div[aria-modal][role="dialog"][aria-label="Are you still there?"]`);
const btn = dialog.querySelector(`button[data-mdc-dialog-button-default]`); // "Stay in the call"
btn.click();
console.log("[stayJoined] activated");
setTimeout(stayJoined, 1 * 60 * 1000); // Rerun every minutes
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment