2026-04-26 02:34:09 +02:00
|
|
|
/// Map a video stream height (pixels) onto the canonical resolution label
|
|
|
|
|
/// the rest of the app uses (`'4k'`, `'1080'`, `'720'`, `'480'`, or the raw
|
|
|
|
|
/// height for non-standard sizes). Returns `null` when [height] is null.
|
|
|
|
|
///
|
|
|
|
|
/// Plex hands the label back already in its `Media.videoResolution` field;
|
2026-08-20 02:01:12 +02:00
|
|
|
/// Jellyfin only gives raw pixel dimensions, which the Jellyfin mapper feeds
|
|
|
|
|
/// through [resolutionLabelFromDimensions] to produce the same shape.
|
2026-04-26 02:34:09 +02:00
|
|
|
String? resolutionLabelFromHeight(int? height) {
|
|
|
|
|
if (height == null) return null;
|
|
|
|
|
if (height >= 2160) return '4k';
|
|
|
|
|
if (height >= 1080) return '1080';
|
|
|
|
|
if (height >= 720) return '720';
|
|
|
|
|
if (height >= 480) return '480';
|
|
|
|
|
return height.toString();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-19 20:12:19 +02:00
|
|
|
/// Convenience overload that takes width + height. Width is considered first
|
|
|
|
|
/// for scope-cropped files, e.g. `3840x1608` should still be labeled `4k`.
|
|
|
|
|
String? resolutionLabelFromDimensions(int? width, int? height) {
|
|
|
|
|
if ((width != null && width >= 3840) || (height != null && height >= 2160)) return '4k';
|
|
|
|
|
if ((width != null && width >= 1920) || (height != null && height >= 1080)) return '1080';
|
|
|
|
|
if ((width != null && width >= 1280) || (height != null && height >= 720)) return '720';
|
|
|
|
|
if ((width != null && width >= 854) || (height != null && height >= 480)) return '480';
|
|
|
|
|
return resolutionLabelFromHeight(height);
|
|
|
|
|
}
|
2026-08-20 02:01:12 +02:00
|
|
|
|
|
|
|
|
final _numericResolutionValue = RegExp(r'^(\d+)(?:p)?$');
|
|
|
|
|
|
|
|
|
|
/// Format a canonical resolution label — or a raw numeric height, with or
|
|
|
|
|
/// without a trailing `p` — for display: `'1080'`/`'1080p'` → `'1080p'`,
|
|
|
|
|
/// `'4k'`/`'uhd'`/heights ≥ 2160 → `'4K'`, `'sd'` → `'SD'`; anything else is
|
|
|
|
|
/// uppercased verbatim.
|
|
|
|
|
String resolutionDisplayLabel(String value) {
|
|
|
|
|
final normalized = value.trim().toLowerCase();
|
|
|
|
|
if (normalized == '4k' || normalized == 'uhd') return '4K';
|
|
|
|
|
if (normalized == 'sd') return 'SD';
|
|
|
|
|
|
|
|
|
|
final numeric = _numericResolutionValue.firstMatch(normalized);
|
|
|
|
|
if (numeric != null) {
|
|
|
|
|
final height = int.tryParse(numeric.group(1)!);
|
|
|
|
|
if (height != null && height >= 2160) return '4K';
|
|
|
|
|
return '${numeric.group(1)}p';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value.trim().toUpperCase();
|
|
|
|
|
}
|