Google Meet Auto Starter + Link Copier (Popup Version)

Adds a button to auto-start a Google Meet and smoothly copy the link, then auto-close the dialog, blocking "Unable to copy" popups

// ==UserScript==
// @name         Google Meet Auto Starter + Link Copier (Popup Version)
// @namespace    Shawon
// @version      2.3
// @description  Adds a button to auto-start a Google Meet and smoothly copy the link, then auto-close the dialog, blocking "Unable to copy" popups
// @author       Mahmudul Hasan Shawon
// @match        https://meet.google.com/landing
// @match        https://meet.google.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant        GM_setClipboard
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  // Block any popup containing "Unable to copy"
  const observer = new MutationObserver((mutations) => {
    mutations.forEach(mutation => {
      mutation.addedNodes.forEach(node => {
        if (node.nodeType === 1) { // Element node
          if (node.innerText && node.innerText.includes("Unable to copy")) {
            // Hide or remove the popup immediately
            node.style.display = 'none';
            console.log('[MeetBot] Blocked "Unable to copy" popup.');
          }
        }
      });
    });
  });

  // Start observing document.body for added popup nodes
  observer.observe(document.body, { childList: true, subtree: true });

  // Also override alert to block "Unable to copy" alerts if they appear as alert()
  const originalAlert = window.alert;
  window.alert = function(msg) {
    if (typeof msg === 'string' && msg.includes('Unable to copy')) {
      console.log('[MeetBot] Blocked alert:', msg);
      return; // Ignore this alert
    }
    return originalAlert(msg);
  };

  const sleep = (ms) => new Promise(r => setTimeout(r, ms));

  const waitForElement = (selector, timeout = 15000) =>
    new Promise((resolve, reject) => {
      const interval = 250;
      let elapsed = 0;
      const timer = setInterval(() => {
        const el = document.querySelector(selector);
        if (el) {
          clearInterval(timer);
          resolve(el);
        }
        elapsed += interval;
        if (elapsed >= timeout) {
          clearInterval(timer);
          reject(new Error("Timeout waiting for: " + selector));
        }
      }, interval);
    });

  function showToast(message = '✅ Link copied!', duration = 3000) {
    const toast = document.createElement('div');
    toast.innerText = message;

    Object.assign(toast.style, {
      position: 'fixed',
      top: '3rem',
      left: '50%',
      transform: 'translateX(-50%) scale(0.95)',
      background: 'rgba(26, 115, 232, 0.9)',
      color: 'white',
      padding: '12px 24px',
      borderRadius: '12px',
      fontSize: '15px',
      fontWeight: '600',
      zIndex: '99999',
      opacity: '0',
      transition: 'opacity 0.4s ease, transform 0.4s ease',
      backdropFilter: 'blur(6px)',
      boxShadow: '0 8px 20px rgba(0, 0, 0, 0.2)',
      pointerEvents: 'none',
      fontFamily: 'Inter, sans-serif',
      userSelect: 'none',
    });

    document.body.appendChild(toast);

    requestAnimationFrame(() => {
      toast.style.opacity = '1';
      toast.style.transform = 'translateX(-50%) scale(1)';
    });

    setTimeout(() => {
      toast.style.opacity = '0';
      toast.style.transform = 'translateX(-50%) scale(0.95)';
      setTimeout(() => toast.remove(), 400);
    }, duration);
  }

  async function startMeetAndCopyLink() {
    try {
      console.log('[MeetBot] Starting...');
      const newMeetingBtn = await waitForElement('span[jsname="V67aGc"]');
      newMeetingBtn.click();
      await sleep(500);

      const instantMeetingBtn = await waitForElement('li[aria-label="Start an instant meeting"]');
      instantMeetingBtn.click();
      await sleep(3000);

      copyLinkFromMeet();
    } catch (err) {
      console.error('[MeetBot] Error:', err);
    }
  }

  async function copyLinkFromMeet() {
    try {
      const dialog = await waitForElement('div[role="dialog"]');
      await sleep(1000);

      const linkDiv = await waitForElement('.gk1DN .DwOtV');
      const meetLink = linkDiv?.textContent?.trim();

      if (meetLink && meetLink.startsWith('meet.google.com/')) {
        GM_setClipboard(meetLink);
        showToast(`📋 Copied: ${meetLink}`);
        console.log('[MeetBot] Link copied:', meetLink);

        // Click the "Copy link" button if present (optional)
        const copyBtn = document.querySelector('button[aria-label="Copy link"]');
        if (copyBtn) copyBtn.click();

        // Close the dialog after a short delay
        const closeBtn = dialog.querySelector('button[aria-label="Close"]');
        if (closeBtn) {
          await sleep(700); // nice delay before closing
          closeBtn.click();
          console.log('[MeetBot] Dialog closed.');
        } else {
          console.warn('[MeetBot] Close button not found.');
        }

      } else {
        console.warn('[MeetBot] No valid link found.');
      }
    } catch (err) {
      console.error('[MeetBot] Copy Error:', err.message);
    }
  }

  function createFloatingButton() {
    const btn = document.createElement('button');
    btn.innerText = '▶ Start Meet & Copy Link';
    Object.assign(btn.style, {
      position: 'fixed',
      bottom: '8rem',
      left: '7rem',
      padding: '12px 18px',
      background: '#1a73e8',
      color: 'white',
      border: 'none',
      borderRadius: '8px',
      fontSize: '14px',
      fontWeight: 'bold',
      cursor: 'pointer',
      zIndex: '9999',
      boxShadow: '0 4px 8px rgba(0,0,0,0.2)',
      userSelect: 'none',
      fontFamily: 'Inter, sans-serif',
    });
    btn.title = 'Click to start a Meet and auto-copy the link';
    btn.addEventListener('click', startMeetAndCopyLink);
    document.body.appendChild(btn);
  }

  window.addEventListener('load', () => {
    if (location.pathname === '/landing') {
      createFloatingButton();
    } else if (location.hostname === 'meet.google.com') {
      setTimeout(copyLinkFromMeet, 3000);
    }
  });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址