Automated Stream Deck plugin installer for Windows. Download and install Elgato marketplace plugins directly into StreamDock/VSD plugin folders with minimal friction—supports both GUI and browser-triggered installation via protocol handler.
- Graphical Interface: Modern dark-themed PySide6 UI for manual plugin installation
- Browser Integration: Windows protocol handler for one-click install from marketplace browser links
- Persistent Authentication: Chromium profile caching eliminates repeated logins
- Streaming Downloads: Real-time progress tracking for large plugin files
- Flexible Configuration: Customizable Chromium profile, plugins root, download directory
- Smart Login Fallback: Automatically switches to headful browser if cached auth expires
- Plugin Management: Direct ZIP extraction with folder replacement (handles updates)
- Windows 10 or later
- Python 3.8+
- ~200 MB free disk space (for Chromium browser)
- Clone or download the repository:
git clone https://github.com/noman1228/StreamDownloader.git
cd StreamDownloader- Install Python dependencies:
pip install -r requirements.txt- Install Chromium browser for Playwright (one-time setup):
python -m playwright install chromium- Run the application:
python PluginDown.pyTo create a self-contained Windows executable (no Python required):
Easy way (Windows):
build.batManual way:
python build_exe.pyThis will:
- Install PyInstaller
- Bundle Python, all dependencies, and the Chromium browser
- Create
dist/StreamDownloader/StreamDownloader.exe - The build takes 5-10 minutes and creates a ~500 MB folder
Share the executable:
- Zip the
dist/StreamDownloaderfolder - Users can extract and run
StreamDownloader.exedirectly - No Python installation needed
Build requirements:
pip install -r requirements-dev.txtLaunch the graphical interface:
python PluginDown.pyThe GUI provides:
- Plugin UUID input field (copy from marketplace plugin page)
- Chromium Profile path for persistent browser cookies
- Plugins Root Directory (auto-detects StreamDock/VSD installation)
- Download Directory (defaults to
~/Downloads) - Headless Mode checkbox (recommended; auto-falls back for login)
- Keep Downloaded File checkbox (retain
.streamDeckPluginarchive) - Progress Bar with live download percentage
- Protocol Handler Registration for browser integration
Register a protocol handler to install via browser links:
- In the GUI, set your desired Scheme (default:
streamdeck) - Click Register Handler
- Click any plugin install link in the marketplace; the app launches automatically
REM Manual invocation (for testing):
python PluginDown.py --protocol "streamdeck://plugins/install/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"The protocol handler will:
- Read settings from the registry (persisted from GUI mode)
- Launch Chromium for authentication if needed
- Download and install silently with console output
Minimal mode for scripting (currently placeholder):
python PluginDown.py --no-guiSettings are persisted in the Windows registry under:
HKEY_CURRENT_USER\Software\JMT\StreamDeck to StreamDock Auto Installer
| Key | Type | Default | Purpose |
|---|---|---|---|
profile_dir |
Path | %LOCALAPPDATA%\ElgatoCookieProfile |
Chromium persistent context (stores auth cookies) |
plugins_root |
Path | Auto-detect | Root folder where plugin folders are installed |
download_dir |
Path | ~/Downloads |
Where .streamDeckPlugin archives are saved |
protocol_scheme |
String | streamdeck |
Protocol scheme for scheme://plugins/install/<uuid> |
headless |
Boolean | true |
Launch Chromium in headless mode (auto-fallback on login needed) |
keep_download |
Boolean | true |
Retain downloaded plugin archive after installation |
Auto-Detected Plugins Roots (in priority order):
%APPDATA%\HotSpot\StreamDock\plugins%APPDATA%\VSDinside\StreamDock\Plugins%APPDATA%\VSDStreamDock\Plugins%LOCALAPPDATA%\VSDinside\VSDStreamDock\Plugins%LOCALAPPDATA%\VSDStreamDock\Plugins
UUID Validation
↓
Cookie Acquisition (Playwright/Chromium)
↓
Marketplace API → Purchase Link Resolution
↓
Plugin Download (streamed, with progress)
↓
ZIP Extraction → Plugins Root
↓
(Optional) Clean Up Downloaded Archive
get_marketplace_cookies()
- Uses Chromium's persistent context for auth cookie caching
- Launches headless by default; falls back to headful for login
- Detects auth tokens:
__Host-kc_at,__Secure-kc_rt,next-auth
fetch_purchase_link()
- Calls Elgato API:
marketplace.elgato.com/api/proxy/items/{item_id}/purchase-link - Returns direct download link for the
.streamDeckPluginfile
download_with_progress()
- Streams download in 256 KB chunks
- Emits progress updates every 0.1 seconds
- Gracefully handles missing
Content-Lengthheader
install_streamdeckplugin()
- Extracts ZIP directly to plugins root
- Auto-replaces existing folder (handles plugin updates)
- Detects single top-level folder in archive
InstallWorker(QThread)
- Runs installation in background thread
- Maps download progress (25–80%) to progress bar
- Emits status messages and final success/error signal
Protocol Handler Registration
- Writes to
HKCU\Software\Classes\<scheme> - Launches:
python "<script_path>" --protocol "%1" - Windows invokes handler when user clicks
scheme://link
Instead of logging frameworks, this codebase uses a simple status_cb callable:
def status_callback(message: str):
# Update UI or print to console
pass
get_marketplace_cookies(profile_dir, headless_preferred=True, status_cb=status_callback)All major functions accept optional status_cb for real-time progress updates.
REM GUI mode with your settings
python PluginDown.py
REM Test protocol mode
python PluginDown.py --protocol "streamdeck://plugins/install/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
REM Debug no-GUI mode
python PluginDown.py --no-gui| Section | Purpose |
|---|---|
| Config/Constants | Market domain, API endpoints, app identity |
| Helpers | UUID validation, path helpers, byte formatting |
| Playwright Cookie Grabber | Auth cookie acquisition via persistent Chromium |
| Marketplace + Download + Install | Core pipeline functions |
| Windows Protocol Handler | Registry manipulation (Windows-only) |
| Protocol Invocation Install | run_protocol_install() entrypoint |
| Qt Worker | InstallWorker thread for GUI responsiveness |
| Qt GUI | InstallerWindow with layout, styling, event handlers |
| Main | CLI argument parsing and mode dispatch |
When changing install behavior, ensure both codepaths stay in sync:
- GUI path:
InstallWorker.run()→on_install_done() - Protocol path:
run_protocol_install()→ console output
- Add key to
_load_settings()(read from registry with default) - Add key to
_save_settings()(write to registry) - Add UI control in
_build_ui() - Read from
QSettingsinrun_protocol_install()
Example:
# _load_settings()
self.my_checkbox.setChecked(self.settings.value("my_key", False, type=bool))
# _save_settings()
self.settings.setValue("my_key", self.my_checkbox.isChecked())
# run_protocol_install()
my_setting = settings.value("my_key", False, type=bool)| Package | Version | Purpose |
|---|---|---|
playwright |
1.58.0+ | Chromium automation and cookie persistence |
pyside6 |
6.10.2+ | Qt GUI framework |
requests |
2.32.5+ | HTTP client for API calls and downloads |
Install all with:
pip install -r requirements.txt
python -m playwright install chromiumYou haven't installed the Chromium browser. Run:
python -m playwright install chromiumIf the app keeps opening a browser window despite headless mode:
- Browser window means cached cookies have expired
- Log in once, and credentials are cached for future runs
- This is expected behavior; headless falls back automatically
- Verify plugins root path exists and is writable
- Check UUID is valid (copy directly from marketplace page)
- Ensure
.streamDeckPluginarchive isn't corrupted (check downloads folder)
- Verify scheme is set correctly in the GUI before registering
- Restart your browser after registration
- Check registry:
HKEY_CURRENT_USER\Software\Classes\<scheme> - Test manually: Open PowerShell and run:
python PluginDown.py --protocol "streamdeck://plugins/install/<uuid>"
- First run requires manual login via headful browser
- Log in once through the opened window; credentials are cached
- Subsequent runs use cached cookies in headless mode