ZoomBot.

Pool nhiều bot Chrome tự join Zoom meeting, điều khiển qua HTTP API và tự khởi động lại khi crash — Python + Selenium + Flask, mỗi bot là một Chrome riêng, lock riêng, thread-safe.

Year2025
RoleSolo · system design + python
Timeline8 tuần
Status● Live · self-hosted

01.Overview

Tổng quan

Zoom-bot ra đời từ một câu hỏi rất đơn giản từ một người bạn: "Có thể cho nhiều account tự join Zoom cùng lúc được không?". Từ đó tôi bắt đầu thử nghiệm automation trên Chrome để mô phỏng nhiều participant join vào cùng một meeting. Sau nhiều lần tuning về browser profile, resource usage và network stability, hệ thống chạy ổn định 20 bot đồng thời trên một máy — miễn là mạng đủ ổn định.

Toàn bộ được gói vào một process Python duy nhất: main.py spawn N bot (mỗi bot một Chrome + user-data-dir tạm), một health loop daemon chạy mỗi 20 giây để tự restart bot chết, và một Flask API để điều khiển từ xa. Phiên bản v0.4 chạy ổn định nhiều giờ liền với 20 bot song song, mỗi bot tiêu thụ khoảng ~100MB RAM.

02.Features

Tính năng
  • 01
    Pool Chrome độc lậpOne Chrome · one tempdir · one lock

    Mỗi bot là một webdriver.Chrome độc lập với --user-data-dir trỏ vào một thư mục tạm riêng từ tempfile.mkdtemp — profile trình duyệt hoàn toàn tách biệt, không dùng chung bất kỳ thứ gì. Mỗi bot giữ một RLock riêng, đảm bảo 2 request vào cùng một bot tự nối tiếp nhau thay vì tranh chấp driver. Chrome của bot này crash không kéo bất kỳ bot nào khác xuống theo.

  • 02
    HTTP control planeFlask · chat · chat-all · mic · video · leave · rejoin

    Flask 3 chạy ở chế độ threaded, phục vụ toàn bộ các endpoint điều khiển: POST /chat gửi tin nhắn tới một bot cụ thể theo tên, POST /chat-all broadcast song song tới toàn bộ pool qua ThreadPoolExecutor. POST /bots/<name>/mic/video toggle mic và camera từng bot, /leave/rejoin điều khiển trạng thái meeting. GET /bots trả về danh sách toàn bộ bot kèm trạng thái hiện tại, /health cho biết hệ thống còn sống.

  • 03
    Health check & auto-restart20s loop · rate-limit · backoff

    Một daemon thread chạy ngầm, quét toàn bộ slot mỗi 20 giây để kiểm tra sức khoẻ từng bot bằng cách đọc driver.titlecurrent_url. Nếu bot không phản hồi hoặc trả về giá trị bất thường, _restart_slot được gọi — Chrome cũ bị kill, một instance mới mở lên và join lại meeting. Để tránh vòng lặp restart vô tận khi một bot liên tục crash, hệ thống dùng sliding window 1 giờ: vượt ngưỡng MAX_RESTART_PER_HOUR=5 thì slot bị đánh dấu disabled=true và dừng hẳn cho đến khi có can thiệp tay.

  • 04
    Random mic/video / botmicro_video_random · per-instance prefs

    Bật micro_video_random=true để kích hoạt chế độ mô phỏng thực tế hơn: mỗi lần bot spawn — kể cả khi restart sau crash — _pick_av_state() random độc lập trạng thái mic và video cho từng bot. Chrome prefs ALLOW/BLOCK được build riêng theo từng instance, không share giữa các bot. Kết quả là một meeting với mix tự nhiên giữa người bật mic, tắt mic, bật camera, tắt camera — gần với hành vi thực tế của nhiều người dùng thật hơn là một pool bot đồng nhất.

  • 05
    Dashboard pollingVanilla HTML · poll /bots · per-bot controls

    Một file dashboard.html tĩnh, không cần build, poll /bots/health mỗi vài giây để hiển thị toàn bộ trạng thái pool theo thời gian thực. Mỗi bot hiện thị trạng thái alive / disabled / manual_offline, trạng thái mic và video hiện tại, số lần restart trong giờ gần nhất — và một hàng nút để toggle mic, toggle video, leave hoặc rejoin từng bot ngay tại chỗ. Mở trình duyệt lên là dùng được, không cần cài thêm gì.

03.Tech stack

Công nghệ sử dụng
LanguagePython 3.8+ · type hints · dataclasses (BotSlot)
BrowserSelenium 4.6+ · Chrome headless=new · Selenium Manager (auto chromedriver) · --user-data-dir tạm / bot
APIFlask 3 (threaded=True) · JSON in/out · ThreadPoolExecutor cho /chat-all
Concurrencymain thread (entry + hotkey) · daemon health loop · Flask worker threads · per-bot RLock · stop_flag (Event) cho shutdown trật tự
ReliabilityHealth probe (driver.title + current_url) · auto-restart · rate-limit 5/h sliding window · screenshot + DOM dump khi join fail
Dev toolskeyboard (hotkey Alt+Ctrl+Shift+E thoát) · logging (console INFO + file DEBUG) · dump_after_join để cập nhật selector

