chore(plex): trim LiveTvDvr to the fields Live TV renders

LiveTvDvr parsed 21 DVR fields plus nested Setting and raw Device lists
on every Live TV availability refresh, while the app reads only the key,
the three lineup labels, and the enabled channel mappings. The rest
describe tuner hardware and DVR setup, which Plezy does not implement.

Keep key, lineup, lineupTitle, lineupURL and channelMappings, and
channelKey/enabled on ChannelMapping. The tests keep the root
channel-mapping fallback, malformed-sibling tolerance and flexible
`enabled` parsing.
This commit is contained in:
edde746
2026-09-03 13:08:46 +02:00
parent deadf712a8
commit 4d2aa8f9a2
4 changed files with 10 additions and 91 deletions
+6 -55
View File
@@ -1,73 +1,26 @@
import 'package:json_annotation/json_annotation.dart';
import '../utils/json_utils.dart';
import 'media_subscription.dart';
part 'livetv_dvr.g.dart';
List<ChannelMapping> _parseChannelMappings(Object? raw) => parseFlexibleJsonList(raw, ChannelMapping.fromJson);
List<SubscriptionSetting> _parseSettings(Object? raw) => parseFlexibleJsonList(raw, SubscriptionSetting.fromJson);
List<Map<String, dynamic>> _parseRawMaps(Object? raw) => flexibleMapList(raw);
/// Represents a Plex Live TV DVR device (e.g., HDHomeRun tuner, IPTV provider)
/// A Plex Live TV DVR (e.g., HDHomeRun tuner, IPTV provider), reduced to what
/// Plezy renders: identity, lineup labelling, and the enabled-channel mapping.
/// Plex also reports tuner hardware, `Setting`, and `Device` relations for DVR
/// setup, which Plezy does not implement.
@JsonSerializable(createToJson: false)
class LiveTvDvr {
@JsonKey(defaultValue: '')
final String key;
@JsonKey(defaultValue: '')
final String uuid;
final String? make;
final String? model;
final String? modelNumber;
final String? firmware;
@JsonKey(fromJson: flexibleInt)
final int? tuners;
final String? lineup;
final String? lineupTitle;
final String? lineupURL;
final String? country;
final String? language;
@JsonKey(fromJson: flexibleInt)
final int? status;
@JsonKey(fromJson: flexibleInt)
final int? state;
final String? protocol;
final String? sources;
final String? uri;
@JsonKey(fromJson: flexibleInt)
final int? lastSeenAt;
@JsonKey(name: 'ChannelMapping', fromJson: _parseChannelMappings)
final List<ChannelMapping> channelMappings;
@JsonKey(name: 'Setting', fromJson: _parseSettings)
final List<SubscriptionSetting> settings;
@JsonKey(name: 'Device', fromJson: _parseRawMaps)
final List<Map<String, dynamic>> devices;
LiveTvDvr({
required this.key,
required this.uuid,
this.make,
this.model,
this.modelNumber,
this.firmware,
this.tuners,
this.lineup,
this.lineupTitle,
this.lineupURL,
this.country,
this.language,
this.status,
this.state,
this.protocol,
this.sources,
this.uri,
this.lastSeenAt,
this.channelMappings = const [],
this.settings = const [],
this.devices = const [],
});
LiveTvDvr({required this.key, this.lineup, this.lineupTitle, this.lineupURL, this.channelMappings = const []});
factory LiveTvDvr.fromJson(Map<String, dynamic> json) => _$LiveTvDvrFromJson(json);
}
@@ -76,12 +29,10 @@ class LiveTvDvr {
@JsonSerializable(createToJson: false)
class ChannelMapping {
final String? channelKey;
final String? deviceIdentifier;
@JsonKey(fromJson: flexibleBool)
final bool? enabled;
final String? lineupIdentifier;
ChannelMapping({this.channelKey, this.deviceIdentifier, this.enabled, this.lineupIdentifier});
ChannelMapping({this.channelKey, this.enabled});
factory ChannelMapping.fromJson(Map<String, dynamic> json) => _$ChannelMappingFromJson(json);
}
-20
View File
@@ -8,36 +8,16 @@ part of 'livetv_dvr.dart';
LiveTvDvr _$LiveTvDvrFromJson(Map<String, dynamic> json) => LiveTvDvr(
key: json['key'] as String? ?? '',
uuid: json['uuid'] as String? ?? '',
make: json['make'] as String?,
model: json['model'] as String?,
modelNumber: json['modelNumber'] as String?,
firmware: json['firmware'] as String?,
tuners: flexibleInt(json['tuners']),
lineup: json['lineup'] as String?,
lineupTitle: json['lineupTitle'] as String?,
lineupURL: json['lineupURL'] as String?,
country: json['country'] as String?,
language: json['language'] as String?,
status: flexibleInt(json['status']),
state: flexibleInt(json['state']),
protocol: json['protocol'] as String?,
sources: json['sources'] as String?,
uri: json['uri'] as String?,
lastSeenAt: flexibleInt(json['lastSeenAt']),
channelMappings: json['ChannelMapping'] == null
? const []
: _parseChannelMappings(json['ChannelMapping']),
settings: json['Setting'] == null
? const []
: _parseSettings(json['Setting']),
devices: json['Device'] == null ? const [] : _parseRawMaps(json['Device']),
);
ChannelMapping _$ChannelMappingFromJson(Map<String, dynamic> json) =>
ChannelMapping(
channelKey: json['channelKey'] as String?,
deviceIdentifier: json['deviceIdentifier'] as String?,
enabled: flexibleBool(json['enabled']),
lineupIdentifier: json['lineupIdentifier'] as String?,
);
@@ -10,20 +10,8 @@ void main() {
{'channelKey': 7},
{'channelKey': 'channel-1'},
],
'Setting': [
{'id': 7},
{'id': 'setting-1'},
],
'Device': [
'invalid',
{'uuid': 'device-1'},
],
});
expect(dvr.channelMappings.map((entry) => entry.channelKey), ['channel-1']);
expect(dvr.settings.map((entry) => entry.id), ['setting-1']);
expect(dvr.devices, [
{'uuid': 'device-1'},
]);
final template = SubscriptionTemplate.fromJson({
'MediaSubscription': [
+4 -4
View File
@@ -151,13 +151,13 @@ void main() {
]);
});
test('DVR list applies root channel mapping to each DVR and parses string numbers', () async {
test('DVR list applies root channel mapping to each DVR and parses flexible enabled flags', () async {
final client = makeClient((request) async {
expect(request.url.path, '/livetv/dvrs');
return jsonResponse({
'MediaContainer': {
'Dvr': [
{'key': '1', 'uuid': 'dvr-1', 'tuners': '2', 'status': '1'},
{'key': '1', 'uuid': 'dvr-1', 'lineupTitle': 'Antenna', 'tuners': '2', 'status': '1'},
],
'ChannelMapping': [
{'channelKey': 'ch-1', 'enabled': '1', 'lineupIdentifier': '001'},
@@ -170,8 +170,8 @@ void main() {
final dvrs = await client.liveTvDvr!.fetchDvrs();
expect(dvrs, hasLength(1));
expect(dvrs.single.tuners, 2);
expect(dvrs.single.status, 1);
expect(dvrs.single.key, '1');
expect(dvrs.single.lineupTitle, 'Antenna');
expect(dvrs.single.channelMappings.single.channelKey, 'ch-1');
expect(dvrs.single.channelMappings.single.enabled, isTrue);
});