* All games will be linked
* feat: Add 'Add Game' button to Settings tab
- Added 'Add Game' button to Games to Watch section in Settings
- Implemented logic to add custom games via search input
- Fixed alignment issue with games filter search bar
- Added English translations for new UI elements
* fix PR 33 review issues
---------
Co-authored-by: ethanblazkowicz <wow990922@outlook.com>
Co-authored-by: LeonSparta <46887992+LeonSparta@users.noreply.github.com>
Co-authored-by: Fengqing Liu <fq_aaron@hotmail.com>
* Add footer with app version and GitHub update check
- Add GET /api/version endpoint returning current_version, latest_version, update_available and download_url (checks rangermix/TwitchDropsMiner releases via GitHub API).
- Add UI footer displaying current version and a visible update indicator with link.
- Add styles for footer and update alert; add client-side logic to fetch version on load.
- Update repository links to rangermix and replace favicon with transparent background.
See: web/index.html, web/static/app.js, web/static/styles.css, src/web/app.py
* - align footer width
- add (latest) indication if is latest version
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- Implemented 'Benefit Type' filtering (Item, Badge, etc.) in backend and settings UI.
- Redesigned 'Wanted Drops Queue' as a card-based, masonry layout.
- Added 'Game Groups' to Wanted Queue for better organization.
- Added variable height support for Inventory cards.
- Added proxy support and verification logic (from previous steps).
- Added unit tests for new filters and UI logic.
- 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>
Removed unnecessary wrapper methods in the Twitch client and the unused
ReloadRequest exception to simplify the codebase.
Client cleanup (src/core/client.py):
- Removed unnecessary wrapper methods that just delegated to services:
- _watch_sleep() - direct call to service
- _watch_loop() - task created directly from service method
- _maintenance_task() - unused wrapper removed
- process_drops() - websocket callback uses service method directly
- process_notifications() - websocket callback uses service method directly
- process_stream_state() - websocket callback uses service method directly
- process_stream_update() - websocket callback uses service method directly
- get_priority() - direct call to service
- _viewers_key() - direct call to static method
- Changed websocket topic callbacks to use service methods directly
- Removed ReloadRequest handling from run() method
- Net reduction: ~50 lines of unnecessary delegation code
Exception removal (src/exceptions.py):
- Removed unused ReloadRequest exception class
- This exception was never actually raised in the codebase
Task wrapper update (src/utils/async_helpers.py):
- Removed ReloadRequest from exception handling
- Updated docstrings to reflect this change
Benefits:
- Simpler code: Less indirection through unnecessary wrappers
- More direct: Websocket callbacks use service methods directly
- Cleaner: Removed unused exception class
- Easier to follow: Less jumping between wrapper and actual implementation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Simplified the Translator class to be more direct and Pythonic, and
updated all translation access from callable pattern to dict access.
Translator changes (src/i18n/translator.py):
- Removed complex fallback/merging logic with English translations
- Simplified from callable pattern _("key", "subkey") to dict access _.t["key"]["subkey"]
- Removed _load_english_translation() and module-level English translation
- Changed from list of language names to dict of Translation objects
- Removed unnecessary imports (abc, json_utils, MinerException, TYPE_CHECKING)
- Made language storage and access more direct (self.t property)
- Simplified set_language() to direct dict lookup
Translation access pattern changes (all other files):
- Changed from _("key", "subkey") to _.t["key"]["subkey"] throughout codebase
- This is more Pythonic and aligns with TypedDict structure
- Applied in: __main__.py, http_client.py, auth_state.py, models/drop.py,
services (inventory, message_handlers, watch), web managers (login, settings),
websocket.py
Benefits:
- More Pythonic: Direct dict access instead of callable
- Simpler: Removed ~70 lines of complex fallback logic
- Type-safe: Direct access to TypedDict structure
- More explicit: _.t["key"]["subkey"] shows the structure clearly
- Easier to maintain: No complex merging or fallback logic
🤖 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>
- Remove unused translation keys from all language files:
- Removed chrome login flow keys (no longer used)
- Removed GUI channel headings (table structure changed)
- Removed GUI inventory filter section (filtering not in web GUI)
- Removed GUI settings proxy field (moved to general section)
- Cleaned up other deprecated keys
- Add new translation keys for web GUI:
- OAuth login prompts (oauth_prompt, oauth_activate, oauth_confirm)
- Progress indicators (no_drop, return_to_auto, manual_mode_info)
- Channel empty states (no_channels, no_channels_for_games, channel_count)
- Inventory empty state (no_campaigns, claimed_drops)
- Settings UI (games selector, search, drag-and-drop hints)
- Help section content (about, features, important_notes)
- Header elements (title, language selector, mode indicators)
- Update app.py /api/translations endpoint to use translation keys instead of hardcoded English strings
- Update translator.py TypedDict definitions to match new structure
- Fix i18n __init__.py exports to remove ChromeMessages, GUIChannelHeadings, GUIInvFilter and add GUIHeader
All 19 language files updated consistently. Non-English languages use English text as placeholders for new keys.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem: Language selection in the web GUI was not being saved to disk,
so the setting was lost on application restart.
Root cause: SettingsManager.update_settings() called alter() to mark
settings as changed, but never called save() to persist them. Settings
were only saved later during inventory fetch, which might not happen
before restart.
Solution: Add immediate save() call after altering settings to ensure
all setting changes (language, dark_mode, games_to_watch, etc.) are
persisted to settings.json immediately.
The language is already loaded on startup (src/__main__.py:105), so
now the saved language preference will be correctly restored.
🤖 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>