fix: fan out multi-airing EPG metadata

close #563
This commit is contained in:
edde746
2026-04-17 03:36:27 +02:00
parent e63920e23b
commit 2e429840d2
2 changed files with 37 additions and 9 deletions
+26 -8
View File
@@ -44,11 +44,30 @@ class LiveTvProgram {
this.premiere,
});
factory LiveTvProgram.fromJson(Map<String, dynamic> json) {
// Grid endpoint nests timing/channel info inside Media[0] and Channel[0]
final media = (json['Media'] as List?)?.firstOrNull as Map<String, dynamic>?;
factory LiveTvProgram.fromJson(
Map<String, dynamic> json, {
Map<String, dynamic>? mediaOverride,
}) {
// Grid endpoint nests timing/channel info inside Media[] and Channel[].
// When mediaOverride is supplied, the caller is pinning this parse to a
// specific airing (one Media entry); treat it as authoritative for
// begin/end/channel fields.
final hasOverride = mediaOverride != null;
final media = mediaOverride ?? (json['Media'] as List?)?.firstOrNull as Map<String, dynamic>?;
final channel = (json['Channel'] as List?)?.firstOrNull as Map<String, dynamic>?;
int? pickInt(String key) {
final fromMedia = (media?[key] as num?)?.toInt();
final fromJson = (json[key] as num?)?.toInt();
return hasOverride ? (fromMedia ?? fromJson) : (fromJson ?? fromMedia);
}
String? pickString(String key) {
final fromMedia = media?[key]?.toString();
final fromJson = json[key] as String?;
return hasOverride ? (fromMedia ?? fromJson) : (fromJson ?? fromMedia);
}
return LiveTvProgram(
key: json['key'] as String?,
ratingKey: json['ratingKey'] as String?,
@@ -57,17 +76,16 @@ class LiveTvProgram {
summary: json['summary'] as String?,
type: json['type'] as String?,
year: (json['year'] as num?)?.toInt(),
beginsAt: (json['beginsAt'] as num?)?.toInt() ?? (media?['beginsAt'] as num?)?.toInt(),
endsAt: (json['endsAt'] as num?)?.toInt() ?? (media?['endsAt'] as num?)?.toInt(),
beginsAt: pickInt('beginsAt'),
endsAt: pickInt('endsAt'),
grandparentTitle: json['grandparentTitle'] as String?,
parentTitle: json['parentTitle'] as String?,
index: (json['index'] as num?)?.toInt(),
parentIndex: (json['parentIndex'] as num?)?.toInt(),
thumb: json['thumb'] as String? ?? json['grandparentThumb'] as String?,
art: json['art'] as String?,
channelIdentifier:
json['channelIdentifier'] as String? ?? media?['channelIdentifier']?.toString() ?? channel?['id']?.toString(),
channelCallSign: json['channelCallSign'] as String? ?? media?['channelCallSign'] as String?,
channelIdentifier: pickString('channelIdentifier') ?? channel?['id']?.toString(),
channelCallSign: pickString('channelCallSign'),
live: flexibleBool(json['live']),
premiere: flexibleBool(json['premiere']),
);
+11 -1
View File
@@ -2332,11 +2332,21 @@ class PlexClient {
}
/// Parse a list of JSON items into [LiveTvProgram] objects, skipping any that fail.
/// A single Metadata entry may carry multiple Media entries representing back-to-back
/// airings of the same program on the same channel; emit one program per airing.
List<LiveTvProgram> _parseLiveTvPrograms(List items) {
final programs = <LiveTvProgram>[];
for (final item in items) {
try {
programs.add(LiveTvProgram.fromJson(item as Map<String, dynamic>));
final map = item as Map<String, dynamic>;
final mediaList = (map['Media'] as List?)?.whereType<Map<String, dynamic>>().toList();
if (mediaList != null && mediaList.length > 1) {
for (final media in mediaList) {
programs.add(LiveTvProgram.fromJson(map, mediaOverride: media));
}
} else {
programs.add(LiveTvProgram.fromJson(map));
}
} catch (_) {}
}
return programs;