refactor(epg/guide): streamline season/episode extraction and guide card layout

- Consolidate serializer season/episode parsing into a single to_representation
  pass: one custom_properties read, regex runs at most once per program
- Compact card: S/E badge inline with title; secondary row shows sub_title with
  description fallback
- Expanded card: sub_title and S/E badge share a row above the description
- Fix secondary text color for legibility on dark backgrounds (#a0aec0 → #e2e8f0)
- Fix expanded card overflow (height:100% → flex:1 1 0) so action buttons stay visible
- Bump expanded card height 180 → 200px, description max-height 80 → 100px
This commit is contained in:
SergeantPanda 2026-03-06 10:44:11 -06:00
parent ee112de84a
commit fa0a963ad9
3 changed files with 74 additions and 52 deletions

View file

@ -83,38 +83,26 @@ class EPGSourceSerializer(serializers.ModelSerializer):
return instance
class ProgramDataSerializer(serializers.ModelSerializer):
season = serializers.SerializerMethodField()
episode = serializers.SerializerMethodField()
class Meta:
model = ProgramData
fields = ['id', 'start_time', 'end_time', 'title', 'sub_title', 'description', 'tvg_id', 'season', 'episode']
fields = ['id', 'start_time', 'end_time', 'title', 'sub_title', 'description', 'tvg_id']
def _parse_onscreen(self, obj):
"""Parse season/episode from onscreen_episode string (e.g. 'S12 E6')."""
onscreen = (obj.custom_properties or {}).get('onscreen_episode', '')
match = _ONSCREEN_RE.search(onscreen)
if match:
return int(match.group(1)), int(match.group(2))
return None, None
def get_season(self, obj):
if obj.custom_properties:
season = obj.custom_properties.get('season')
if season is not None:
return season
season, _ = self._parse_onscreen(obj)
return season
return None
def get_episode(self, obj):
if obj.custom_properties:
episode = obj.custom_properties.get('episode')
if episode is not None:
return episode
_, episode = self._parse_onscreen(obj)
return episode
return None
def to_representation(self, obj):
data = super().to_representation(obj)
cp = obj.custom_properties or {}
season = cp.get('season')
episode = cp.get('episode')
# Only run the regex if at least one value is still missing
if (season is None or episode is None) and cp.get('onscreen_episode'):
match = _ONSCREEN_RE.search(cp['onscreen_episode'])
if match:
if season is None:
season = int(match.group(1))
if episode is None:
episode = int(match.group(2))
data['season'] = season
data['episode'] = episode
return data
class EPGDataSerializer(serializers.ModelSerializer):
"""