* update agent instructions * - update translations - add id to translation anchors to ensure correct update
16 KiB
AGENTS.md
AGENTS.md Specific Instructions
This file provides guidance to AI Agents when working with code in this repository.
Development Guidelines
-
Testing:
- Always add unit tests for backend changes.
- Frontend changes should have tests if possible.
-
Code Style & Architecture:
- DRY (Don't Repeat Yourself): Codebase must follow DRY principle.
- OOP (Object-Oriented Programming): Required for all backend code.
-
Refactoring:
- You are authorized to refactor code to align with DRY/OOP principles.
- Permission Required: You MUST ask for user permission before significant refactoring.
-
Localization (i18n):
- Update translation files if there are changes to UI text or console messages.
-
Documentation:
- Always update
README.mdand all agent instruction files when making changes. - The contents of all agent instruction files should be identical except for the
Specific Instructionssection. Any agent-specific instructions must be added to that section.
- Always update
Project Overview
Twitch Drops Miner is a Python application that automatically mines timed Twitch drops without downloading stream data. It uses Twitch's GraphQL API and websocket connections to simulate watching streams while tracking drop progress.
Key Characteristics:
- Python 3.12+ required
- Web-based GUI using FastAPI and Socket.IO
- Async/await architecture with asyncio
- Session persistence via cookies
- No stream video/audio download (bandwidth-efficient)
- Docker-ready for easy deployment
Architecture
The application now uses a clean src/ package structure with clear separation of concerns.
Project Structure
src/
├── models/ # Domain models (Game, Channel, Campaign, Drop, Benefit)
├── config/ # Configuration (constants, paths, operations, settings, client_info)
├── utils/ # Pure utilities (string, JSON, async helpers, rate_limiter, backoff)
├── i18n/ # Translation system (Translator class, TypedDict schemas)
├── auth/ # Authentication (auth_state for OAuth and token management)
├── api/ # External API (HTTP client, GraphQL client)
├── websocket/ # Real-time updates (websocket connection, pool)
├── web/ # Web GUI (app, gui_manager, api/)
│ └── managers/ # Individual UI managers (status, console, channels, campaigns, inventory, login, settings, cache, broadcaster)
├── services/ # Business logic services (channel, inventory, watch, maintenance, message_handlers)
├── core/ # Core client (Twitch client)
├── exceptions.py # Custom exceptions
├── version.py # Version string
└── __main__.py # Entry point
lang/ # Translation JSON files (19 languages)
├── English.json # Default/fallback translations
├── Español.json
├── Français.json
├── Deutsch.json
└── ... # 15 more languages
Core Components
main.py - Simple launcher:
- Runs the
srcpackage as a module usingrunpy.run_module("src") - All application logic is now in
src/__main__.py
src/main.py - Entry point:
- Parses command-line arguments
- Initializes Settings, Twitch client, and WebGUIManager
- Starts the FastAPI web server (uvicorn on port 8080)
- Runs the main asyncio event loop
- Handles signals (SIGINT, SIGTERM on Linux) and exit codes
src/core/client.py - Central client (Twitch class):
- State machine: IDLE, INVENTORY_FETCH, GAMES_UPDATE, CHANNELS_CLEANUP, CHANNELS_FETCH, CHANNEL_SWITCH, EXIT
- Composes
_AuthState,HTTPClient, andGQLClient - Delegates to service layer for business logic
- Drop progress monitoring via periodic "watch" payloads
- Manages WebsocketPool and maintenance tasks
src/services/ - Business logic layer (fully implemented):
ChannelService: Channel management and selection logicInventoryService: Campaign and drop inventory operationsWatchService: Drop mining watch payload logicMaintenanceService: Periodic maintenance tasksMessageHandlerService: Websocket message routing and handling
src/models/channel.py - Channel and Stream:
Channelclass: Twitch channel with online/offline statusStreamclass: Active stream with game, viewers, drop status- Stream URL fetching and validation
- ACL-based vs directory channels
src/models/campaign.py - Drop campaigns:
DropsCampaign: Campaign with game, timeframe, allowed channels- Time-based eligibility and progress tracking
src/models/drop.py - Drop types:
TimedDrop: Drops with minute requirements and progressBaseDrop: Base class with claim logic- Precondition chains for sequential drops
src/web/gui_manager.py - Web GUI:
WebGUIManager: Main GUI coordinator- Composes individual managers for different UI concerns (status, console, channels, campaigns, inventory, login, settings, cache)
- Uses
WebSocketBroadcasterfor real-time Socket.IO updates - Pure asyncio, no tkinter dependency
src/web/app.py - FastAPI application:
- REST API endpoints:
/api/status,/api/channels,/api/campaigns,/api/settings,/api/login,/api/oauth/confirm,/api/reload,/api/close,/api/version - Socket.IO server for real-time bi-directional communication
- Serves static web frontend from
web/directory - Integrates with WebGUIManager via
set_managers()
src/websocket/pool.py - WebSocket management:
- Sharded connections (up to 50 topics per socket, max 199 channels)
- Topics: User.Drops, User.Notifications, Channel.StreamState, Channel.StreamUpdate
- Automatic reconnection with exponential backoff
- Message routing to registered callbacks
src/config/settings.py - Application settings:
- Games to watch list (auto-populated from available campaigns if empty)
- Connection quality multiplier
- Language selection
- Proxy support (including verification)
- Logging and dump flags from command-line arguments
- Persistence to JSON file (
settings.json) in DATA_DIR - Inventory filters (Status, Benefit Type, Game Search)
State Machine Flow
- IDLE - Waiting for campaigns or user action
- INVENTORY_FETCH - Fetch campaigns from GraphQL, claim completed drops
- GAMES_UPDATE - Determine wanted games based on priority/exclude lists
- CHANNELS_CLEANUP - Remove channels not streaming wanted games
- CHANNELS_FETCH - Discover channels via ACL lists or game directories
- CHANNEL_SWITCH - Select best channel to watch based on priority/ACL
- Loop between CHANNEL_SWITCH and periodic INVENTORY_FETCH (hourly)
Authentication
- Uses OAuth device code flow (user enters code at twitch.tv/activate)
- Managed by
src/auth/auth_state.py(_AuthStateclass) - Access tokens stored in
cookies.jarin DATA_DIR - Device ID from Twitch's
unique_idcookie - Session ID generated per run
- Client info defined in
src/config/client_info.py(presents as Android app with Client-Id and User-Agent spoofing)
Drop Mining Mechanism
The application sends periodic "watch" payloads to a spade URL every ~20 seconds:
- Payload contains minute-watched events with channel/broadcast IDs
- Twitch reports progress via websocket (User.Drops topic)
- If websocket updates stop, fallback to GQL CurrentDrop query
- Extrapolation via "bump minutes" when no updates received
GraphQL Operations
Defined in src/config/operations.py as GQL_OPERATIONS:
- Inventory - Fetch in-progress campaigns and claimed benefits
- Campaigns - List available active/upcoming campaigns
- CampaignDetails - Detailed drop info for a campaign
- GameDirectory - Find live streams for a game with drops enabled
- GetStreamInfo - Check if channel is online and get stream details
- CurrentDrop - Query currently mined drop progress
- ClaimDrop - Claim a completed drop
- AvailableDrops - Check which campaigns a channel qualifies for (badge validation)
- NotificationsDelete - Delete Twitch notifications
Channel Selection Priority
- Selected channel (if user clicked one)
- ACL-based channels over directory channels
- Game priority order (from settings)
- Viewer count (descending)
- Maximum 199 channels tracked simultaneously
Maintenance Task
Runs in background to trigger:
- Channel cleanup when drops start/end (based on time_triggers)
- Inventory reload every ~60 minutes
Translation System
Architecture:
- All translations stored as JSON files in
lang/directory (19 languages supported) - English (
lang/English.json) is the single source of truth and fallback language - Strongly typed with TypedDict schema defined in
src/i18n/translator.py - Translator class (
src/i18n/translator.py) handles language loading and fallback - Singleton instance
_available viafrom src.i18n import _
Supported Languages:
- English, Dansk (Danish), Deutsch (German), Español (Spanish), Français (French)
- Indonesian, Italiano (Italian), Nederlandse (Dutch), Polski (Polish), Português (Portuguese)
- Română (Romanian), Türkçe (Turkish), Čeština (Czech)
- Русский (Russian), Українська (Ukrainian), العربية (Arabic)
- 日本語 (Japanese), 简体中文 (Simplified Chinese), 繁體中文 (Traditional Chinese)
Translation Structure:
Translation = {
"language_name": str, # Display name of language
"english_name": str, # English name of language
"status": StatusMessages, # Console status messages
"login": LoginMessages, # Login-related messages
"error": ErrorMessages, # Error messages
"gui": GUIMessages # All web GUI text (tabs, settings, help, etc.)
}
Usage:
from src.i18n import _
# Access translations
status_text = _.t["gui"]["status"]["idle"] # Returns "Idle"
login_text = _.t["login"]["status"]["logged_in"] # Returns "Logged in"
Language Persistence:
- Language selection persisted in
settings.json(DATA_DIR) - Dynamic language switching supported in web GUI
- Changes take effect immediately without restart
Key Files
- src/config/constants.py - Core enums (State, WebsocketTopic), logging config, type aliases
- src/config/operations.py - GraphQL operation definitions (GQL_OPERATIONS)
- src/config/paths.py - Path management and Docker environment detection
- src/config/client_info.py - Twitch client info (Client-Id, User-Agent)
- src/config/settings.py - Application settings with JSON persistence
- src/exceptions.py - Custom exceptions (MinerException, ExitRequest, RequestException, RequestInvalid, WebsocketClosed, LoginException, CaptchaRequired, GQLException)
- src/utils/ - Helper utilities (string_utils, json_utils, async_helpers, rate_limiter, backoff)
- src/i18n/ - Internationalization package with TypedDict schema and Translator class
- translator.py - Translator class with typed translation schema (Translation TypedDict)
- init.py - Exports translation types and
_(Translator instance)
- lang/ - Translation JSON files for 19 languages (English.json is the single source of truth)
- src/version.py - Version string
- src/web/app.py - FastAPI application with REST API and Socket.IO
- src/web/managers/cache.py - ImageCache for campaign artwork caching
- web/ - Frontend assets (index.html, static/app.js, static/styles.css)
Development Commands
IMPORTANT: Always activate the virtual environment first!
The project uses a virtual environment located at env/. All Python commands must be run within this environment:
# Activate the virtual environment (required before any Python commands)
source env/bin/activate
Running the Application
# Run from source (remember to activate venv first!)
source env/bin/activate && python main.py
# With verbose logging (stackable: -vv, -vvv)
source env/bin/activate && python main.py -v
# Create data dump for debugging
source env/bin/activate && python main.py --dump
# Access the web interface at http://localhost:8080
Development Setup
The application requires:
- Python 3.12+
- Virtual environment at
env/(must be activated before running commands) - Dependencies from
pyproject.toml(includes FastAPI, uvicorn, Socket.IO)
Docker deployment:
# Build and run with docker-compose
docker-compose up -d
# Access at http://localhost:8080
Testing
Automated Tests
The project includes a test suite in the tests/ directory:
# Activate virtual environment and run tests
source env/bin/activate && python -m pytest tests/
Test Files:
tests/test_proxy_settings.py- Tests for proxy settings configurationtests/test_verify_proxy.py- Tests for proxy verification functionality
Manual Testing
- Run with
-vvvfor maximum verbosity (levels: -v, -vv, -vvv, -vvvv) - Use
--dumpto generate debug data dumps - Check log files in
./logs/directory - Use
--debug-wsfor websocket debug logging - Use
--debug-gqlfor GraphQL debug logging - Monitor web GUI console output and browser developer tools
Web GUI Architecture
The application uses a web-based interface accessible via browser:
Web GUI Components
src/web/gui_manager.py - WebGUIManager class:
- Managers: StatusManager, ConsoleOutputManager, ChannelListManager, CampaignProgressManager, InventoryManager, LoginFormManager, SettingsManager, CacheManager
- Uses WebSocketBroadcaster to push real-time updates to connected clients via Socket.IO
- Pure async/await implementation
src/web/app.py - FastAPI application:
- REST API endpoints:
/api/status,/api/channels,/api/campaigns,/api/settings,/api/login,/api/oauth/confirm,/api/reload,/api/close,/api/version - Socket.IO server for real-time bi-directional communication
- Serves static web frontend from
web/directory - Integrates with WebGUIManager via
set_managers()
web/ - Frontend assets:
index.html- Single-page application layout with tabsstatic/app.js- Socket.IO client, real-time UI updates, API calls, Inventory Filtering logicstatic/styles.css- Responsive design with dark mode support
Communication Protocol
Server → Client (Socket.IO events):
initial_state- Full state on connectstatus_update- Status bar changesconsole_output- New log lineschannel_add/update/remove- Channel list changesdrop_progress- Drop mining progresscampaign_add- New campaign addedlogin_required- Prompt for credentialssettings_updated- Settings changed
Client → Server:
- REST API for actions (login, settings, channel selection)
- Socket.IO for connection management
Docker Integration
src/config/paths.py:
- Detects Docker environment via
DOCKER_ENVenv var or/.dockerenvfile - Docker: Uses
/appfor code,/app/datafor persistent storage - Development: Uses
<project_root>/datafor persistent storage - All user data (cookies, settings, cache, logs) stored in DATA_DIR
- Provides
_resource_path()helper for locating bundled resources
Dockerfile:
- Based on
python:3 - Installs dependencies from
pyproject.toml - Exposes port 8080
- Health check on
/api/status
docker-compose.yml:
- Volume mounts
./data:/app/datafor persistence - Port mapping
8080:8080 - Auto-restart policy
- Timezone configuration
Key Design Decisions
- WebSocket for real-time - Socket.IO chosen for reliability (fallback to polling)
- Single-page app - Simpler than full framework (React/Vue), fast load times
- Direct Docker support - Environment detection, proper path handling
- OAuth device code flow - Works great for web-based deployment
Project Scope
Supported:
- ✅ Web GUI - browser-based interface with advanced filtering
- ✅ Docker deployment - containerized for any platform
- ✅ Remote access - access from any device on network
- ✅ Headless operation - no display server required
NOT supported:
- Multi-account support
- Channel points mining
- Mining for unlinked campaigns
- Desktop GUI