fix(plex): fail open on unknown transcode capability
This commit is contained in:
@@ -188,6 +188,17 @@ class ConnectionTestResult {
|
||||
ConnectionTestResult({required this.success, required this.latencyMs, this.error, this.transcoderVideo});
|
||||
}
|
||||
|
||||
bool? _parsePlexTranscoderVideoCapability(Object? value) {
|
||||
return switch (value) {
|
||||
final bool b => b,
|
||||
final int n when n == 1 => true,
|
||||
final int n when n == 0 => false,
|
||||
final String s when s.trim().toLowerCase() == 'true' || s.trim() == '1' => true,
|
||||
final String s when s.trim().toLowerCase() == 'false' || s.trim() == '0' => false,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
class PlexClient
|
||||
with MediaServerCacheMixin, _PlexLiveTvClientMethods
|
||||
implements MediaServerClient, GracefullyCloseable {
|
||||
@@ -592,7 +603,9 @@ class PlexClient
|
||||
|
||||
bool? transcoderVideo;
|
||||
if (success && response.data is Map && response.data['MediaContainer'] is Map) {
|
||||
transcoderVideo = flexibleBool((response.data['MediaContainer'] as Map)['transcoderVideo']);
|
||||
transcoderVideo = _parsePlexTranscoderVideoCapability(
|
||||
(response.data['MediaContainer'] as Map)['transcoderVideo'],
|
||||
);
|
||||
}
|
||||
|
||||
return ConnectionTestResult(
|
||||
@@ -2815,7 +2828,7 @@ class PlexClient
|
||||
final response = await _http.get('/', timeout: const Duration(seconds: 5));
|
||||
final container = _getMediaContainer(response);
|
||||
final value = container?['transcoderVideo'];
|
||||
final supported = flexibleBool(value);
|
||||
final supported = _parsePlexTranscoderVideoCapability(value) ?? true;
|
||||
_serverTranscoderCached = supported;
|
||||
return supported;
|
||||
} catch (e) {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/testing.dart';
|
||||
import 'package:plezy/database/app_database.dart';
|
||||
import 'package:plezy/models/plex/plex_config.dart';
|
||||
import 'package:plezy/services/plex_api_cache.dart';
|
||||
import 'package:plezy/services/plex_client.dart';
|
||||
|
||||
void main() {
|
||||
late AppDatabase db;
|
||||
|
||||
setUp(() {
|
||||
db = AppDatabase.forTesting(NativeDatabase.memory());
|
||||
PlexApiCache.initialize(db);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
group('Plex transcoder capability', () {
|
||||
test('client probe fails open when transcoderVideo is absent', () async {
|
||||
final client = _makeClient({'friendlyName': 'Plex'});
|
||||
addTearDown(client.close);
|
||||
|
||||
final supported = await client.serverSupportsVideoTranscoding();
|
||||
|
||||
expect(supported, isTrue);
|
||||
expect(client.capabilities.videoTranscoding, isTrue);
|
||||
});
|
||||
|
||||
test('client probe preserves explicit transcoderVideo false', () async {
|
||||
final client = _makeClient({'transcoderVideo': false});
|
||||
addTearDown(client.close);
|
||||
|
||||
final supported = await client.serverSupportsVideoTranscoding();
|
||||
|
||||
expect(supported, isFalse);
|
||||
expect(client.capabilities.videoTranscoding, isFalse);
|
||||
});
|
||||
|
||||
test('connection probe keeps absent transcoderVideo unknown', () async {
|
||||
final server = await _startRootServer({'friendlyName': 'Plex'});
|
||||
addTearDown(() async => server.close(force: true));
|
||||
|
||||
final result = await PlexClient.testConnectionWithLatency(
|
||||
_serverBaseUrl(server),
|
||||
'token',
|
||||
timeout: const Duration(seconds: 2),
|
||||
clientIdentifier: 'client-id',
|
||||
);
|
||||
|
||||
expect(result.success, isTrue);
|
||||
expect(result.transcoderVideo, isNull);
|
||||
});
|
||||
|
||||
test('connection probe preserves explicit transcoderVideo false', () async {
|
||||
final server = await _startRootServer({'transcoderVideo': false});
|
||||
addTearDown(() async => server.close(force: true));
|
||||
|
||||
final result = await PlexClient.testConnectionWithLatency(
|
||||
_serverBaseUrl(server),
|
||||
'token',
|
||||
timeout: const Duration(seconds: 2),
|
||||
clientIdentifier: 'client-id',
|
||||
);
|
||||
|
||||
expect(result.success, isTrue);
|
||||
expect(result.transcoderVideo, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
PlexClient _makeClient(Map<String, dynamic> rootContainer) {
|
||||
return PlexClient.forTesting(
|
||||
config: PlexConfig(
|
||||
baseUrl: 'https://plex.example.com',
|
||||
token: 'token',
|
||||
clientIdentifier: 'client-id',
|
||||
product: 'Plezy',
|
||||
version: 'test',
|
||||
),
|
||||
serverId: 'server-id',
|
||||
httpClient: MockClient((request) async {
|
||||
expect(request.url.path, '/');
|
||||
return http.Response(
|
||||
jsonEncode({'MediaContainer': rootContainer}),
|
||||
200,
|
||||
headers: {'content-type': 'application/json'},
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<HttpServer> _startRootServer(Map<String, dynamic> rootContainer) async {
|
||||
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||
server.listen((request) async {
|
||||
if (request.uri.path != '/') {
|
||||
request.response.statusCode = HttpStatus.notFound;
|
||||
await request.response.close();
|
||||
return;
|
||||
}
|
||||
request.response.statusCode = HttpStatus.ok;
|
||||
request.response.headers.contentType = ContentType.json;
|
||||
request.response.write(jsonEncode({'MediaContainer': rootContainer}));
|
||||
await request.response.close();
|
||||
});
|
||||
return server;
|
||||
}
|
||||
|
||||
String _serverBaseUrl(HttpServer server) => 'http://${server.address.host}:${server.port}';
|
||||
Reference in New Issue
Block a user