Files
SubMiner/docs-site/jellyfin-integration.md
T
sudacode f19d93e3ab 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
2026-05-24 03:00:44 -07:00

8.0 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 log in, browse it, and 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. Most of this integration is driven from the command line, so it is aimed at slightly more advanced users; the in-app setup window (subminer jellyfin) is the easiest starting point. :::

SubMiner includes an optional Jellyfin CLI integration for:

  • authenticating against a server
  • listing libraries and media items
  • launching item playback in the connected mpv instance
  • receiving Jellyfin remote cast-to-device playback events in-app
  • opening an in-app setup window for server URL and authentication
  • toggling Jellyfin cast discovery from the tray once configured

Requirements

  • Jellyfin server URL and user credentials
  • For --jellyfin-play: connected mpv IPC socket (--start or existing mpv plugin workflow)
  • On Linux, token encryption defaults to gnome-libsecret; pass --password-store=<backend> to override.

Setup

  1. Set base config values (config.jsonc):
{
  "jellyfin": {
    "enabled": true,
    "serverUrl": "http://127.0.0.1:8096",
    "recentServers": ["http://127.0.0.1:8096"],
    "username": "your-user",
    "remoteControlEnabled": true,
    "remoteControlAutoConnect": true,
    "autoAnnounce": false,
    "defaultLibraryId": "",
    "pullPictures": false,
    "iconCacheDir": "/tmp/subminer-jellyfin-icons",
    "directPlayPreferred": true,
    "directPlayContainers": ["mkv", "mp4", "webm", "mov", "flac", "mp3", "aac"],
    "transcodeVideoCodec": "h264",
  },
}
  1. Authenticate:
subminer jellyfin
subminer jellyfin -l \
  --server http://127.0.0.1:8096 \
  --username your-user \
  --password 'your-password'

subminer jellyfin opens the setup window. It pre-fills the server URL from the configured server, a recent successful server, or the local default. Successful login keeps the window open, stores the Jellyfin session token in encrypted storage, updates the configured server/username, and refreshes recent servers. Passwords are never stored.

  1. List libraries:
SubMiner.AppImage --jellyfin-libraries

Launcher wrapper equivalent for interactive playback flow:

subminer jellyfin -p

Launcher wrapper for Jellyfin cast discovery mode (background app + tray):

subminer jellyfin -d

After Jellyfin is enabled with a server URL and SubMiner is already running, the tray menu shows Jellyfin Discovery. Use that checkbox to start or stop discovery for the current runtime session without changing config. By default, Jellyfin sees the cast target as the OS hostname (uname -n on Linux). If the stored login session is missing or expired, starting discovery shows a warning and setup remains the path to refresh credentials. It does not survive app restart.

Stop discovery session/app:

subminer app --stop

subminer jf ... is an alias for subminer jellyfin ....

To clear saved session credentials:

subminer jellyfin --logout
  1. List items in a library:
SubMiner.AppImage --jellyfin-items --jellyfin-library-id LIBRARY_ID --jellyfin-search term

Optional listing controls:

  • --jellyfin-recursive=true|false (default: true)
  • --jellyfin-include-item-types=Series,Season,Folder,CollectionFolder,Movie,...

These are used by the launcher picker flow to:

  • keep root search focused on shows/folders/movies (exclude episode rows)
  • browse selected anime/show directories as folder-or-file lists
  • recurse for playable files only after selecting a folder
  1. Start playback:
SubMiner.AppImage --start
SubMiner.AppImage --jellyfin-play --jellyfin-item-id ITEM_ID

Optional stream overrides:

  • --jellyfin-audio-stream-index N
  • --jellyfin-subtitle-stream-index N

Playback Behavior

  • Direct play is attempted first when:
    • jellyfin.directPlayPreferred=true
    • media source supports direct stream
    • source container matches jellyfin.directPlayContainers
  • If direct play is not selected/available, SubMiner requests a Jellyfin transcoded stream (master.m3u8) using jellyfin.transcodeVideoCodec.
  • Resume position (PlaybackPositionTicks) is applied via mpv seek.
  • Media title is set in mpv as [Jellyfin/<mode>] <title>.
  • When SubMiner auto-launches mpv for Jellyfin playback, it injects the bundled mpv plugin unless an installed SubMiner mpv plugin is already present. This keeps mpv-side keybindings available without clicking the overlay first.
  • Jellyfin playback shows the SubMiner visible overlay before selecting subtitle tracks, so subtitleStyle controls the rendered subtitle appearance. Use the overlay toggle shortcut if you want to hide it for a session.

Cast To Device Mode (jellyfin-mpv-shim style)

When SubMiner is running with a valid Jellyfin session, it can appear as a remote playback target in Jellyfin's cast-to-device menu.

Requirements

  • jellyfin.enabled=true
  • valid jellyfin.serverUrl and Jellyfin auth session (env override or stored login session)
  • jellyfin.remoteControlEnabled=true (default)
  • jellyfin.remoteControlAutoConnect=true (default) for startup auto-connect
  • jellyfin.autoAnnounce=false by default (true enables auto announce/visibility check logs on connect)

Behavior

  • SubMiner connects to Jellyfin remote websocket and posts playback capabilities.
  • Startup auto-connect still requires remoteControlAutoConnect=true; the tray Jellyfin Discovery checkbox can start discovery later even when startup auto-connect is disabled.
  • Play events open media in mpv with the same defaults used by --jellyfin-play.
  • If mpv IPC is not connected at cast time, SubMiner auto-launches mpv in idle mode with SubMiner defaults and retries playback.
  • Playstate events map to mpv pause/resume/seek/stop controls.
  • Stream selection commands (SetAudioStreamIndex, SetSubtitleStreamIndex) are mapped to mpv track selection.
  • SubMiner reports start/progress/stop timeline updates back to Jellyfin so now-playing and resume state stay synchronized.
  • --jellyfin-remote-announce forces an immediate capability re-broadcast and logs whether server sessions can see the device.

Troubleshooting

  • Device not visible in Jellyfin cast menu:
    • ensure SubMiner is running
    • ensure session token is valid (--jellyfin-login again if needed)
    • ensure remoteControlEnabled is true
    • use tray Jellyfin Discovery or subminer jellyfin -d to start discovery
  • Cast command received but playback does not start:
    • verify mpv IPC can connect (--start flow)
    • verify item is playable from normal --jellyfin-play --jellyfin-item-id ...
  • Frequent reconnects:
    • check Jellyfin server/network stability and token expiration

Failure Handling

User-visible errors are shown through CLI logs and mpv OSD for:

  • invalid credentials
  • expired/invalid token
  • server/network errors
  • missing library/item identifiers
  • no playable source
  • mpv not connected for playback

Security Notes and Limitations

  • Jellyfin auth session (accessToken + userId) is stored in local encrypted token storage after login/setup.
  • Launcher wrappers support --password-store=<backend> and forward it through to the app process.
  • Optional environment overrides are supported: SUBMINER_JELLYFIN_ACCESS_TOKEN and SUBMINER_JELLYFIN_USER_ID.
  • Treat both token storage and config files as secrets and avoid committing them.
  • Password is used only for login and is not stored.
  • Optional setup UI is available via --jellyfin; all actions are also available via CLI flags.
  • subminer wrapper uses Jellyfin subcommands (subminer jellyfin ..., alias subminer jf ...). Use SubMiner.AppImage for direct --jellyfin-libraries and --jellyfin-items.
  • For direct app CLI usage (SubMiner.AppImage ...), --jellyfin-server can override server URL for login/play flows without editing config.