// ==UserScript== // @name Zoom link upgrader // @author AZ // @description swap http Zoom meeting links to zoommtg:// links // @downloadURL https://raw.githubusercontent.com/hamidzr/user-scripts/refs/heads/master/userscripts/calendar.google.com/zoom-links.user.js // @grant none // @match https://calendar.google.com/* // @namespace https://latentbyte.com/products // @run-at document-idle // @updateURL https://raw.githubusercontent.com/hamidzr/user-scripts/refs/heads/master/userscripts/calendar.google.com/zoom-links.user.js // @version 0.2.0 // ==/UserScript== 'use strict'; (() => { var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __hasOwnProp = Object.prototype.hasOwnProperty; function __accessProp(key) { return this[key]; } var __toCommonJS = (from) => { var entry = (__moduleCache ??= new WeakMap).get(from), desc; if (entry) return entry; entry = __defProp({}, "__esModule", { value: true }); if (from && typeof from === "object" || typeof from === "function") { for (var key of __getOwnPropNames(from)) if (!__hasOwnProp.call(entry, key)) __defProp(entry, key, { get: __accessProp.bind(from, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } __moduleCache.set(from, entry); return entry; }; var __moduleCache; // src/calendar.google.com/zoom-links.user.ts var exports_zoom_links_user = {}; // src/lib/dom-observe.ts var DEFAULT_INIT = { childList: true, subtree: true }; var observeDomChanges = (run, opts) => { let timer = null; let disconnectTimer = null; let currentTarget = opts?.root ?? null; let currentInit = opts?.observerInit ?? DEFAULT_INIT; const disconnect = () => { if (timer) { window.clearTimeout(timer); timer = null; } if (disconnectTimer) { window.clearTimeout(disconnectTimer); disconnectTimer = null; } observer.disconnect(); }; const refreshDisconnectTimer = () => { if (disconnectTimer) window.clearTimeout(disconnectTimer); if (!opts?.disconnectAfterMs) return; disconnectTimer = window.setTimeout(() => { disconnect(); }, opts.disconnectAfterMs); }; const scheduleRun = () => { if (timer) window.clearTimeout(timer); const debounceMs = opts?.debounceMs ?? 0; if (debounceMs <= 0) { run(); refreshDisconnectTimer(); return; } timer = window.setTimeout(() => { timer = null; run(); refreshDisconnectTimer(); }, debounceMs); }; const observer = new MutationObserver((mutations) => { if (opts?.shouldRun && !opts.shouldRun(mutations)) return; scheduleRun(); }); const observe = (target, options) => { const nextTarget = target ?? currentTarget ?? document.body; if (!nextTarget) return; currentTarget = nextTarget; currentInit = options ?? currentInit; observer.disconnect(); observer.observe(nextTarget, currentInit); refreshDisconnectTimer(); }; if (opts?.runImmediately) scheduleRun(); return { disconnect, observe }; }; // src/calendar.google.com/zoom-links.user.ts var sels = { zoomLinks: 'a[href*="zoom.us/j/"]' }; var buildZoomHref = (meetingNumber) => `zoommtg://zoom.us/join?action=join&confno=${meetingNumber}`; var meetingNumberRe = /(?<=zoom.us\/j\/)\d+/i; var upgradeZoomLinks = () => { const zooms = Array.from(document.querySelectorAll(sels.zoomLinks)); for (const zoomA of zooms) { if (zoomA.href.startsWith("zoommtg://")) continue; const meetingNumber = zoomA.href.match(meetingNumberRe); if (meetingNumber) zoomA.href = buildZoomHref(meetingNumber[0]); } }; upgradeZoomLinks(); var observer = observeDomChanges(upgradeZoomLinks, { debounceMs: 300 }); observer.observe(document.body, { childList: true, subtree: true }); })();