mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 00:55:50 +00:00
Bug Fix: EPG channel name vlaue too long for type character varying(255) (Fixes #1134)
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
This commit is contained in:
parent
844ef4667a
commit
69e0cba86e
7 changed files with 60 additions and 3 deletions
|
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- **EPG channel name truncation**: EPG sources that include long `<display-name>` values (e.g. event-based channels with descriptions appended to the name) would crash the channel-parse task with a `value too long for type character varying(255)` PostgreSQL error and silently discard the entire batch. The `EPGData.name`, `Stream.name`, and `Channel.name` fields have been widened to 512 characters, and names exceeding this limit are now truncated with a warning log rather than aborting the import. (Fixes #1134)
|
||||
|
||||
### Added
|
||||
|
||||
- **Plugin warning & disclaimer components**: extracted shared plugin warning UI into a new `PluginWarnings.jsx` component and normalized warning/disclaimer usage across all plugin action modals. New reusable components: `PluginSecurityWarning` (untrusted code), `PluginSupportDisclaimer` (community support scope), `PluginDowngradeWarning` (version downgrade), `PluginInfoNote` (informational), and `PluginRestartWarning` (backend restart on import). Updated `Plugins.jsx`, `AvailablePluginCard.jsx`, and `PluginCard.jsx` to use the shared components. — Thanks [@sethwv](https://github.com/sethwv)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 6.0.4 on 2026-04-21 14:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dispatcharr_channels', '0034_remove_stream_dispatcharr_stream_id_idx_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='channel',
|
||||
name='name',
|
||||
field=models.CharField(max_length=512),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='stream',
|
||||
name='name',
|
||||
field=models.CharField(default='Default Stream', max_length=512),
|
||||
),
|
||||
]
|
||||
|
|
@ -56,7 +56,7 @@ class Stream(models.Model):
|
|||
Represents a single stream (e.g. from an M3U source or custom URL).
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255, default="Default Stream")
|
||||
name = models.CharField(max_length=512, default="Default Stream")
|
||||
url = models.URLField(max_length=4096, blank=True, null=True)
|
||||
m3u_account = models.ForeignKey(
|
||||
M3UAccount,
|
||||
|
|
@ -294,7 +294,7 @@ class ChannelManager(models.Manager):
|
|||
|
||||
class Channel(models.Model):
|
||||
channel_number = models.FloatField(db_index=True)
|
||||
name = models.CharField(max_length=255)
|
||||
name = models.CharField(max_length=512)
|
||||
logo = models.ForeignKey(
|
||||
"Logo",
|
||||
on_delete=models.SET_NULL,
|
||||
|
|
|
|||
18
apps/epg/migrations/0022_alter_epgdata_name.py
Normal file
18
apps/epg/migrations/0022_alter_epgdata_name.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 6.0.4 on 2026-04-21 14:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('epg', '0021_epgsource_priority'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='epgdata',
|
||||
name='name',
|
||||
field=models.CharField(max_length=512),
|
||||
),
|
||||
]
|
||||
|
|
@ -137,7 +137,7 @@ class EPGData(models.Model):
|
|||
# Removed the Channel foreign key. We now just store the original tvg_id
|
||||
# and a name (which might simply be the tvg_id if no real channel exists).
|
||||
tvg_id = models.CharField(max_length=255, null=True, blank=True, db_index=True)
|
||||
name = models.CharField(max_length=255)
|
||||
name = models.CharField(max_length=512)
|
||||
icon_url = models.URLField(max_length=500, null=True, blank=True)
|
||||
epg_source = models.ForeignKey(
|
||||
EPGSource,
|
||||
|
|
|
|||
|
|
@ -966,6 +966,7 @@ def parse_channels_only(source):
|
|||
batch_size = 500 # Process in batches to limit memory usage
|
||||
progress = 0 # Initialize progress variable here
|
||||
icon_url_max_length = EPGData._meta.get_field('icon_url').max_length # Get max length for icon_url field
|
||||
name_max_length = EPGData._meta.get_field('name').max_length # Get max length for name field
|
||||
|
||||
# Track memory at key points
|
||||
if process:
|
||||
|
|
@ -1022,6 +1023,10 @@ def parse_channels_only(source):
|
|||
if not display_name:
|
||||
display_name = tvg_id
|
||||
|
||||
if display_name and len(display_name) > name_max_length:
|
||||
logger.warning(f"EPG display name too long ({len(display_name)} > {name_max_length}), truncating: {display_name[:80]}...")
|
||||
display_name = display_name[:name_max_length]
|
||||
|
||||
# Use lazy loading approach to reduce memory usage
|
||||
if tvg_id in existing_tvg_ids:
|
||||
# Only fetch the object if we need to update it and it hasn't been loaded yet
|
||||
|
|
|
|||
|
|
@ -1087,6 +1087,8 @@ def process_m3u_batch_direct(account_id, batch, groups, hash_keys):
|
|||
streams_to_update = []
|
||||
stream_hashes = {}
|
||||
|
||||
name_max_length = Stream._meta.get_field('name').max_length
|
||||
|
||||
logger.debug(f"Processing batch of {len(batch)} for M3U account {account_id}")
|
||||
if compiled_filters:
|
||||
logger.debug(f"Using compiled filters: {[f[1].regex_pattern for f in compiled_filters]}")
|
||||
|
|
@ -1099,6 +1101,11 @@ def process_m3u_batch_direct(account_id, batch, groups, hash_keys):
|
|||
logger.warning(f"Skipping stream '{name}': URL too long ({len(url)} characters, max 4096)")
|
||||
continue
|
||||
|
||||
# Truncate name if it exceeds the model field limit
|
||||
if name and len(name) > name_max_length:
|
||||
logger.warning(f"Stream name too long ({len(name)} > {name_max_length}), truncating: {name[:80]}...")
|
||||
name = name[:name_max_length]
|
||||
|
||||
tvg_id, tvg_logo = get_case_insensitive_attr(
|
||||
stream_info["attributes"], "tvg-id", ""
|
||||
), get_case_insensitive_attr(stream_info["attributes"], "tvg-logo", "")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue