Files
SubMiner/docs-site/jellyfin-integration.md
T
sudacode b1bdeabca8 fix(jellyfin): show overlay, inject plugin, and fix stats title on playback (#77)
* fix(jellyfin): show overlay, inject plugin, and fix stats title on playb

- Show visible overlay automatically during Jellyfin playback so subtitleStyle applies
- Inject bundled mpv plugin on auto-launch so keybindings work without overlay focus
- Group Jellyfin playback stats under item metadata (jellyfin://host/item/id) instead of stream URLs so episodes merge with matching local titles
- Mark ffsubsync unavailable in subsync modal for remote media paths
- Drain queued second-instance commands even when onReady throws

* fix(overlay): stabilize macOS focus handoff and sidebar Yomitan pause

- Keep overlay visible during macOS foreground probe after overlay blur
- Hold sidebar hover-pause while a Yomitan lookup popup remains open

* fix(jellyfin): fix discovery loop, device identity, tray state, and Disc

- Derive device identity from OS hostname; remove legacy configurable client/device fields
- Prevent discovery playback from reloading active item, misreporting pause state, and duplicate overlay restores
- Restart stale tray discovery sessions without re-login when server drops SubMiner cast target
- Sync tray discovery checkbox state on Linux after CLI/startup/remote-session changes
- Stop Discord presence falling back to stream URLs; prime title before tokenized stream loads
- Fix picker library discovery when log level is above info
- Fix config.example.jsonc trailing commas and array formatting

* docs(release): trim and consolidate prerelease notes for 0.15.0

- Remove breaking changes section and several redundant bullet points
- Consolidate per-platform updater notes into a single entry
- Normalize em-dash separators to hyphens in section headers

* fix(config): remove trailing commas from config.example.jsonc

- Strip trailing commas throughout both config.example.jsonc copies
- Reformat inline arrays to multi-line for JSON strictness
- Update Jellyfin subtitle preload and playback launch tests and impl

* fix(tokenizer): preserve known-word highlight when POS filters suppress

- Known-word cache matches now set isKnown=true even for tokens excluded by POS filters
- POS exclusion gate suppresses N+1, frequency, and JLPT only; known status is computed before the gate
- Jellyfin subtitle preload continues after cleanup failures instead of aborting
- Update config docs and option description to document the known-word bypass behavior

* fix(jellyfin): send explicit hide/show overlay instead of toggle

- Track overlay visibility in plugin state; y-t uses explicit hide/show commands when state is known
- Prevent paused Jellyfin playback from resuming on overlay hide
- Fix subtitle cache cleanup to only remove dirs after successful cleanup

* fix(jellyfin): fix remote progress sync, seek reporting, and startup sto

- arm active playback before loadfile with loadedMediaPath: null to suppress premature stop events
- force immediate progress report on seek-like position jumps at the mpv time-pos level
- send positionTicks and failed=false in reportStopped payload
- remove EventName from HTTP timeline payloads (websocket-only field)
- add startup grace window to drop stop events before media finishes loading

* fix(jellyfin): fix overlay toggle sync, redirect reload, and AppImage bi

- Sync visible-overlay state back to plugin via script messages to avoid toggle/hide drift
- Collapse duplicate toggle events within 250ms to prevent hide-then-show on single keypress
- Preserve manual hide across Jellyfin path-changing redirects even when media-title drops
- Rearm managed subtitle defaults on path-changing redirects
- Route toggleVisibleOverlay session binding through plugin toggle instead of app-side IPC
- Show Linux/Hyprland overlay passively (showInactive) to avoid stealing mpv keyboard focus
- Fix AppImage binary resolution to prefer $APPIMAGE env over mounted inner binary
- Add stats window layer management so delete/update dialogs appear above stats window
- Fix Jellyfin remote progress sync during Linux websocket reconnect windows

* Fix CodeRabbit review feedback

* fix(jellyfin): subtitle timing, resume progress, and overlay sync

- Add per-stream subtitle delay persistence and auto timeline-offset correction
- Strip server-selected subtitle stream from mpv load URL; suppress plugin subtitle rearm and auto-start during app-managed preload
- Fix resume position lost when mpv resets on stop; use last known position for final progress/stopped reports
- Keep Play vs Resume distinct to avoid early seek race on normal play
- Fix discovery resume when remote play sends StartPositionTicks=0 despite saved progress
- Deduplicate show/hide overlay commands using recorded visibility state
- Rewrite docs-site Jellyfin page around cast-to-device UX

* test: update lifecycle cleanup assertion

* fix: clear aborted playback state, fix overlay passthrough, and guard du

- Reset app_managed_playback_pending on lifecycle cleanup to prevent state leak into next item
- Record visible overlay action only after command succeeds, not before
- Non-native passive overlay now always click-through on re-show (fix isNonNativePassiveOverlay ordering)
- Defer activeParsedSubtitleMediaPath assignment until after prefetch completes
- Move autoplay gate release into the hide branch of toggleVisibleOverlay
- Clear active Jellyfin playback when stopping media that never loaded
- Reset managed subtitle delay and delay key when no external tracks are available
- Await async removeDir in subtitle cache cleanup
- Guard duplicate delete clicks in MediaDetailView and SessionsTab with refs
- Escape key in DeleteConfirmDialog now calls stopPropagation and stopImmediatePropagation
2026-05-24 18:40:56 -07:00

7.5 KiB

Jellyfin Integration

Jellyfin is a free, self-hosted media server — think of it as your own private streaming service for video you own. If you keep your anime on a Jellyfin server, SubMiner can play episodes through mpv with the full mining overlay.

::: tip Who needs this? This page is only relevant if you already run (or have access to) a Jellyfin server. If you watch local files or YouTube, you can skip it. The in-app setup window (subminer jellyfin) is the easiest starting point. :::

SubMiner can act as a cast-to-device target for Jellyfin (similar to jellyfin-mpv-shim). Sign in once, turn on discovery, and SubMiner shows up in the "Play on…" / cast menu of any Jellyfin app — web, phone, or TV. Pick an episode, cast it to SubMiner, and it plays in SubMiner's mpv window with the full overlay and Yomitan click-to-lookup.

This is the recommended way to use Jellyfin with SubMiner. A terminal-only option is covered in Launcher playback at the end.

Requirements

  • A Jellyfin server plus your username and password
  • SubMiner installed and running (see Installation)
  • On Linux, the session token is stored with gnome-libsecret by default

Quick start

1. Start SubMiner

Launch SubMiner so it's running in the system tray.

2. Sign in to your server

Open the tray menu and click Configure Jellyfin. In the window that opens, enter your Server URL (for example http://127.0.0.1:8096), Username, and Password, then click Login.

On success, SubMiner:

  • saves an encrypted session token — your password is never stored,
  • turns the Jellyfin integration on, and
  • remembers the server and username for next time.

Reopen this window any time to switch servers or Logout.

3. Turn on discovery

Discovery is what makes SubMiner appear as a cast target. Two ways to enable it:

  • For the current session — open the tray menu and tick Jellyfin Discovery. (This item appears once you've signed in.)
  • Automatically on every launch — already on by default. After your first sign-in, SubMiner auto-connects to Jellyfin at startup, so the cast target is ready without touching the tray. You can change this under Settings.

4. Cast from any Jellyfin app

In the Jellyfin web UI or mobile app, start playing something, open the cast / "Play on" menu, and pick your device — SubMiner appears there named after your computer's hostname. Playback opens in SubMiner.

From then on, pause / resume / seek / stop and audio or subtitle track changes you make in the Jellyfin app are mirrored in SubMiner, and your watch progress syncs back to Jellyfin (now-playing and resume position).

What happens during playback

  • mpv launches automatically. If mpv isn't already running when you cast, SubMiner starts it with SubMiner defaults and the bundled mpv plugin, so keybindings work right away.
  • The overlay is managed by SubMiner, so your configured subtitleStyle controls how subtitles look. Use the overlay-toggle shortcut to hide it for a session.
  • Resume works. If Jellyfin has a saved position for the item, SubMiner seeks there on load.
  • Direct play first. When the source allows it and the container is in your direct-play allowlist, SubMiner streams the original file; otherwise it requests a transcoded stream from Jellyfin.
  • Japanese subtitles are auto-selected, preferring Jellyfin's default and embedded tracks over external sidecar files when several match.
  • Subtitle timing is corrected when possible. SubMiner removes Jellyfin's server-selected subtitle stream from the mpv load URL, suppresses the mpv plugin's one-shot subtitle auto-selection and overlay auto-start for managed Jellyfin loads, stages downloaded subtitle tracks without letting mpv auto-switch between tracks, then selects the Japanese track once after applying any saved or inferred timing delay. When Jellyfin provides both Japanese and English subtitle files, SubMiner compares their cue timelines and applies a global delay if one track is clearly offset. Manual delay shifts you make with SubMiner's adjacent-cue controls are saved per item and subtitle track, then restored the next time you select that track.

Settings

All Jellyfin options live under Settings → Integrations → Jellyfin (open settings from the tray's Open SubMiner Settings). The ones that matter for casting:

Setting Default What it does
Enabled Off Turns the Jellyfin integration on. Switched on for you when you sign in.
Server Url Your Jellyfin server. Filled in when you sign in.
Remote Control Enabled On Lets SubMiner act as a cast target.
Remote Control Auto Connect On Connects to Jellyfin at startup so discovery is automatic. Turn off if you'd rather start it from the tray each time.
Auto Announce Off Re-broadcasts visibility on connect. Enable if your device is slow to appear in the cast menu.

Prefer editing the config file? The same keys live under jellyfin in config.jsonc:

{
  "jellyfin": {
    "enabled": true,
    "serverUrl": "http://127.0.0.1:8096",
    "remoteControlEnabled": true,
    "remoteControlAutoConnect": true,
  },
}

See Configuration for the full list (transcode codec, direct-play containers, default library, and more).

Troubleshooting

SubMiner doesn't appear in the cast menu

  • Make sure SubMiner is running.
  • Make sure you're signed in — reopen Configure Jellyfin and log in again if your token expired.
  • Make sure discovery is on (tray Jellyfin Discovery, or Remote Control Auto Connect in settings).
  • Make sure SubMiner and the Jellyfin client point at the same server.

Casting starts but nothing plays

  • Confirm the item plays normally in another Jellyfin client.
  • If mpv was closed, give it a moment — SubMiner launches it on demand and retries.

SubMiner keeps disconnecting

  • Check server/network stability and whether the session token has expired.

Security notes

  • The Jellyfin session (access token + user ID) is kept in SubMiner's local encrypted token storage. Your password is used only to log in and is never saved.
  • Treat the token storage and your config.jsonc as secrets — don't commit them.
  • Advanced/headless: the SUBMINER_JELLYFIN_ACCESS_TOKEN and SUBMINER_JELLYFIN_USER_ID environment variables can supply a session without the sign-in window.

Launcher playback

If you'd rather stay in the terminal, the subminer launcher can browse and play Jellyfin media directly, without casting from a Jellyfin app:

subminer jellyfin -p      # alias: subminer jf -p

This opens an fzf picker (add -R for rofi) to browse your libraries and episodes, then plays the selected item in SubMiner's mpv with the same overlay, resume, and subtitle behavior described above. Sign in first (step 2) so the launcher can reach your server. See Launcher Script for the rest of the launcher's features.