04.How it works

Kiến trúc tổng thể

Mô hình threading gọn nhưng phải đúng thứ tự: main thread chạy hotkey loop chờ tín hiệu thoát; một daemon health-loop quét toàn bộ slot mỗi 20 giây; một daemon Flask phục vụ HTTP với threaded=True. Mọi thao tác Selenium đi qua ZoomBot.lock — RLock riêng theo từng bot — đảm bảo 2 request /chat vào cùng một bot tự nối tiếp nhau. /chat-all dùng ThreadPoolExecutor bắn song song mà vẫn an toàn vì mỗi worker chiếm lock của bot riêng mình.

Phần khó nhất là set mic và video sau khi join: Zoom Web Client gắn trạng thái vào aria-label của button — mute my microphone nghĩa là mic đang ON, unmute my microphone nghĩa là đang OFF. Match phải dùng substring và check 'unmute' trước 'mute' — vì 'unmute' chứa chuỗi 'mute' bên trong. Bug này từng khiến mic luôn enabled bất chấp config ở v0.3, được sửa ở v0.4. Khi WebElement.click() không trigger được React headless, fallback là JS click.

Design decision

"Phần tốn thời gian nhất khi xây ZoomBot không phải spawn Chrome hay viết Flask API — mà là đọc đúng trạng thái mic từ aria-label. Zoom Web Client không expose state qua attribute rõ ràng, không có data attribute, không có class toggle — chỉ có một chuỗi text trong label thay đổi tuỳ ngôn ngữ và tuỳ version. Bug ở v0.3 nằm đúng ở chỗ đó: check 'mute' trước 'unmute' nên mic luôn được đọc là ON. Một ký tự prefix, vài giờ debug."

05.Bình luận

Ý kiến của bạn

Chưa có bình luận nào.

Xem tiep
python-ocr preview
O
Captcha OCR

CaptchaOCR là một micro-service FastAPI nhận ảnh captcha 4 chữ số dưới dạng base64 và trả về số nguyên tương ứng. Model ddddocr pretrained được load một lần duy nhất lúc process khởi động — mọi request sau đó chỉ là inference, latency vài chục ms mỗi ảnh. Service deploy bằng PM2 với auto-restart và giới hạn RAM cứng, đảm bảo chạy ổn định dài hạn mà không cần giám sát thủ công.

trading-signals preview
T
Trading Signals

TradingSignals là công cụ phân tích tín hiệu mua/bán cá nhân cho crypto và chứng khoán — không phải bot copy trade đại trà, mà là hệ thống được xây riêng để phục vụ đúng một người, với dữ liệu kiểm chứng thực tế 2–5 năm trở lại. NestJS scan đồng thời trên nhiều khung thời gian từ 15 phút đến 1 tháng, chạy song song qua 4 engine độc lập: candlestick pattern, indicator, price action và volume analysis. Tín hiệu chỉ được ghi nhận khi nhiều khung đồng thuận — loại bỏ nhiễu, chỉ giữ lại những điểm vào lệnh thực sự đáng chú ý. Sau 10 ngày, hệ thống tự nhìn lại từng tín hiệu — đúng hay sai — tích lũy dần độ chính xác theo thời gian sử dụng. Kết quả được đẩy thẳng về Telegram cá nhân ngay khi có tín hiệu, pattern hiển thị realtime trên TradingView tích hợp trong Next.js.

restaurant-system preview
R
Restaurant OS

Hệ thống POS dành cho nhà hàng đa chi nhánh — khách quét QR tại bàn để xem menu và đặt món trực tiếp trên điện thoại, không cần gọi nhân viên. Order được đẩy realtime về màn hình bếp và quầy thu ngân, nhân viên duyệt và cập nhật trạng thái từng món ngay khi phục vụ. Khi bàn thanh toán, bill được in tại quầy chỉ với một thao tác. Toàn bộ hệ thống — API NestJS, dashboard quản trị Next.js và web đặt món của khách — chạy trên một backend duy nhất, đồng bộ dữ liệu xuyên suốt giữa các chi nhánh theo thời gian thực.

bank-notify-bridge preview
B
Bank Notify

BankNotify biến một chiếc điện thoại Android cũ thành cổng thanh toán DIY cho merchant nhỏ. App Flutter + Kotlin chạy nền trên điện thoại, đọc thông báo biến động số dư từ app ngân hàng và forward ngay về backend qua HTTP. Backend nhận thông báo, match với đơn hàng đang pending, rồi gọi callback để hoàn thành thanh toán — tất cả xảy ra trong vài giây, không cần tích hợp cổng thanh toán chính thức, không cần phí hàng tháng.