diff --git a/lib/models/plex_media_version.dart b/lib/models/plex_media_version.dart index 2d9925d0..6a6804fb 100644 --- a/lib/models/plex_media_version.dart +++ b/lib/models/plex_media_version.dart @@ -27,6 +27,16 @@ bool? _flexibleBoolNullable(Object? v) => switch (v) { _ => null, }; +final _videoResolution = RegExp(r'^(\d+)(k?)$', caseSensitive: false); + +/// Plex uses numeric heights for SD/HD and values like `4k`/`8k` for UHD+. +String _videoResolutionDisplayLabel(String resolution) { + final value = resolution.trim(); + final match = _videoResolution.firstMatch(value); + if (match == null) return value; + return match.group(2)!.isEmpty ? '${match.group(1)}p' : '${match.group(1)}K'; +} + @JsonSerializable(createToJson: false) class PlexMediaVersion { @JsonKey(fromJson: _flexibleIntOrZero) @@ -77,7 +87,7 @@ class PlexMediaVersion { // Add resolution if (videoResolution != null && videoResolution!.isNotEmpty) { - parts.add('${videoResolution}p'); + parts.add(_videoResolutionDisplayLabel(videoResolution!)); } else if (height != null) { parts.add('${height}p'); } diff --git a/test/models/plex_media_version_test.dart b/test/models/plex_media_version_test.dart index b15e9cfe..a6fb5b21 100644 --- a/test/models/plex_media_version_test.dart +++ b/test/models/plex_media_version_test.dart @@ -100,4 +100,17 @@ void main() { expect(v.isPlayable, isTrue); }); }); + + group('PlexMediaVersion displayLabel', () { + test('formats Plex videoResolution for display', () { + expect(PlexMediaVersion(id: 1, partKey: '/k', videoResolution: '1080').displayLabel, startsWith('1080p ')); + for (final resolution in ['4k', '4K']) { + expect(PlexMediaVersion(id: 1, partKey: '/k', videoResolution: resolution).displayLabel, startsWith('4K ')); + } + for (final resolution in ['8k', '8K']) { + expect(PlexMediaVersion(id: 1, partKey: '/k', videoResolution: resolution).displayLabel, startsWith('8K ')); + } + expect(PlexMediaVersion(id: 1, partKey: '/k', videoResolution: 'sd').displayLabel, startsWith('sd ')); + }); + }); }