Skip to content

Fix play next episode for MX and MPV external players#5379

Open
RealGreenDragon wants to merge 2 commits intojellyfin:release-0.19.zfrom
RealGreenDragon:fix-external-player
Open

Fix play next episode for MX and MPV external players#5379
RealGreenDragon wants to merge 2 commits intojellyfin:release-0.19.zfrom
RealGreenDragon:fix-external-player

Conversation

@RealGreenDragon
Copy link

Changes

Fixes a regression where the "play next episode" feature failed for external players (specifically MX Player and MPV) because they do not return a standard playback position upon completion.

  • MX Player: Re-implemented specific intent handling from v0.18 (checking the end_by flag).
  • MPV: Added specific handling for MPV's result intent. Since MPV does not return a position extra when playback finishes, the code now correctly interprets this as completion based on the official MPV intent spec.

This restores functionality that was previously covered by the "time elapsed" fallback check, which was removed in v0.19.

Code assistance

Used LLM to verify Kotlin syntax and validate the Intent handling logic for specific players.

Issues

Fixes #5293

@RealGreenDragon
Copy link
Author

RealGreenDragon commented Feb 5, 2026

@nielsvanvelzen I rewrite PR by adding a playbackCompleted flag that is true only if natively the external player communicate the playback completed at runtime end, this for all external player supported (not only MX and MPV).

Following the cases when we are sure from documentation that playback is completed for each external player:

  • MX: if end_by extra is present and equal at playback_completion
  • MPV: if position extra is absent (as you suggested I check only if endPosition is null)
  • VIMU: if resultCode is 1
  • VLC: check is not possible according to documentation (I leaved a comment for clarity)

Finally, as discussed before at the server we send runtime instead of endPosition if playback is completed.


val runtime = (mediaSource.runTimeTicks ?: item.runTimeTicks)?.ticks
val shouldPlayNext = runtime != null && endPosition != null && endPosition >= (runtime * 0.9)
val shouldPlayNext = (playbackCompleted) || (runtime != null && endPosition != null && endPosition >= (runtime * 0.9))

Check warning

Code scanning / detekt

Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers. Warning

This expression contains a magic number. Consider defining it to a well named constant.
@nielsvanvelzen
Copy link
Member

Did you even test these changes? Because the code doesn't even compile right now.

@RealGreenDragon
Copy link
Author

Did you even test these changes? Because the code doesn't even compile right now.

Sorry no, but now I tested the build and with my last commit it finish without errors.

The build error was caused by resultCode not present in result. I fixed editing onItemFinished sign to pass ActivityResult instead of data Intent.
Also I fixed playbackCompleted when else branch to set false and avoid Boolean conversion warnings.
Finally, I merged also your suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants