fix(plex): tolerate scalar schema drift

This commit is contained in:
edde746
2026-07-12 08:42:18 +02:00
parent a809cbbcef
commit 9c6fcbc841
14 changed files with 197 additions and 79 deletions
+10 -10
View File
@@ -14,14 +14,14 @@ void main() {
test('captures the first video stream and accumulates audio + subs', () {
final streams = [
// streamType 1=video, 2=audio, 3=subtitle
{'streamType': 1, 'id': 100, 'frameRate': 23.976, 'colorSpace': 'bt709'},
{'streamType': '1', 'id': '100', 'frameRate': 23.976, 'colorSpace': 'bt709'},
{
'streamType': 2,
'id': 101,
'index': 1,
'streamType': '2',
'id': '101',
'index': '1',
'codec': 'eac3',
'language': 'English',
'channels': 6,
'channels': '6',
'selected': true,
'displayTitle': 'English (EAC3 5.1)',
},
@@ -35,9 +35,9 @@ void main() {
'selected': false,
},
{
'streamType': 3,
'id': 200,
'index': 3,
'streamType': '3',
'id': '200',
'index': '3',
'codec': 'srt',
'language': 'English',
'forced': false,
@@ -48,8 +48,8 @@ void main() {
final out = walkStreams(streams, reader);
expect(out.videoStream?['id'], 100);
expect(out.audioStream?['id'], 101);
expect(out.videoStream?['id'], '100');
expect(out.audioStream?['id'], '101');
expect(out.videoStream?['frameRate'], closeTo(23.976, 1e-6));
expect(out.audioTracks.map((t) => t.id), [101, 102]);
expect(out.audioTracks[0].channels, 6);
+31
View File
@@ -79,6 +79,37 @@ void main() {
expect(response.profile.defaultAudioLanguages, ['en', 'sv']);
expect(response.profile.defaultSubtitleLanguages, ['en', 'sv']);
});
test('fetchServers tolerates scalar drift in server and connection fields', () async {
final server = _serverJson()
..['owned'] = '1'
..['presence'] = 1
..['product'] = 42
..['lastSeenAt'] = 123;
final connection = (server['connections'] as List).single as Map<String, dynamic>
..['port'] = '32400'
..['local'] = '1'
..['relay'] = 0
..['IPv6'] = 'false';
final client = MediaServerHttpClient(
client: MockClient(
(_) async => http.Response(jsonEncode([server]), 200, headers: {'content-type': 'application/json'}),
),
);
addTearDown(client.close);
final servers = await PlexAuthService.forTesting(http: client).fetchServers('token');
expect(servers.single.owned, isTrue);
expect(servers.single.presence, isTrue);
expect(servers.single.product, '42');
expect(servers.single.lastSeenAt, isNull);
expect(connection['port'], '32400');
expect(servers.single.connections.first.port, 32400);
expect(servers.single.connections.first.local, isTrue);
expect(servers.single.connections.first.relay, isFalse);
expect(servers.single.connections.first.ipv6, isFalse);
});
});
}
@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
@@ -53,4 +55,34 @@ void main() {
expect(await client.createCollectionFromUri(sectionId: '1', title: 'Collection', uri: 'server://items'), isNull);
expect(await client.createPlayQueue(uri: 'server://items', type: 'video'), isNull);
});
test('play queue accepts numeric strings from Plex', () async {
final client = makeClient(
(_) async => http.Response(
jsonEncode({
'MediaContainer': {
'playQueueID': '42',
'playQueueSelectedItemID': '7',
'playQueueSelectedItemOffset': '1',
'playQueueTotalCount': '3',
'playQueueVersion': '5',
'size': '3',
'Metadata': <dynamic>[],
},
}),
200,
headers: {'content-type': 'application/json'},
),
);
addTearDown(client.close);
final queue = await client.createPlayQueue(uri: 'server://items', type: 'video');
expect(queue?.playQueueID, 42);
expect(queue?.playQueueSelectedItemID, 7);
expect(queue?.playQueueSelectedItemOffset, 1);
expect(queue?.playQueueTotalCount, 3);
expect(queue?.playQueueVersion, 5);
expect(queue?.size, 3);
});
}
+13
View File
@@ -9,6 +9,19 @@ const _serverId = 'plex-machine-1';
const _serverName = 'Home';
void main() {
test('PlexMetadataDto accepts string ratings', () {
final dto = PlexMetadataDto.fromJson({
'ratingKey': '1',
'rating': '8.8',
'audienceRating': '9.1',
'userRating': '9.5',
});
expect(dto.rating, 8.8);
expect(dto.audienceRating, 9.1);
expect(dto.userRating, 9.5);
});
group('PlexMappers.mediaItem (movie)', () {
test('maps a Plex movie with watch state, ratings, genres, and people', () {
final json = {
+20 -13
View File
@@ -343,32 +343,39 @@ void main() {
'container': 'mkv',
'videoCodec': 'h264',
'videoResolution': '1080',
'width': 1920,
'height': 1080,
'aspectRatio': 1.78,
'bitrate': 8000,
'duration': 120000,
'width': '1920',
'height': '1080',
'aspectRatio': '1.78',
'bitrate': '8000',
'duration': '120000',
'audioCodec': 'aac',
'audioChannels': 2,
'audioChannels': '2',
'optimizedForStreaming': '1',
'has64bitOffsets': 0,
'Part': [
{
'file': '/media/movie.mkv',
'size': 123456,
'size': '123456',
'Stream': [
{'streamType': 1, 'frameRate': 24, 'colorSpace': 'bt709', 'bitDepth': 8, 'bitrate': 7000},
{'streamType': '1', 'frameRate': '24', 'colorSpace': 'bt709', 'bitDepth': '8', 'bitrate': '7000'},
{
'streamType': 2,
'id': 301,
'index': 0,
'streamType': '2',
'id': '301',
'index': '0',
'language': 'English',
'languageCode': 'eng',
'channels': 2,
'channels': '2',
'selected': true,
'audioChannelLayout': 'stereo',
},
{'streamType': 3, 'id': 401, 'index': 0, 'languageCode': 'eng', 'forced': 0, 'key': '/subtitles/401'},
{
'streamType': '3',
'id': '401',
'index': '0',
'languageCode': 'eng',
'forced': 0,
'key': '/subtitles/401',
},
],
},
],