Skip to content

bug: Direct play serves the previous episode, and AniList progress is not updated #925

Description

@Vincius-dev

Checklist

Bug Severity

Usability is affected

Bug Area

Media streaming (transcode / direct)

Description

Two separate problems when watching a local library from a browser on /mediastream with direct play.

1. Going to the next episode plays the previous one

The video that plays is the previous episode, while the page (title, episode list, playback info modal) correctly shows the new one.

Cause: newMediaContainer gives every file the same stream URL:

// internal/mediastream/playback.go
case StreamTypeDirect:
    streamUrl = "/api/v1/mediastream/direct"

ServeEchoDirectPlay then serves whatever is in currentMediaContainer. So the URL identifies a slot, not a file, and HandleMediastreamDirectPlay sets no cache headers (unlike /subs and /att, which set no-store). c.File only sends Last-Modified, so Chrome applies heuristic freshness and reuses the cached response of the previous episode for the new one.

Captured while switching episodes (Chrome devtools, Network):

Last request of the episode being finished:

Content-Range: bytes 543162368-543173080/543173081
Last-Modified: Sun, 16 Aug 2026 18:29:49 GMT

First request of the next episode, 45s later, same Request URL:

Range:         bytes=0-425983
If-Range:      Sun, 16 Aug 2026 18:29:49 GMT   <- validator of the previous file
Content-Range: bytes 0-543173080/638433783
Last-Modified: Sun, 16 Aug 2026 18:30:01 GMT   <- the new file

The browser is revalidating with the previous episode's validator because to it this is the same resource. The response also ends up inconsistent: the total (638433783) is the new file while the range ends at 543173080, which is exactly the last byte of the previous one.

Ticking "Disable cache" in devtools makes the problem disappear, which confirms it.

There is also a smaller race on the client: selecting an episode updates filePath (and remounts the player via key={filePath}) before the new media container is requested, so the <video> mounts with the previous episode's URL for one render and starts fetching it.

Steps to reproduce

  1. Have a browser client with direct play (codec supported), local library.
  2. Play an episode, let it finish or click next.
  3. The next episode's metadata is shown but the previous episode's video plays.

2. AniList progress is not updated

With "Automatically update progress" enabled, the entry is not updated after watching. Two things drop the update in mediacore:

  • listenToBackendEvents rejects any event whose PlaybackID differs from the session's. That includes a PlaybackLoadedEvent, which is precisely what announces a new playback. If a client starts the next episode without a TerminatedEvent landing first, the session stays pinned to the old playback and every event of the new one is dropped for the rest of the session.
  • The CompletedEvent handler in SetupSharedEffects calls GetActivePlaybackState() when the effect runs, not when the event was ingested. A TerminatedEvent (auto next episode, or leaving right after the 80% mark) clears activePlaybackState first, and the update is skipped with no log.

Both are reproducible against the coordinator with a fake platform.

Related, directstream.updateCompletedProgress looks like a fallback for this but is dead code: it does stream.(*BaseStream) while the concrete streams (*LocalFileStream, *TorrentStream, ...) only embed BaseStream, so the assertion never matches.

Additional context

I have a fix ready for both and can open a PR if the approach sounds right: put the file hash (already on MediaContainer) in the direct play URL, check it in ServeEchoDirectPlay, send no-store, and capture the playback state when the CompletedEvent is ingested instead of reading it later.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions