Root cause: Stream names were normalizing to empty strings through
aggressive pattern stripping, causing multiple unrelated channels
(GNT, MTV, TLC, BIS, TNT, etc.) to incorrectly match each other
with 100% similarity scores.
Changes made:
1. Fixed calculate_similarity() to return 0.0 for empty string
comparisons instead of 1.0, preventing false positives
2. Added validation in normalize_name() to log warnings when
normalization results in empty strings
3. Added empty string checks (< 2 chars) in all matching stages:
- fuzzy_match() Stage 1 (exact match)
- fuzzy_match() Stage 2 (substring match)
- find_best_match() (token-sort matching)
4. Added validation in plugin.py _match_streams_to_channel() to
skip streams with empty/short cleaned names in:
- Fuzzy matcher result collection
- JSON exact match section
- Basic substring matching fallback
5. Fixed country prefix regex pattern from [:|\s] to [:\s]
(removed incorrect pipe and backslash characters)
Testing: Added comprehensive test suite (test_fuzzy_matcher_fix.py)
that verifies empty strings don't match and valid matches still work.
All tests pass.
Changed the following log entries to DEBUG level to reduce log verbosity:
- API request logs
- Page fetch progress logs
- Fuzzy matcher usage logs
- Fuzzy match result logs
These logs are useful for debugging but too verbose for normal operation.
Implements automatic version checking that displays update status on the plugin settings page.
Features:
- Fetches latest release version from GitHub using stdlib (urllib.request)
- Displays version status at top of settings page (Update Available / Up to Date)
- Caches version check results for 24 hours to minimize API calls
- Re-checks automatically when plugin version changes
- Fails gracefully if network unavailable or GitHub API errors occur
Technical Details:
- Uses only Python standard library (no requests dependency)
- Version check triggered via fields property (runs when settings opened)
- Cache stored in /data/stream_mapparr_version_check.json
- Timeout set to 5 seconds for API requests
- All errors logged at debug level to avoid cluttering logs
Enhancements:
- Add database validation to settings validation
* Checks if at least one database file exists
* Validates JSON format of enabled databases
* Ensures at least one database is enabled
* Reports invalid/malformed database files
- Add database information to CSV exports
* Show which database was used for each channel match
* Add "database_used" column to preview and update CSVs
* Include enabled databases list in CSV header comments
* Track database source through matching pipeline
- Shorten validation success message
* Condensed format with key info only
* Separate success items and info items
* More readable for small notification areas
* Shows database count in validation results
Changes to _match_streams_to_channel():
- Now returns 5-tuple: (streams, cleaned_name, cleaned_stream_names, match_reason, database_used)
- Tracks country_code from channel database entry
- Returns "N/A" if channel not found in any database
CSV export improvements:
- Preview CSV includes database_used column
- Update CSV includes database_used column
- Header comments show: "Channel Databases Loaded: [list]"
- Update plugin.py version from 0.6.0 to 0.5.0a
- Update fuzzy_matcher.py version to 25.314.1907 (Nov 10, 2025 19:07)
- Update all references to v0.6.0 in README.md to v0.5.0a
Changed approach from modifying global GEOGRAPHIC_PATTERNS (which affects
all plugins using fuzzy_matcher.py) to adding a new optional parameter.
Changes:
- Reverted GEOGRAPHIC_PATTERNS to original US-only patterns
- Added new remove_country_prefix parameter to normalize_name() (default: False)
- Updated _clean_channel_name() to use remove_country_prefix=True by default
- Implemented smart prefix detection that avoids removing quality tags (HD, SD, UHD, FHD)
- Added fallback country prefix removal in basic cleaning code
- Updated README to clarify country code prefix handling approach
This ensures backward compatibility for other plugins while enabling
multi-country support for Stream-Mapparr.
This update introduces GUI-based channel database management, allowing users to enable or disable specific country databases for channel matching.
Key Changes:
- Convert fields from static list to @property method for dynamic database detection
- Add _get_channel_databases() method to scan and extract database metadata
- Update _load_channels_data() to filter by enabled databases from settings
- Support new database format with country_code, country_name, and version metadata
- Maintain backward compatibility with legacy array format
- Add dynamic checkbox fields for each detected database in plugin settings
- Default behavior: US enabled, all others disabled (or enable if only one database exists)
- Update fuzzy_matcher.py GEOGRAPHIC_PATTERNS to handle any country code prefix (CC:, CC , CCC:, CCC )
- Add comprehensive README documentation for new database format and GUI management
- Include sample CA_channels.json demonstrating new metadata format
Features:
- Selectable channel databases through GUI settings
- Multi-country support with automatic country code prefix handling
- Clear database labels showing country name and version in settings
- Improved matching accuracy by enabling only relevant regional databases
Version: 0.6.0
- Document the *_channels.json file format and naming pattern
- Provide step-by-step guide for creating country-specific databases
- Include field descriptions and examples (UK_channels.json)
- Add Docker commands for installation and verification
- Include tips for better channel matching
- Update field description and placeholder to show quotation usage
- Add _parse_tags() static method to parse comma-separated tags with quote support
- Support both single and double quotes to preserve spaces and special characters
- Update all ignore_tags parsing locations to use new helper function
- Examples: "4K, \" East\", \"[Dead]\"" -> ["4K", " East", "[Dead]"]
Changes:
1. Extract validation logic into _validate_plugin_settings helper method:
- Returns (has_errors, validation_results, token) tuple
- Validates API connection, profiles, groups, thresholds, etc.
- Reusable across multiple action methods
2. Update validate_settings_action:
- Now calls _validate_plugin_settings helper
- Formats results for UI display
3. Add validation to load_process_channels_action:
- Validates settings before loading channels
- Prevents processing with invalid profiles or groups
- Returns clear error messages if validation fails
4. Add validation to preview_changes_action:
- Validates settings before previewing changes
- Ensures settings are still valid when preview is run
- Returns clear error messages if validation fails
5. Update version to 0.5.0d
Benefits:
- Prevents users from proceeding with invalid settings
- Provides immediate feedback on configuration errors
- Ensures channel profiles and groups exist before processing
- Improves user experience with clear error messages
- Maintains DRY principle with shared validation logic
Changes:
1. Add four new UI settings for granular pattern control:
- ignore_quality_tags: Control quality pattern removal ([4K], HD, etc.)
- ignore_regional_tags: Control regional pattern removal (East)
- ignore_geographic_tags: Control geographic prefix removal (US:, USA:)
- ignore_misc_tags: Control miscellaneous pattern removal ((CX), (Backup), etc.)
2. Update _clean_channel_name method:
- Add parameters: ignore_quality, ignore_regional, ignore_geographic, ignore_misc
- Pass these to fuzzy_matcher.normalize_name
- Defaults to True for backward compatibility
3. Update _match_streams_to_channel method:
- Accept category flag parameters
- Pass them through to all _clean_channel_name calls
4. Store category settings in processed_data:
- Save settings when loading/processing channels
- Retrieve settings when executing actions
- Apply settings consistently across all operations
5. Update all action methods:
- preview_changes_action
- add_streams_to_channels_action
- manage_channel_visibility_action
- All retrieve and use category settings from processed_data
This enables users to fine-tune pattern matching behavior through the UI
while maintaining full backward compatibility with existing configurations.
Features:
- Multi-profile support: Profile Name field now accepts comma-separated list
- Validate Settings button: New first action to validate all settings
- Checks API connection
- Validates all profiles exist
- Validates all groups exist
- Verifies fuzzy matcher initialization
- CSV headers: All generated CSV files now include comment headers with:
- Plugin version
- All applicable settings (Overwrite, Threshold, Profiles, Groups, Tags, Limit)
- Statistics (visible channels, total streams, matched streams)
Changes:
- Updated Profile Name field help text and placeholder
- Modified load_process_channels_action to handle multiple profiles
- Added validate_settings_action method with comprehensive validation
- Added _generate_csv_header_comment helper method
- Updated all three CSV exports (preview, update, visibility) to include headers
Add __version__ constant using Julian date format: YY.DDD.HHMM
- YY: Two-digit year (25 = 2025)
- DDD: Day of year (310 = November 6th)
- HHMM: Time in 24-hour format (1806 = 6:06 PM)
Version: 25.310.1806
This provides a clear, sortable version number that indicates exactly
when the last modification was made.
Fix inconsistency where some quality tags were only matched in bracketed
format but not in unbracketed format, causing streams with unbracketed
quality tags to be excluded from matching.
Previous issue:
- [4K], [Unknown], [Unk], [Slow], [Dead] were matched (bracketed)
- But "4K", "Unknown", "Unk", "Slow", "Dead" were NOT matched (unbracketed)
This caused streams like:
- "BBC One 4K" (no brackets) - NOT normalized, NOT matched
- "BBC One Unknown" - NOT normalized, NOT matched
- "ESPN (Slow)" - NOT normalized, NOT matched
Changes to HARDCODED_IGNORE_PATTERNS:
- Added 4K, Unknown, Unk, Slow, Dead to middle pattern: " TAG "
- Added 4K, Unknown, Unk, Slow, Dead to end pattern: " TAG"
- Added 4K, Unknown, Unk, Slow, Dead to colon pattern: "TAG:"
- Added 4K, Unknown, Unk, Slow, Dead to parentheses pattern: (TAG)
- Added inline documentation for each pattern type
- Note: All patterns already use re.IGNORECASE for case-insensitive matching
Now ALL quality tags are handled consistently across:
- Bracketed: [TAG] ✓
- Unbracketed at end: " TAG" ✓
- Unbracketed in middle: " TAG " ✓
- Parenthesized: (TAG) ✓
- With colon: "TAG:" ✓
This ensures no quality tags are missed regardless of format.
Fix bug where FHD and UHD streams were not being matched to channels.
The HARDCODED_IGNORE_PATTERNS were missing FHD and UHD in several regex
patterns, causing streams like "BBC one FHD" to fail normalization and
be excluded from matching results.
Changes:
- Add FHD and UHD to bracketed quality patterns: [FHD], [UHD], [fhd], [uhd]
- Add FHD and UHD to unbracketed quality patterns at end: " FHD", " UHD"
- Add FHD and UHD to parentheses patterns: (FHD), (UHD)
- Add FHD and UHD to word boundary patterns: "FHD:", "UHD:"
- Add UHD to STREAM_QUALITY_ORDER for proper quality sorting
- Add UHD to CHANNEL_QUALITY_TAG_ORDER for channel prioritization
This ensures streams with FHD/UHD quality tags are properly normalized
and matched alongside HD and SD streams.
Fixes issue where only HD and SD streams were matched while FHD streams
were ignored.
- Updated regex from '\bCinemax\s+' to '\bCinemax\b\s*'
- Now handles edge cases like Cinemax at end of string
- Matches Cinemax as complete word with optional trailing spaces
- Ensures proper matching for channels containing 'max'
The WebSocket notifications require frontend handlers in Dispatcharr's
WebSocket.jsx that cannot be added from the plugin code. Removed all
send_websocket_update() calls to avoid sending notifications that won't
be displayed.
The plugin still logs progress to the console for debugging.
Changes:
- Remove import of send_websocket_update
- Remove all WebSocket notification calls from:
* preview_changes_action
* add_streams_to_channels_action
* manage_channel_visibility_action
- Progress is still logged via standard logging
When a channel name contains "max" (case insensitive), the plugin
now removes "Cinemax" from stream names during matching. This allows
channels like "5StarMax" to properly match streams like:
- US: Cinemax 5Starmax
- US 5STARMAX (East) (H)
- US: 5 STARMAX
Changes:
- Add remove_cinemax parameter to normalize_name() in fuzzy_matcher.py
- Add remove_cinemax parameter to _clean_channel_name() in plugin.py
- Detect if channel name contains "max" in _match_streams_to_channel()
- Pass remove_cinemax=True to all stream name cleaning when applicable
- Update fuzzy_match() and find_best_match() to support Cinemax removal
This improves matching accuracy for Cinemax channels that include
the network name in stream names but not in channel names.
Root cause: Lines 1414-1415 were trying to access non-existent fields
'stream_count' and 'attached' directly from channel objects. These values
are actually stored in the channel_stream_counts dictionary and
channels_attached_to_others set respectively.
Changes:
- Fixed field access to use correct data structures
- Added error handling to check if channel exists in stream_counts
- Added debug logging to show evaluation details for each channel
- Added full traceback logging in exception handler for better debugging
This fixes the error: "Error managing channel visibility: 'stream_count'"