Bug Fix: XC stream refresh crashing with a null value in column "name" database error when a provider returns streams with a null or empty name. Affected streams are now assigned a generated fallback name in the format <account name> - <stream_id> so the refresh completes successfully and the stream remains accessible. A warning is logged for each affected stream.

This commit is contained in:
SergeantPanda 2026-03-07 18:33:17 -06:00
parent 639b3ea4af
commit 9876a25e62
2 changed files with 16 additions and 2 deletions

View file

@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- XC stream refresh crashing with a `null value in column "name"` database error when a provider returns streams with a null or empty name. Affected streams are now assigned a generated fallback name in the format `<account name> - <stream_id>` so the refresh completes successfully and the stream remains accessible. A warning is logged for each affected stream.
- 504 Gateway Timeout when saving M3U group settings on slower hardware (e.g. Synology NAS). Replaced per-row `update_or_create()` loops with `bulk_create(update_conflicts=True)` wrapped in `transaction.atomic()` for both `ChannelGroupM3UAccount` and `M3UVODCategoryRelation`, reducing hundreds of individual DB round-trips to a single query per model. (Fixes #745) — Thanks [@nickgerrer](https://github.com/nickgerrer)
- Improved frontend table stability during M3U imports: Fixed incorrect default `state` initialization (`[]``{}`) in `CustomTable` to match TanStack Table v8's expected state object shape. Added `autoResetPageIndex: false` and `autoResetExpanded: false` to prevent TanStack Table from issuing internal state resets on data updates. Memoized `processedData` in `M3UsTable` to avoid redundant sort/filter recomputation on re-renders. - Thanks [@marcinolek](https://github.com/marcinolek)
- `debian_install.sh` hardened for non-UTF8 environments (common in minimal LXC containers) - Thanks [@marcinolek](https://github.com/marcinolek)

View file

@ -751,6 +751,14 @@ def collect_xc_streams(account_id, enabled_groups):
# Filter streams based on enabled categories
filtered_count = 0
for stream in all_xc_streams:
# Fall back to a generated name if the provider returns null/empty
stream_name = stream.get("name") or f"{account.name} - {stream.get('stream_id', 'Unknown')}"
if not stream.get("name"):
logger.warning(
f"XC stream has null/empty name; using generated name '{stream_name}' "
f"(stream_id={stream.get('stream_id', 'unknown')})"
)
# Get the category_id for this stream
category_id = str(stream.get("category_id", ""))
@ -760,7 +768,7 @@ def collect_xc_streams(account_id, enabled_groups):
# Convert XC stream to our standard format with all properties preserved
stream_data = {
"name": stream["name"],
"name": stream_name,
"url": xc_client.get_stream_url(stream["stream_id"]),
"attributes": {
"tvg-id": stream.get("epg_channel_id", ""),
@ -844,7 +852,12 @@ def process_xc_category_direct(account_id, batch, groups, hash_keys):
)
for stream in streams:
name = stream["name"]
name = stream.get("name") or f"{account.name} - {stream.get('stream_id', 'Unknown')}"
if not stream.get("name"):
logger.warning(
f"XC stream has null/empty name in category {group_name}; "
f"using generated name '{name}' (stream_id={stream.get('stream_id', 'unknown')})"
)
raw_stream_id = stream.get("stream_id", "")
provider_stream_id = None
if raw_stream_id: