Automated Discord voice channel joiner with system tray integration
Project description
DiscordAutoJoin v1.0
A powerful, persistent Windows background application that automatically joins a specific Discord voice channel, enables the camera, mutes the mic, and monitors connection health โ all from a lightweight system tray icon.
๐ Features
- Automated Voice Connection: Navigates to a Discord channel and joins voice automatically.
- Camera Automation: Silently re-enables the camera if Discord turns it off.
- Microphone Management: Ensures the microphone stays muted (configurable).
- Persistent Monitoring: Continuously checks connection health and auto-reconnects on drop.
- System Tray Integration: Runs silently in the background with a real-time diagnostic tray icon.
- Windows Startup Support: Registers itself to start automatically when Windows boots.
- Resource Optimized: Blocks analytics domains, disables animations, limits Chrome memory to ~128MB JS heap.
- Thread-Safe State: All shared state protected by
threading.RLockfor safe concurrent access. - Secure by Default: Zero dangerous Chrome flags โ all security boundaries intact.
๐๏ธ Architecture
The codebase is split into 12 focused modules with a strict acyclic dependency graph:
main.py โโโบ __init__.py โโโบ automation.py โโโบ browser.py
โ โ โ chrome_flags.py
โ โ โโโโบ actions.py resource_guard.py
โ โ โโโโบ tray.py โโโบ state.py
โ โ โโโโบ config.py
โ โโโโบ lock.py โโโบ config.py
โ โโโโบ logging_setup.py โโโบ config.py
โโโโบ tray.py (icon ref)
| # | Module | Responsibility |
|---|---|---|
| 1 | chrome_flags.py |
27 curated safe Chrome flags |
| 2 | config.py |
Path constants, JSON config with UTF-8 + field validation |
| 3 | logging_setup.py |
Rotating file logger, CategoryFilter, Console class |
| 4 | lock.py |
PID-based instance locking with stale lock detection |
| 5 | state.py |
AppState singleton โ 10 RLock-protected properties + 2 threading.Event |
| 6 | resource_guard.py |
Domain blocking regex + CSS injection |
| 7 | actions.py |
MONITOR_JS, CLICK_MIC_JS, safe_eval() with timeout |
| 8 | browser.py |
Chrome process management, lock removal, priority, HWND discovery |
| 9 | tray.py |
Icon generation, dynamic menu, 6 tray callbacks, startup registration |
| 10 | automation.py |
7-step lifecycle orchestrator + run_asyncio_loop() |
| 11 | __init__.py |
Package exports |
| 12 | main.py |
Thin entry point (~90 lines): CLI parsing, lock, tray, thread launch |
๐ ๏ธ Technology Stack
- Python 3.9+ โ Core logic and automation
- Playwright โ Browser automation for Discord web client interaction
- PyStray โ System tray icon and menu management
- Pillow โ Dynamic tray icon generation
- psutil โ Cross-platform process management (priority, memory, PID checks)
๐ฆ Installation
Prerequisites
- Windows 10/11
- Python 3.9 or later
- Google Chrome installed
Setup
# Clone the repository
git clone https://github.com/username/DiscordAutoJoin.git
cd DiscordAutoJoin
# Install the package with dependencies
pip install -e .
# Install Playwright's Chromium browser
playwright install chromium
# Or install just the dependencies manually:
pip install playwright>=1.40.0 pystray>=0.19.0 pillow>=10.0.0 psutil>=5.9.0
Development Setup
pip install -e ".[dev]" # Includes pytest, pytest-asyncio, pytest-cov
๐ฅ๏ธ Usage
Running the Application
# Via console_scripts (after pip install):
discord-autojoin
# In debug mode (all messages printed to console):
discord-autojoin-debug
# Or run directly:
python -m DiscordAutoJoin.main
python -m DiscordAutoJoin.main --debug
python -m DiscordAutoJoin.main --version
First Run
- On first launch, the app opens Chrome and navigates to Discord.
- Log in manually in the Chrome window if prompted.
- Right-click the tray icon and select "Confirm Login Done".
- The app will join the configured voice channel, enable camera, mute mic, and minimize Chrome.
Tray Menu
| Menu Item | Action |
|---|---|
| Status / Uptime / Last Action | Real-time dashboard (read-only) |
| View Config | Shows current configuration values |
| Confirm Login Done | Signals that manual login is complete |
| Pause / Resume Automation | Temporarily halts monitoring |
| Force Reconnect | Triggers a full disconnect/reconnect cycle |
| Show / Hide Chrome | Toggles the Chrome window visibility |
| View Debug Log | Opens the log file in Notepad |
| Restart App | Clean restart of the application |
| Exit | Clean shutdown (releases lock, kills Chrome) |
Configuration
The config file is stored at %APPDATA%/DiscordAutoJoin/config.json and is created automatically on first run with these defaults:
{
"DISCORD_URL": "https://discord.com/channels/...",
"MAX_JOIN_RETRIES": 30,
"POLL_INTERVAL": 5.0,
"RESTART_DELAY": 5,
"HEALTH_LOG_EVERY": 12,
"MAX_CONSECUTIVE_ERRS": 3,
"MAX_RELOAD_FAILS": 2,
"MAX_LAUNCH_RETRIES": 5
}
Edit DISCORD_URL to point to your target voice channel. Missing keys are automatically filled from defaults on next launch.
Logs
Logs are stored at %APPDATA%/DiscordAutoJoin/app.log with rotation (5 MB max, 3 backups).
๐งช Testing
239 tests pass with 69% code coverage (core modules at 100%).
# Run all tests with coverage:
pytest
# Run only unit tests:
pytest -m unit
# Run only integration tests:
pytest -m integration
# Run with verbose output:
pytest -v --tb=long
# Coverage report is generated in htmlcov/index.html
Test Structure
| File | Tests | Coverage | What It Tests |
|---|---|---|---|
tests/test_config.py |
17 | 100% | Config loading, merging, missing keys, corrupt files |
tests/test_state.py |
27 | 100% | AppState properties, thread safety, events |
tests/test_lock.py |
14 | 69% | Instance locking, stale lock detection, release |
tests/test_resource_guard.py |
23 | 67% | Domain blocking regex, CSS optimization |
tests/test_actions.py |
22 | 100% | safe_eval(), MONITOR_JS, CLICK_MIC_JS |
tests/test_browser.py |
25 | 98% | Chrome process management, locks, priority, HWND |
tests/test_tray.py |
35 | 86% | Icon generation, menu, callbacks, startup |
tests/test_logging_setup.py |
20 | 100% | Console, CategoryFilter, DEBUG_MODE |
tests/test_integration.py |
56 | โ | Full flow with mocked Playwright, error recovery |
CI/CD
GitHub Actions pipeline (.github/workflows/ci.yml):
- Lint โ ruff check + format verification
- Test โ pytest matrix across Python 3.9โ3.12 with coverage
- Build โ wheel artifact generation
๐ Data Directory
All application data is stored in %APPDATA%/DiscordAutoJoin/:
%APPDATA%/DiscordAutoJoin/
โโโ config.json # User configuration
โโโ app.log # Rotating log file
โโโ app.lock # Instance lock file
โโโ ChromeProfile/ # Persistent Chrome profile (login session)
๐ก๏ธ Security
- No dangerous Chrome flags:
--disable-web-security,--no-sandbox,--disable-site-isolation-trials, and--disable-gpu-sandboxhave been removed. - Sandbox intact: All Chrome process isolation and site isolation remain enabled.
- No credentials stored: Login session is handled entirely by Chrome's persistent profile.
- No telemetry: Analytics/tracking domains (Sentry, Google Analytics, New Relic, DataDog) are blocked at the request level.
๐ License
This project is for educational purposes. Use responsibly and adhere to Discord's Terms of Service.
๐ค Contributing
See CONTRIBUTING.md for module structure, coding standards, and pull request guidelines.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file discordautojoin-1.0.0-py3-none-any.whl.
File metadata
- Download URL: discordautojoin-1.0.0-py3-none-any.whl
- Upload date:
- Size: 24.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
711b76cd4b27463673660facb8811f6b0278f87ca223a388fe0e3dabf9fcb66f
|
|
| MD5 |
579f0494b04460b31e5cd3dcb39bdc64
|
|
| BLAKE2b-256 |
abb735093158257fc6d8e3fdb14c28957547530f27476e3eea84fe2cf1acd74e
|