mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 17:16:26 +00:00
show lineup name in EPG channel dropdown for Schedules Direct sources
This commit is contained in:
parent
578c50ea96
commit
15bb0cc4f6
5 changed files with 52 additions and 11 deletions
16
apps/epg/migrations/0027_epgdata_lineup.py
Normal file
16
apps/epg/migrations/0027_epgdata_lineup.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('epg', '0026_epgsourceindex'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='epgdata',
|
||||
name='lineup',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -153,6 +153,7 @@ class EPGData(models.Model):
|
|||
tvg_id = models.CharField(max_length=255, null=True, blank=True, db_index=True)
|
||||
name = models.CharField(max_length=512)
|
||||
icon_url = models.URLField(max_length=500, null=True, blank=True)
|
||||
lineup = models.CharField(max_length=255, null=True, blank=True)
|
||||
epg_source = models.ForeignKey(
|
||||
EPGSource,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ class EPGDataSerializer(serializers.ModelSerializer):
|
|||
'tvg_id',
|
||||
'name',
|
||||
'icon_url',
|
||||
'lineup',
|
||||
'epg_source',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -2971,12 +2971,20 @@ def fetch_schedules_direct(
|
|||
headers=_sd_headers(),
|
||||
timeout=30,
|
||||
)
|
||||
token_response.raise_for_status()
|
||||
token_data = token_response.json()
|
||||
# Parse the response body first so we can surface SD's own error message
|
||||
# regardless of HTTP status code (SD sometimes returns 400 for app-level
|
||||
# errors like SERVICE_OFFLINE that carry a meaningful JSON body).
|
||||
try:
|
||||
token_data = token_response.json()
|
||||
except Exception:
|
||||
token_response.raise_for_status()
|
||||
raise
|
||||
|
||||
auth_code = token_data.get('code', 0)
|
||||
if auth_code != 0:
|
||||
if auth_code == 4007:
|
||||
if not token_response.ok or auth_code != 0:
|
||||
if auth_code == 3000:
|
||||
msg = "Schedules Direct is offline for maintenance. Try again later."
|
||||
elif auth_code == 4007:
|
||||
msg = "Schedules Direct: this application is not authorized. Please contact the Dispatcharr maintainers."
|
||||
elif auth_code == 4004:
|
||||
msg = "Schedules Direct: account locked due to too many failed login attempts. Try again in 15 minutes."
|
||||
|
|
@ -2986,8 +2994,13 @@ def fetch_schedules_direct(
|
|||
msg = "Schedules Direct: account has expired. Please renew your subscription at schedulesdirect.org."
|
||||
elif auth_code == 4008:
|
||||
msg = "Schedules Direct: account is inactive. Please log in to schedulesdirect.org to reactivate."
|
||||
else:
|
||||
elif auth_code == 4003:
|
||||
msg = "Schedules Direct: invalid username or password."
|
||||
elif auth_code != 0:
|
||||
msg = f"Schedules Direct authentication failed (code {auth_code}): {token_data.get('message', 'Unknown error')}"
|
||||
else:
|
||||
token_response.raise_for_status()
|
||||
raise RuntimeError(f"Unexpected SD token response: {token_response.text}")
|
||||
logger.error(msg)
|
||||
source.status = EPGSource.STATUS_ERROR
|
||||
source.last_message = msg
|
||||
|
|
@ -3118,6 +3131,7 @@ def fetch_schedules_direct(
|
|||
lineup_id = lineup.get('lineupID') or lineup.get('lineup')
|
||||
if not lineup_id:
|
||||
continue
|
||||
lineup_name = lineup.get('name') or lineup_id
|
||||
try:
|
||||
detail_response = requests.get(
|
||||
f"{SD_BASE_URL}/lineups/{lineup_id}",
|
||||
|
|
@ -3143,6 +3157,8 @@ def fetch_schedules_direct(
|
|||
'name': station.get('name', sid),
|
||||
'callsign': station.get('callsign', ''),
|
||||
'logo_url': logo_url,
|
||||
# Preserve lineup from first encounter if station appears in multiple lineups
|
||||
'lineup': station_map.get(sid, {}).get('lineup') or lineup_name,
|
||||
}
|
||||
logger.debug(f"Fetched {len(detail_data.get('stations', []))} stations from lineup {lineup_id}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
|
|
@ -3182,6 +3198,7 @@ def fetch_schedules_direct(
|
|||
logo = info['logo_url']
|
||||
if logo and len(logo) > icon_max_length:
|
||||
logo = None
|
||||
lineup_val = info.get('lineup')
|
||||
|
||||
if sid in existing_epg_map:
|
||||
epg_obj = existing_epg_map[sid]
|
||||
|
|
@ -3192,6 +3209,9 @@ def fetch_schedules_direct(
|
|||
if epg_obj.icon_url != logo:
|
||||
epg_obj.icon_url = logo
|
||||
needs_update = True
|
||||
if epg_obj.lineup != lineup_val:
|
||||
epg_obj.lineup = lineup_val
|
||||
needs_update = True
|
||||
if needs_update:
|
||||
epgs_to_update.append(epg_obj)
|
||||
else:
|
||||
|
|
@ -3199,6 +3219,7 @@ def fetch_schedules_direct(
|
|||
tvg_id=sid,
|
||||
name=display_name,
|
||||
icon_url=logo,
|
||||
lineup=lineup_val,
|
||||
epg_source=source,
|
||||
))
|
||||
|
||||
|
|
@ -3206,7 +3227,7 @@ def fetch_schedules_direct(
|
|||
EPGData.objects.bulk_create(epgs_to_create, ignore_conflicts=True)
|
||||
logger.info(f"Created {len(epgs_to_create)} new EPGData entries.")
|
||||
if epgs_to_update:
|
||||
EPGData.objects.bulk_update(epgs_to_update, ['name', 'icon_url'])
|
||||
EPGData.objects.bulk_update(epgs_to_update, ['name', 'icon_url', 'lineup'])
|
||||
logger.info(f"Updated {len(epgs_to_update)} existing EPGData entries.")
|
||||
|
||||
gc.collect()
|
||||
|
|
|
|||
|
|
@ -1179,11 +1179,13 @@ const ChannelForm = ({ channel: channelProp = null, isOpen, onClose }) => {
|
|||
setEpgPopoverOpened(false);
|
||||
}}
|
||||
>
|
||||
{filteredTvgs[index].name &&
|
||||
filteredTvgs[index].tvg_id
|
||||
? `${filteredTvgs[index].name} (${filteredTvgs[index].tvg_id})`
|
||||
: filteredTvgs[index].name ||
|
||||
filteredTvgs[index].tvg_id}
|
||||
{(() => {
|
||||
const tvg = filteredTvgs[index];
|
||||
const base = tvg.name && tvg.tvg_id
|
||||
? `${tvg.name} (${tvg.tvg_id})`
|
||||
: tvg.name || tvg.tvg_id;
|
||||
return tvg.lineup ? `${base} [${tvg.lineup}]` : base;
|
||||
})()}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue