Open-source project
streamyfin/streamyfin avatar
streamyfin/streamyfin

Streamyfin setup: an Expo Jellyfin client that plays through MPV

A modern Jellyfin client built with Expo

5,362 stars310 forksTypeScriptMPL-2.0

At a glance

What is it?
Streamyfin is a TypeScript Expo client for Jellyfin with MPV playback, server side FFmpeg downloads and a plugin that carries shared settings. It is deep on phone and tablet, and thin on desktop, Roku and Chromecast subtitles.
Who is it for?
Adopt Streamyfin if your library is watched on phones and tablets and you want an Expo client with MPV playback, trickplay seeking and server backed downloads. Skip it if you need a desktop, browser or Roku build, or if subtitle carrying Chromecast casting is a requirement today.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • streamyfin/streamyfin5,362 ★ · +155
Star history
Repository2026-09-232026-11-14
streamyfin/streamyfin5.2k5.4k

155 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

MPV and MPVKit sit under playback on every platform

Streamyfin is an Expo application written in TypeScript, and the player underneath it is MPV, powered on all platforms by MPVKit, with the native MPV module in Streamyfin built by @Alexk2309. One engine across phone and tablet means a codec or a subtitle track behaves the same way on both, instead of diverging per platform. Two playback features sit on top of it: skipping intros and credits during playback, and trickplay images as the chapter preview when you scrub through a timeline. The sessions view lists every stream currently active on your server, which matters when several household devices are open at once. Custom auth headers extend the reach of the same client to servers behind an access gateway, with a page at docs/custom-headers.md naming Cloudflare Zero Trust and Pangolin as the cases it covers. All of it depends on a server new enough to avoid the compatibility problems the project attributes to older Jellyfin versions.

Downloads are a live FFmpeg transcode your server performs

Nothing is copied off your server when you save something for offline viewing. Streamyfin pulls the HLS stream, converts it into a video file on the device through FFmpeg, and the conversion itself is handled in real time by Jellyfin on the server while the download runs. That design buys compatibility: any file your server can transcode can end up on the phone, whatever the original container was. It costs time, and it costs CPU on the server. The README is direct that the process takes longer. The method itself is one of the settings you can pin from the plugin instead of setting it per device, and downloads sit under the experimental block next to Chromecast. Expect a save to take noticeably longer than a plain file copy of the same title would.

Settings live in a Jellyfin plugin, not in the app

The settings layer is not inside the client. streamyfin/jellyfin-plugin-streamyfin installs into Jellyfin itself and holds the configuration the app reads, which lets one account set defaults for every user on that server: automatic Seerr login with no user input required, preferred default languages, the download method and the search provider, and a personalised home screen. Seerr, formerly Jellyseerr, for requesting media and Jellysearch, a full text search proxy for Jellyfin, both hang off that same configuration. The practical difference is where the work happens. With the plugin in place you configure once per server. Without it the app still connects and still plays, but the shared defaults and the hands free Seerr login are gone, and each device carries its own copy of the configuration. The cost of that convenience is one more component inside the server that has to be kept in step with the client.

Four ways in, and a beta channel behind a subscription

The four download routes are not equivalent. The iOS build sits in the App Store under listing id6593660679, the Android build under the package id com.fredrikburmester.streamyfin, and the same code is reachable through the latest GitHub release and through Obtainium for anyone who wants builds pulled straight from the repository. The release route is how you get a version the stores have not carried, and it hands the install and the update cadence back to you on each device. Beta access is narrower again. It requires the Member tier or higher on Patreon, and what the subscription delivers is entry to the beta releases channel on Discord where APKs and IPAs are posted. There is no automatic TestFlight entry: you send a direct message to Cagemaster with the email address you use for Apple, then wait to be added by hand. People actively contributing source code receive beta access without any of that.

bun i, then expo run:ios, and nothing from npm

Source builds have two fixed requirements: node above 20, and bun as the package manager. The project uses bun exclusively, and npm, yarn and npx are not supported. Installing dependencies and regenerating the native projects come first:

bash
bun i
bun run prebuild

Then you create a development build for the platform you are targeting. Both of these open a simulator on your machine, so Xcode or Android Studio has to be installed:

bash
bun run ios
bun run android

The TV variants are the same commands with a `:tv` suffix, which is what flips the EXPO_TV variable between 0 and 1:

bash
bun run prebuild:tv
bun run ios:tv
bun run android:tv

Prebuild pipes a confirmation into `expo prebuild --clean`, so it regenerates the native projects rather than patching them. On iOS, a build that fails with `missing Metal Toolchain` from KSPlayer shaders is fixed by running the bundled script once, through `bun run ios:install-metal-toolchain`, which shells out to scripts/ios/install-metal-toolchain.sh. Before opening a pull request, the project asks you to read CONTRIBUTING.md and run `bun run test`, which chains typecheck, jest unit tests, biome lint and format, the i18n key check and expo-doctor. Login flows are covered end to end with Maestro, installed by the setup target and then driven against an Android device:

bash
make e2e-setup
maestro start-device --platform android
maestro test login.yaml

Biome also ships as an editor extension, and the repository keeps its own config in biome.json at the top level next to babel.config.js, metro.config.js and the app.config.ts that drives Expo.

Casting reaches the television, subtitles do not follow

Casting appears twice in the README, and the two entries do not agree on how finished it is. The feature list offers Chromecast support to any Chromecast enabled device. The experimental section, which holds downloads and casting together, says video casting is already available while subtitle support and further features are still being worked on. The gap that matters is the second half of that sentence. A title can be thrown to the television and subtitle selection does not travel with it, so anyone who depends on subtitles has to watch on the device instead. Read that paragraph as a snapshot rather than a purchase criterion. The television side of the project also runs through build targets instead of store listings: TV discovery has its own note at docs/tv-discovery.md.

No desktop build, no Roku app, and a quiet spot on server URLs

The download list sets the boundaries. App Store, Play Store, GitHub releases, Obtainium: every entry is a phone, a tablet or a raw release file. No Windows, macOS, Linux, browser or Roku build is named in the download list. A second silence sits around the server address. What you get is the homepage streamyfin.app and the network prerequisites: your device must be on the same network as the Jellyfin server for local connections, the server needs remote access enabled to be reached from outside your network, the server version should be current because older versions cause compatibility issues, and you need a valid user account with access to the libraries you want. If the server sits behind an access gateway, docs/custom-headers.md is the documented route. Third, the client does not paper over an empty server. Its own troubleshooting answer for missing libraries points at a current server version and at least one library that is not audio only.

Editorial conclusion

Adopt Streamyfin if your library is watched on phones and tablets and you want an Expo client with MPV playback, trickplay seeking and server backed downloads. Skip it if you need a desktop, browser or Roku build, or if subtitle carrying Chromecast casting is a requirement today. Before signing in, check that your Jellyfin server version is current, that at least one non audio library is enabled, and whether the streamyfin plugin is installed, since it carries the shared defaults and the Seerr login.

Frequently asked questions

What are the differences between Streamyfin and Jellyfin?

Jellyfin is the server that holds your libraries, sessions and transcoding. Streamyfin is one client for that server, written in Expo and TypeScript, and it plays video through MPV via MPVKit on all platforms. Downloads and settings depend on a plugin installed into Jellyfin itself.

How to set up Streamyfin?

Install it from the App Store, the Play Store, the latest GitHub release or Obtainium, then sign in with a Jellyfin account that can see your libraries. Your device has to be on the same network as the server for local connections, and the server needs remote access enabled to be reachable from outside that network.

What is the URL for the Streamyfin server?

Streamyfin connects to the address of your own Jellyfin server, not to a service of its own, and the project homepage is streamyfin.app.

What does Streamyfin do?

It skips intros and credits during playback, shows trickplay images while you seek, lists the sessions currently streaming on your server, casts video to a Chromecast enabled device, saves media for offline viewing, reaches servers behind an access gateway through custom auth headers, and can request media through Seerr.

Is Streamyfin on Apple TV or Android TV?

The repository builds TV variants through commands suffixed with `:tv`, and it links a TV discovery note at docs/tv-discovery.md. The download links point at the phone apps and the GitHub releases page, and no Roku build is named. Chromecast video casting works today, subtitle casting is still being worked on.

Is Streamyfin open source?

Yes. The client is published on GitHub under the MPL-2.0 licence, forks and pull requests are the contribution route, and translations are handled on Crowdin. Beta builds require a Patreon subscription or active contribution to the source code.

Official sources

  1. License: MPL-2.0
  2. Project website
  3. README
  4. Releases
  5. streamyfin/streamyfin on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/streamyfin-streamyfin.svg)](https://hysenlabs.com/projects/streamyfin-streamyfin)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/streamyfin-streamyfin.svg)](https://hysenlabs.com/projects/streamyfin-streamyfin)

Was this useful?