fix(player): tell the user when the server cannot read the media file
A 404 on the media stream means the server resolved the item but could not open the file behind it — moved, deleted, or on storage that went away. Jellyfin maps the resulting FileNotFoundException to 404, and PlaybackInfo never stats the file, so negotiation succeeds and only the stream request fails. Playback then died with a snackbar reading "Failed to open [REDACTED_URL]" before popping the route, which tells the user nothing and leaves nothing useful in a bug report. Generalize the HTTP-500 log probe into PlayerError.httpStatusFromLog and latch every status in fatalPlaybackHttpStatuses. Each latches on its own so the 503 that stream-lavf-o deliberately retries cannot mask the fatal status behind it. A 404 now raises a dedicated modal naming the cause and the fix. On Android a 404 previously failed the "Response code: 500" string test and fell through to the ExoPlayer→MPV fallback, showing "switching to compatible player" before failing again on the same request. Read the real status off HttpDataSource.InvalidResponseCodeException instead and skip the fallback: an HTTP status is not a codec problem.
This commit is contained in:
@@ -104,6 +104,28 @@ Future<void> showServerLimitDialog(BuildContext context) async {
|
||||
);
|
||||
}
|
||||
|
||||
/// Shows the server-side 404 modal: the item exists but the server cannot read
|
||||
/// the file behind it, so nothing client-side can recover the playback.
|
||||
Future<void> showMediaUnreadableDialog(BuildContext context) async {
|
||||
await showScopedDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(t.messages.mediaUnreadableTitle),
|
||||
content: Text(t.messages.mediaUnreadableBody),
|
||||
actions: [
|
||||
DialogActionButton(
|
||||
autofocus: true,
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
label: t.common.close,
|
||||
isPrimary: true,
|
||||
style: FilledButton.styleFrom(padding: _buttonPadding, shape: _buttonShape),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Shows a delete confirmation dialog.
|
||||
/// Convenience wrapper around [showConfirmDialog] with destructive styling.
|
||||
Future<bool> showDeleteConfirmation(
|
||||
|
||||
Reference in New Issue
Block a user