Files
plezy/lib/models/transcode_quality_preset.dart
T
edde746 9ac8002b53 feat(player): apply separate default quality on cellular connections
On mobile data the single default streaming quality either burns
through the user's data plan or permanently caps quality at home.
Playback start now applies a dedicated cellular default when the
device is on a cellular-only connection, read from the app's existing
single connectivity subscription. The new setting defaults to
following the general default, ships in Settings > Playback for
phones/tablets only, and explicit per-play quality picks still win.

'Metered connection' had been spelled out independently in the offline
provider, the download WiFi-only gate and the sync-rule cooldown.
Rather than add a fourth copy, all four now share
ConnectivityLinkType. Network *presence* is deliberately left alone:
its callers disagree on whether an empty snapshot counts as
connected, so folding that in would change behavior.

showSelectionDialog now returns the picked DialogOption instead of its
raw value so the tile's null-valued 'Same as Default Quality' option
stays distinguishable from dismissing the dialog.

close #2147
2026-08-27 14:14:01 +02:00

73 lines
2.7 KiB
Dart

/// Video transcode quality presets modeled on Plex Web's custom-quality table.
///
/// When a non-[original] preset is selected, playback asks the active backend
/// for a capped transcode stream. [original] bypasses transcoding entirely and
/// uses the direct-play URL.
enum TranscodeQualityPreset {
original(null, null, null),
p240_320(320, '420x240', 30),
p320_720(720, '576x320', 40),
p480_1_5mbps(1500, '720x480', 60),
p720_2mbps(2000, '1280x720', 60),
p720_3mbps(3000, '1280x720', 75),
p720_4mbps(4000, '1280x720', 100),
p1080_8mbps(8000, '1920x1080', 60),
p1080_10mbps(10000, '1920x1080', 75),
p1080_12mbps(12000, '1920x1080', 90),
p1080_20mbps(20000, '1920x1080', 100);
const TranscodeQualityPreset(this.videoBitrateKbps, this.videoResolution, this.videoQuality);
final int? videoBitrateKbps;
final String? videoResolution;
final int? videoQuality;
bool get isOriginal => this == TranscodeQualityPreset.original;
/// Resolution height (e.g. 720, 1080) parsed from [videoResolution]. Null for original.
int? get resolutionHeight {
final r = videoResolution;
if (r == null) return null;
final parts = r.split('x');
if (parts.length != 2) return null;
return int.tryParse(parts[1]);
}
/// Order shared by every picker surface so they can't drift apart:
/// [original] pinned first, then transcode presets highest-bitrate first.
static final List<TranscodeQualityPreset> displayOrder = List.unmodifiable([
original,
...values.where((p) => !p.isOriginal).toList().reversed,
]);
/// The saved default playback starts at, for callers without an explicit
/// per-play pick (those apply their own preset directly).
///
/// Backends that cannot transcode start at [original] regardless of any
/// saved default. Otherwise the cellular default applies on a cellular-only
/// connection when set, else the general default.
static TranscodeQualityPreset resolveStartupDefault({
required bool serverSupportsTranscoding,
required bool onCellularOnly,
required TranscodeQualityPreset? cellularDefault,
required TranscodeQualityPreset generalDefault,
}) {
if (!serverSupportsTranscoding) return original;
if (onCellularOnly && cellularDefault != null) return cellularDefault;
return generalDefault;
}
}
/// Outcome of a transcode decision call.
enum TranscodeDecisionOutcome {
/// Decision indicates transcode is available (`transcodeDecisionCode == 1001`).
transcodeOk,
/// Decision indicates only direct play is available (`transcodeDecisionCode == 1000`).
/// Caller should fall back to the direct-play URL.
directPlayOnly,
/// Decision failed (HTTP error, code >= 2000, or parse error).
failed,
}