Second beta for v0.13.0, cut from master. 23 PRs since beta.1.
Read the auth section first. Part of what's fixed in it has been broken in every release Mydia has ever shipped.
The GraphQL API was readable without a login
Someone reported that paired players stop working after 30 days. They do. Pairing mints an access token with a 30-day TTL and nothing ever renewed it, because the player's refresh call was a stub and there was no endpoint behind it anyway. Once it expired, every request arrived unauthenticated. Browsing still rendered, playback died with "Authentication required", and re-pairing by hand was the only way out. The player now swaps its pairing token for a fresh access token and retries once, over HTTP and p2p both. HLS is gated on the same token, so playback comes back with it.
Digging into that turned up the bigger problem. Authorization was opt-in per resolver and 19 resolvers never opted in. 14 of those were browse, so anyone who could reach the endpoint could read your entire catalog. Four were downloads, which also let them start transcode jobs.
Every root field now goes through middleware that denies by default, with login and the two refresh mutations allowlisted. The old per-resolver checks sit underneath it. A test walks every root field and breaks the build if a new one turns up ungated.
If your instance only listens on your LAN there wasn't much exposure here. If you've ever port-forwarded it, assume the catalog was readable.
Skip intro and credits
Mydia finds the intro and the credits in TV episodes now, and the player gives you a button.
Detection runs over a whole season at once, which is the only way the audio approach works at all. Files that already carry chapter markers get read straight off them and nothing else runs. Failing that, every episode in the season gets fingerprinted with Chromaprint and correlated, hunting for the stretch of audio they all have in common. blackdetect then drags the credits boundary onto the actual fade.
It waits until enough files in a season are ready before it'll commit to an answer, so a season you're halfway through downloading gets left alone.
Every season shows its status in the admin UI with a re-analyze button that queues on the spot. In the player a skip button turns up when you hit a segment. Auto-skip is its own toggle in settings and it's off by default.
Release notes in the app
Notes ship inside the image now. There's a /changelog page, and after an upgrade a banner lists the versions you haven't read yet. v0.2.0 through v0.12.0 are backfilled so it isn't empty on first boot.
Betas don't bundle a notes file, so that page stops at v0.12.0 until 0.13.0 goes stable.
Casting
Chromecast never worked on macOS, for the same reason it never worked on iOS: no Bonjour declaration, so the picker came up empty. Both declare it now.
Picking a device connects to it, no need to hit play first, and the cast bar owns up to connecting and not-connected states. Casting resumes where you left off and reports real progress. Subtitles survive a seek that restarts the stream. Seeking past the streamed window restarts the session, where it used to stall. On Apple platforms a denied local network permission says so and hands you a button to the right settings pane. It used to just look like an empty device list.
Desktop windows
The player remembers where its window was and how big, and puts it back, even when the monitor it lived on is gone. It sizes itself to the video's aspect when playback starts, then leaves off once you've resized it yourself.
Downloaded playback
Progress on downloaded media gets recorded locally, so resume works offline and syncs back when the server's reachable again. A record only counts as synced once the server confirms it took it.
Docs
docs.mydia.dev is reorganized around Diátaxis. The deployment guide is five how-tos now, the two PostgreSQL guides are one, and the OIDC, Cardigann and env var material stopped being duplicated across three places. mkdocs builds with --strict in CI, so a dead link fails the build.
Fixes
The Issues tab library picker took the tab down for any item that had metadata, and guest request search crashed the moment it had a result to show. Both were structs read with bracket syntax (#282).
Also: a plugin whose new manifest asks for more than you granted it now says so, the admin status page shows upgrades that got stuck, and quality profile preset ids are pinned unique.
Upgrade notes
Back up first. If you're coming from v0.12.0 and not from beta.1, read beta.1's notes below too, there are migrations down there that delete rows.
- Two additive migrations:
media_segments, plus segment analysis state onmedia_files. - Segment detection starts on its own after you upgrade. It queues up to 20 seasons every five minutes and works them one at a time, so a big TV library gets chewed through slowly in the background. The Docker image ships
chromaprint. Iffpcalcisn't on your install it queues nothing and logs at debug, and it'll pick the backlog up whenever you do install it. - GraphQL denies unauthenticated requests to every root field except login and token refresh. Anything you've pointed at the API without credentials stops working.
- The database actually gets backed up before migrations now. The code was there and tested, but its only caller was a dev mix task, so the unattended upgrade path, the one nearly all of you use, ran migrations with nothing to restore from. SQLite snapshots with
VACUUM INTO. On Postgres it logs thepg_dumpcommand for you, since pg_dump isn't guaranteed to be installed next to the server and a backup you can't trust is worse than none. A failed backup logs an error and boots anyway, because a full disk shouldn't lock you out of your own instance.SKIP_BACKUPSworks now, having been documented for ages and read nowhere.
Docker is ghcr.io/getmydia/mydia:0.13.0-beta.2, or :beta. Add -pg for the Postgres image.
Full Changelog: v0.13.0-beta.1...v0.13.0-beta.2
Also in v0.13.0-beta.1
Back from vacation. 52 PRs have landed since v0.12.0, most of them small fixes, plus three things worth calling out properly. Read the upgrade notes at the bottom before you pull this, there's a data-loss fix in there and two migrations that delete rows.
Automatic quality upgrades
The "Allow automatic quality upgrades" checkbox has been sitting in the admin UI for months doing nothing at all. It works now. A daily sweep looks for library files scoring below their profile's cutoff and goes looking for something better.
The budget is counted in indexer searches rather than items, since searches are what gets you banned from a private tracker. Episodes group into season packs where they can. After import the new file gets re-scored on real ffprobe output, and if it turns out worse than what it replaced, it goes to trash and the release gets blacklisted.
upgrade_until_quality is gone. There's a score cutoff and a minimum margin in its place, so a better codec or audio track can now trigger an upgrade on its own.
External downloads
Plenty of people run a torrent client for things besides Mydia. Every one of those torrents used to get a database row, show up in your Queue, count toward the sidebar badge, and sit in Issues waiting to be fixed. Dismissing them didn't help, the next monitor tick put them straight back.
Unmanaged torrents are now read off the client on each scan and never persisted. Anything that parses as a movie or show goes to Issues → Needs Matching. The rest lands in a new External tab. Match from either one and the download gets created at that point and imports normally.
Player
Chromecast and DLNA both work, on desktop and mobile. The old Chromecast path never could have: iOS was missing its Bonjour declaration, so the picker came back empty every time. If the receiver can reach your server it gets a direct URL and playback survives you quitting the app. Over p2p the player bridges the stream across your LAN.
Two caveats I'd rather say up front than have you find: cast sessions don't survive an app restart, and DLNA subtitles are best-effort because sidecar signalling varies too much between TVs to promise anything.
The playback chrome got rebuilt. The scrubber was 3px at 20% opacity with a thumb that only appeared on hover, four different Material icon families had drifted into one control row, and the timecodes sat 1450px apart in opposite corners. It's one component now. Also new: a neutral palette with a gold accent, hold anywhere to drag the window on desktop, and season episodes in a horizontal rail.
Smaller things
Library search across movies, shows, episodes and collections. It was unreachable on desktop before this, the magnifier only rendered in the mobile app bar.
Scheduled library scanning, per library, off by default. Manual-search grabs come back immediately and survive closing the modal. Bulk auto-search from the selection toolbar. Movie franchises on the detail page, TV trailers, and a progress filter on library pages from @aescolastico.
Quality profiles collapsed down to one model and one struct with the dead config stripped out.
Fixes
Multi-resolution quality profiles were grabbing the lowest resolution you'd checked. Tick 720p and 1080p, get 720p. Fixed, though see note 4 below, because it changes what your instance picks.
Most of the rest was downloads. qBittorrent 5.2+, TorBox uploads (thanks @ppoloskov), two bugs found on a live instance where 47 of 101 downloads never imported, provider failure reasons reaching debrid blacklists, rqbit shared-directory contamination. Removing a download client no longer leaves its downloads pointing at a name that doesn't resolve.
On the player: stale data reaching the UI, cast controls you couldn't get to from most screens, a failed startup step leaving a blank window, cold HLS streams restarting from zero. The web UI got infinite scroll, favicon and date sorting fixes.
Upgrade notes
Back up first.
- SQLite table rebuilds were firing foreign-key deletes on child tables. One of them shipped in v0.10.0 through v0.12.0 and wiped
subtitles,media_hashesandtranscode_jobsfor anyone coming from a pre-v0.10 install. The fix lives in the migration helper, so every rebuild inherits it. If you're on an old install, this is the release to upgrade on. - The quality-profile migration can't be rolled back. It backfills
preferred_resolutions, then dropsqualities,metadata_preferencesandcustomizations.down/0raises on purpose. - Old
unmatcheddownload rows get deleted. Nothing referenced them and none had ever been imported. Anything still sitting in a client reappears in the new tabs on the next scan. - Multi-resolution profiles now pick the highest resolution you've checked, where they used to pick the lowest. It's the bug fix from above, but it will change your grabs.
media.scan_interval_hoursis gone and every library starts out manual-only, so nothing begins scanning on its own after you upgrade. A leftover env var or YAML key gets ignored rather than rejected, so your instance still boots.- Trashed media moves to a trash directory with a retention window. It used to just get marked in place.