- Display game box art icons (52x70px) next to game names in campaign headers
- Show contextual timing information below campaign status:
* Active campaigns display end time
* Upcoming campaigns display start time
* Expired campaigns display end time
- Use locale-aware date formatting via JavaScript toLocaleString()
- Utilize existing translation keys (starts/ends) with {time} placeholders
- Add flexbox layout for icon alignment and styling for timing text
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add visual indicators showing account linking status for each campaign in the inventory tab. Campaigns now display either a "LINKED" (green) or "NOT LINKED" (orange) badge in the top right corner of each card. For unlinked campaigns, both the badge and a "Link Account" button provide direct access to the Twitch account linking page.
Backend changes:
- Add campaign_url property to DropsCampaign model
- Include both campaign_url and link_url in inventory API response
Frontend changes:
- Add LINKED/NOT LINKED badges positioned at top right of campaign cards
- Add "Link Account" button for unlinked campaigns
- Style badges with subtle green for linked and prominent orange for not linked
- Make NOT LINKED badge clickable to open account linking page
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhance the inventory tab with comprehensive filtering options to help users quickly find relevant campaigns. The new filter system supports status-based filtering (Active, Not Linked, Upcoming, Expired, Finished) and an advanced game selection dropdown with tag-based UI and keyboard navigation.
Key features:
- Status filters: Active, Not Linked (default), Upcoming (default), Expired, Finished
- Multi-select game dropdown with live search and keyboard navigation (arrows, Enter, Escape)
- Visual game tags with easy removal
- Persistent filter preferences across sessions
- Dual data source (combines games from campaigns and settings)
- OR logic for game selection, AND logic between filter types
- Clear filters button to reset all selections
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced the inventory tab to show each benefit on its own line instead of
an icon grid. Each benefit now displays with:
- Icon (40x40px) on the left
- Benefit name and type on the right in format: "Name (TYPE)"
Changes:
- Backend: Send full benefit data (name, type, image_url) instead of just URLs
- Frontend: Render benefits as vertical list of horizontal lines
- CSS: Add new styles for benefit items (.benefit-item, .benefit-icon, .benefit-info)
- Removed: Icon grid layout (chunks of 3) and rewards text field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Simplified the /api/translations endpoint to return the complete
Translation TypedDict object instead of manually constructing a
custom nested structure. This makes the code more maintainable,
type-safe, and consistent with the translation schema.
Backend changes (src/web/app.py):
- Removed 116 lines of manual translation object construction
- Now returns _.t directly (full Translation object)
- Reduced endpoint from ~120 lines to 3 lines
Frontend changes (web/static/app.js):
- Updated to work with full Translation object structure
- All GUI translations now accessed via t.gui.* paths
- Login status uses t.login.status.* (from Translation.login)
- Websocket status uses t.gui.websocket.*
- Updated all render functions and Socket.IO handlers
Benefits:
- Simpler and more maintainable backend code
- Type-safe: returns exact Translation TypedDict structure
- Frontend can access all translation sections (gui, login, error, status)
- Follows the defined TypedDict schema exactly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit documents the current state of the translation system architecture
and consolidates the recent i18n refactoring work.
Documentation updates:
- Add detailed Translation System section describing architecture
- Document all 19 supported languages with native names
- Include TypedDict schema structure and usage examples
- Update project structure to show lang/ directory
- Expand Key Files section with i18n/ package details
- Document language persistence and dynamic switching
Translation system changes:
- Migrate English translations from hardcoded to lang/English.json
- Add English.json as single source of truth for fallback translations
- Update all language files with comprehensive GUI translations
- Refactor translator.py to load English from JSON file
- Add language_name and english_name fields to all translations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem: Help tab content was growing/duplicating every time the
language was changed because the code was trying to dynamically insert
"How It Works" sections that couldn't be found after translation.
Solution: Remove the dynamic content insertion logic for help sections.
Now only updates existing header text instead of creating new elements.
This prevents duplicate sections from appearing when switching languages.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Backend enhancements:
- Expand /api/translations endpoint with all available translation strings
- Include login form fields, OAuth prompts, progress labels, channel statuses
- Add inventory status texts, settings empty messages, help content
- Include connection status and viewer/channel count translations
Frontend improvements:
- Update all input placeholders (username, password, 2FA, search)
- Translate all button texts (Login, OAuth confirm, reload, manual mode)
- Apply translations to empty state messages across all sections
- Translate campaign statuses (Active, Upcoming, Expired, Claimed)
- Update channel and viewer count labels
- Apply translations to settings empty messages
- Update help tab with translated how-it-works and getting-started text
- Translate connection status indicators
Now supports translating:
- Login form (all fields and buttons)
- OAuth device code flow prompts
- Progress section labels and manual mode controls
- Channel list empty states and status labels
- Inventory campaign statuses and empty states
- Settings section empty messages and labels
- Help content sections
- Header connection indicators
All dynamically rendered content now respects language selection.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add /api/translations endpoint to return GUI text in current language
- Emit language_changed event when user changes language setting
- Frontend fetches and applies translations on language change
- Update all UI elements dynamically: tabs, headers, labels, buttons
- Load translations on page initialization
Fixes issue where language selection didn't update webpage text.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The application already had a complete i18n system with 18+ language
translation files, but the web GUI only showed English as an option.
Changes:
- Add /api/languages endpoint to fetch available languages from translator
- Update SettingsUpdate model to include language field
- Add SettingsManager.get_languages() method to expose available languages
- Update SettingsManager to handle language changes via translator.set_language()
- Populate language dropdown dynamically from available translations on page load
- Add auto-save for language changes in frontend
- Language is persisted to settings.json and loaded on startup
The translator is initialized with the saved language at application startup
(already implemented in src/__main__.py lines 101-105).
Available languages include:
English, Français, Deutsch, Español, Italiano, Português, Polski,
Русский, Українська, 简体中文, 繁體中文, 日本語, العربية,
Türkçe, Română, Nederlandse, Dansk, Čeština, Indonesian
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Relocated language dropdown from Settings tab to header banner
- Added new header-top layout with flexbox to position title and controls
- Styled language selector for better integration in header
- Removed duplicate language selector from Settings tab
- Language selector now appears in top-right corner for easier access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added user-configurable minimum refresh interval for inventory reloads, allowing users to control how frequently the maintenance service triggers updates (default: 30 minutes, range: 1-1440 minutes).
- Add minimum_refresh_interval_minutes to settings system with default of 30 minutes
- Update maintenance service to use configurable interval instead of hardcoded 1-minute value
- Add GUI input field in General Settings with auto-save functionality
- Include field in API settings endpoint and settings manager
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit introduces a manual mode for channel selection that allows users to lock onto a specific game, along with significant UI/UX improvements:
Manual Mode Features:
- Locks channel selection to a specific game when user manually selects a different game
- Automatically exits manual mode when all drops for the game are completed
- Shows visual indicators (🎯 badge) in status bar and drop display
- Allows manual exit via "Return to Auto Mode" button
- Prioritizes manual game in wanted_games list during auto-selection
UI/UX Improvements:
- Batch update system for channels and campaigns prevents flickering during refresh
- Channels list now updates atomically instead of clearing and re-adding
- Campaign loading emits all campaigns at once for smooth initial load
- Drop progress persists on initial_state load for reconnecting clients
- Game icons (box art) now displayed in channel list
- Campaign links added to inventory items
Bug Fixes:
- Fixed logging level to respect INFO by default (was hardcoded to DEBUG)
- Fixed channel cleanup to not call channel.remove() (handled by batch_update)
- Fixed drop display not persisting during channel switch
- Fixed stop_watching() clearing drop timer prematurely
- Fixed status display typo ("fames_to_watch" → "games_to_watch")
Backend Changes:
- Added manual mode tracking (_manual_target_channel, _manual_target_game)
- Added enter_manual_mode(), exit_manual_mode(), is_manual_mode() methods
- Added get_manual_mode_info() for API serialization
- Added batch_update() to ChannelListManager for atomic updates
- Added start_batch()/finalize_batch() to InventoryManager
- Added /api/mode/exit-manual endpoint
- Game model now stores box_art_url from GraphQL response
- Manual mode info included in /api/status and initial_state
Frontend Changes:
- Added manual mode badge and controls in UI
- Added channels_batch_update and inventory_batch_update socket events
- Added manual_mode_update socket event
- Countdown timer now properly tracked and cleared
- Drop display shows manual mode status with game name
- Exit manual mode button added to drop display area
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace the legacy desktop/Tkinter client and packaging artifacts with a Docker-first, web-hosted approach.
- Add Docker quickstart and run-from-source instructions to the README to simplify deployment.
- Simplify launcher to invoke the new web backend module instead of the old desktop entrypoint.
- Update dependencies for a web UI stack (FastAPI, Uvicorn, python-socketio, Jinja2, etc.) and remove desktop/tray-specific packages.
- Remove legacy GUI, packaging and platform-specific helper code, along with obsolete build/pack scripts and AppImage assets to declutter the repo.
- Tidy project ignore rules to add runtime logs and editor metadata.
Rationale: streamline deployment, favor a browser-accessible interface, and reduce maintenance overhead from multiple platform-specific GUI/packaging implementations.