# Stream-Mapparr v0.7.2
## What Was Fixed
Updated fuzzy_matcher.py dependency to include complete regional pattern support for all US timezone indicators.
## The Issue
- "E! Entertainment" was incorrectly matching `USA: E! ENTERTAINMENT (WEST)`
- fuzzy_matcher.py only recognized "East", missing West/Pacific/Central/Mountain/Atlantic
- Affected users with `Ignore Regional Tags: False` setting
## The Solution
**plugin.py v0.7.2**:
- Updated version to 0.7.2
- Added minimum fuzzy_matcher version requirement: 25.354.1835
**fuzzy_matcher.py v25.354.1835** (required dependency):
- Added 5 missing regional indicators: West, Pacific, Central, Mountain, Atlantic
- Each in both word format (` West`) and parenthesized format (`(West)`)
- Updated extract_tags() to recognize all regional indicators
## M3U Source Prioritization
Stream-Mapparr allows you to prioritize streams from specific M3U providers, ensuring your preferred sources are always selected first, regardless of quality metrics.
### How It Works
When you specify M3U sources in the **"📡 M3U Sources"** setting, streams are sorted using a multi-level hierarchy:
1. **M3U Priority** (0 = highest) - Based on order in your comma-separated list
2. **Quality Tier** - High (HD+FPS) > Medium > Low > Dead
3. **Resolution** - Higher resolution preferred within tier
4. **FPS** - Higher framerate preferred within tier
### Example Scenario
**Settings:**
```
M3U Sources: Premium Sports, Backup Provider, Free Streams
```
**Matched Streams for "ESPN":**
- ESPN HD (Premium Sports, 1920x1080, 60fps) → Priority 0, High Quality
- ESPN UHD (Free Streams, 3840x2160, 60fps) → Priority 2, High Quality
- ESPN SD (Premium Sports, 854x480, 30fps) → Priority 0, Low Quality
- ESPN FHD (Backup Provider, 1920x1080, 30fps) → Priority 1, Medium Quality
**Sorted Order:**
1. ESPN HD (Premium Sports) - Priority 0, High Quality ← Best overall
2. ESPN SD (Premium Sports) - Priority 0, Low Quality ← Same provider
3. ESPN FHD (Backup Provider) - Priority 1, Medium Quality
4. ESPN UHD (Free Streams) - Priority 2, High Quality ← Despite being 4K, sorted last
### Configuration
1. Navigate to the Stream-Mapparr plugin settings
2. Find the **"📡 M3U Sources (comma-separated, prioritized)"** field
3. Enter your M3U provider names in priority order, separated by commas:
```
Premium IPTV, Local M3U, Backup Provider
```
4. Save settings and run "Load/Process Channels" or "Sort Alternate Streams"
### Use Cases
- **Primary/Backup Providers**: Prioritize premium providers over backup sources for reliability
- **Regional Preferences**: Prioritize local M3U sources for better geographic performance
- **Quality Control**: Use specific providers known for better encoding/stability
- **Cost Optimization**: Prioritize cheaper sources when quality differences are negligible
### Notes
- Leave the M3U Sources field **empty** to disable prioritization (streams sort by quality only)
- Order matters: the **first** M3U in the list gets **highest** priority
- Prioritization applies to both "Match & Assign Streams" and "Sort Alternate Streams" actions
- Streams from unspecified M3U sources receive lowest priority (999)
Changed default values:
- Rate Limiting: "medium" → "none" (disabled by default)
- Fuzzy Match Threshold: 85 → 65 (more permissive matching)
Updated all fallback values in settings.get() calls throughout the codebase
to ensure consistency with the new defaults.
Fixed incorrect API endpoint paths that were causing JSON parsing errors:
- Changed /api/channels/stream-groups/ to /api/channels/streams/groups/ (correct endpoint)
- Changed /api/channels/m3us/ to /api/m3u/accounts/ (correct endpoint)
- Removed pagination loops since both endpoints return simple arrays, not paginated responses
Fixed stream filtering to use correct field names:
- Changed stream_group_id to channel_group (streams use channel_group FK)
- Changed m3u_id to m3u_account (streams use m3u_account FK)
- Use group_name_to_id instead of stream_group_name_to_id (stream groups endpoint returns strings, not objects)
These changes resolve the "Expecting value: line 1 column 1 (char 0)" JSON errors.
Added proper error handling for API endpoints that return empty or invalid JSON responses. This prevents JSONDecodeError exceptions when the StreamMaster API returns empty content.
Changes:
- Added empty response checking before JSON parsing in _get_api_data, _patch_api_data, and _post_api_data methods
- Added try-except blocks to catch json.JSONDecodeError with helpful error messages
- Return appropriate empty values ([] for GET, {} for PATCH/POST) when response is empty
- Added debug logging to show response content when JSON parsing fails
Fixes errors like: "Expecting value: line 1 column 1 (char 0)" when calling /api/channels/stream-groups/ and /api/channels/m3us/ endpoints
- Add new 'selected_m3us' setting field to filter streams by M3U source
- Fetch M3U sources from API endpoint /api/channels/m3us/
- Filter streams based on selected M3U sources (comma-separated or blank for ALL)
- Update CSV header comments to display selected M3U sources
- Store selected_m3us in processed_data for persistence
- Apply filter in both Preview Changes and Add Streams actions
This allows users to limit which streams are considered during matching
by specifying M3U source names (e.g., "IPTV Provider 1, Local M3U") or
leaving blank to use all available M3U sources. Works in conjunction with
the stream group filter for fine-grained stream selection.
- Add new 'selected_stream_groups' setting field to filter streams by group
- Fetch stream groups from API endpoint /api/channels/stream-groups/
- Filter streams based on selected stream groups (comma-separated or blank for ALL)
- Update CSV header comments to display selected stream groups
- Store selected_stream_groups in processed_data for persistence
- Apply filter in both Preview Changes and Add Streams actions
This allows users to limit which streams are considered during matching
by specifying stream group names (e.g., "TVE, Cable") or leaving blank
to use all available stream groups.
Additional logs moved to DEBUG level:
- Settings and configuration operations (loaded/saved settings, schedule config)
- API request details (PATCH/POST requests, token caching)
- Internal operations (frontend refresh, WebSocket updates)
- Pagination details (reached last page messages for groups/streams)
- Schedule syncing and viewing operations
- Channel database reloading in fuzzy matcher
These changes ensure that:
- INFO level shows only user-facing events and important state changes
- DEBUG level contains detailed operational and internal information
- Logs are consistent across all actions (preview_changes, add_streams, etc.)
- Cleaner log output for production use while maintaining debuggability
Benefits:
- Reduced log noise in production environments
- Easier troubleshooting with DEBUG level when needed
- Consistent logging patterns across the entire codebase
- Better separation between user-facing and internal operations
Changes to logging levels:
- Changed fuzzy_matcher channel database loading logs to DEBUG level
- Changed plugin validation and API authentication logs to DEBUG level
- Changed notification sending log to DEBUG level
- Changed per-file channel loading log to DEBUG level
Enhanced INFO logs:
- Updated total channels loaded log to include database names
- Added channel group statistics logging showing:
* Total number of groups processed
* For each group: name, channel count, and matched stream count
* Shows first 10 groups with summary for remaining groups
Benefits:
- Cleaner INFO logs show only essential information
- Detailed debugging information available at DEBUG level
- Better visibility into channel group processing and stream matching
- Easier troubleshooting with group-level statistics
Changes:
- Modified preview_changes_action to always reload channels before previewing
- Modified add_streams_to_channels_action to always reload channels before adding streams
- Removed file existence check that prevented reload when data was stale
- This ensures deleted channels (like ES DAZN 09/10) won't cause warnings
The processed data file is now refreshed on every preview/add operation,
ensuring users always work with current channel data from the Dispatcharr API.
Addresses issue where stale cached channel data causes foreign key errors when
attempting to create ChannelStream relationships for channels that no longer
exist in the database.
Changes:
- Add pre-validation check using Channel.objects.filter(id).exists() before
attempting any ChannelStream operations
- Gracefully skip deleted channels with warning log message including channel
name and ID
- Track count of skipped channels and report in final success message
- Suggest reloading channels when skipped channels are detected
This prevents the error:
"insert or update on table dispatcharr_channels_channelstream violates
foreign key constraint" when channel_id is not present in the channels table.
Integrates robust pagination error handling from PR #16 (by wdmitchell.uk)
into the current v0.6.0b codebase.
Changes:
- Add try-except error handling for all pagination API calls (groups and streams)
- Gracefully handle 404 errors when attempting to fetch non-existent pages
- Add empty result set detection to prevent unnecessary API calls
- Improve logging with detailed pagination status messages
- Re-raise errors only on first page (indicates real problem vs. end of pagination)
Fixes pagination bug where total records = exact multiple of page_size
(e.g., 700 streams with page_size=100 would crash on page 8)
Applied to 3 pagination loops:
1. Group fetching in validate_settings_action (line ~1693)
2. Group fetching in load_process_channels_action (line ~2019)
3. Stream fetching in load_process_channels_action (line ~2053)
Related: PR #16
# Stream-Mapparr Plugin Changelog (v0.6.0a -> v0.6.0b)
## New Features
* **Smart Analysis & Recommendations:**
* Added "What-if" analysis: Automatically tests matching at lower fuzzy thresholds (down to 65) to identify potential matches missed by current settings.
* Added Token Mismatch detection: Analyzes unmatched streams to suggest specific prefixes or suffixes (e.g., "US:", "HD") to add to the "Ignore Tags" list.
* **Enhanced CSV Export:**
* CSV files now include a detailed header section containing active settings, version info, and specific optimization recommendations based on the Smart Analysis.
* Rows now include data on potential matches found at lower thresholds.
* **Rate Limiting:** Added a "None (Disabled)" option to remove all artificial delays for faster processing on local networks.
* **Notifications:** Implemented WebSocket-based frontend notifications to display progress bars and success/error toasts during long-running operations.
## Improvements
* **Matching Logic:** Improved fuzzy matching algorithm to handle token overlap, better detecting matches where word order differs (e.g., "Channel Name US" vs "US Channel Name").
* **Maintenance:** Added a "Cleanup Orphaned Tasks" action to remove stale Celery Beat schedules left behind by older plugin versions.
* **Scheduling:** Updated schedule saving logic to provide immediate feedback on the next calculated run times in the local timezone.
## Internal
* Added `_get_matches_at_thresholds` and `_analyze_token_mismatch` methods to power the new recommendation engine.
* Refined `_clean_channel_name` to support optional country prefix removal.
- Update plugin.py version from 0.5.0 to 0.5.1
- Update fuzzy_matcher.py version from 25.314.1907 to 25.317.1200
- Remove 📚 Channel Databases header field from settings (keep dynamic database fields)
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.