fix(livetv): show active recording indicators

close #1076
This commit is contained in:
edde746
2026-05-21 00:19:21 +02:00
parent 209101796b
commit 0582ab2947
2 changed files with 65 additions and 6 deletions
+21 -6
View File
@@ -309,19 +309,34 @@ class GuideTabState extends State<GuideTab> with MountedSetStateMixin {
try {
final grabs = await client.liveTv.fetchScheduledRecordings();
for (final grab in grabs) {
if (!_isActiveScheduledGrab(grab)) continue;
final program = grab.program;
if (program == null) continue;
keys.addAll(_recordingKeysForProgram(program, fallbackServerId: serverId));
_addRecordingKeysForGrab(grab, serverId: serverId, keys: keys);
}
} catch (e) {
appLogger.d('Failed to load scheduled recordings for $serverId', error: e);
}
try {
final rules = await client.liveTv.fetchRecordingRules(includeGrabs: true, includeStorage: false);
for (final rule in rules) {
for (final grab in rule.grabOperations) {
_addRecordingKeysForGrab(grab, serverId: serverId, keys: keys);
}
}
} catch (e) {
appLogger.d('Failed to load active recording grabs for $serverId', error: e);
}
}
void _addRecordingKeysForGrab(MediaGrabOperation grab, {required String serverId, required Set<String> keys}) {
if (!_isActiveScheduledGrab(grab)) return;
final program = grab.program;
if (program == null) return;
keys.addAll(_recordingKeysForProgram(program, fallbackServerId: serverId));
}
bool _isActiveScheduledGrab(MediaGrabOperation grab) {
final status = grab.status?.toLowerCase();
return status == null || status.isEmpty || status == 'scheduled' || status == 'grabbing';
final status = grab.status?.trim().toLowerCase();
return status == null || status.isEmpty || status == 'scheduled' || status == 'grabbing' || status == 'recording';
}
bool _isRecordingScheduled(LiveTvProgram program) {
@@ -237,6 +237,50 @@ void main() {
expect(updated?.key, '18');
});
test('recording rules parse active grab operation metadata', () async {
late http.Request captured;
final client = makeClient((request) async {
captured = request;
return jsonResponse({
'MediaContainer': {
'MediaSubscription': [
{
'key': '18',
'type': 4,
'title': 'Episode',
'MediaGrabOperation': [
{
'id': 'grab-active',
'status': 'grabbing',
'Metadata': {
'title': 'Live Episode',
'ratingKey': 'episode-1',
'guid': 'plex://episode/1',
'Media': [
{'beginsAt': '1466060400', 'endsAt': '1466062200', 'channelIdentifier': '004'},
],
},
},
],
},
],
},
});
});
addTearDown(client.close);
final rules = await client.liveTv.fetchRecordingRules(includeGrabs: true, includeStorage: false);
expect(captured.url.path, '/media/subscriptions');
expect(captured.url.queryParameters['includeGrabs'], '1');
expect(captured.url.queryParameters['includeStorage'], '0');
final grab = rules.single.grabOperations.single;
expect(grab.status, 'grabbing');
expect(grab.program?.ratingKey, 'episode-1');
expect(grab.program?.guid, 'plex://episode/1');
expect(grab.program?.channelIdentifier, '004');
});
test('cancelGrab deletes the operation key path', () async {
late http.Request captured;
final client = makeClient((request) async {