Open-source project
FNOSP/FlyNarwhal avatar
FNOSP/FlyNarwhal

FlyNarwhal puts libmpv playback on the desktop for FNOS media

基于 Flutter 框架开发的适用于飞牛影视的跨平台客户端

517 stars39 forksDartAGPL-3.0

At a glance

What is it?
FlyNarwhal is an unofficial Flutter desktop client for the FNOS media service, rebuilt on libmpv for HDR playback across Windows, macOS and Linux. It is worth adopting only if you already run that service, and if you can accept an unsigned macOS build and an AGPL-3.0 licence.
Who is it for?
FlyNarwhal fits home users who already run FNOS media and want a desktop player on a second machine with hardware decoding and HDR kept intact. It does not fit anyone looking for a general media client, and the macOS build still needs a manual quarantine removal on first launch.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly Dart, according to GitHub's language statistics.

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

Editorial analysis

FlyNarwhal targets one media service, not a general player

FlyNarwhal is a third-party desktop client for FNOS media, and the project says so plainly in its own disclaimer: it is built by enthusiasts, is unrelated to the official FNOS product, and users should respect the relevant service terms. That narrowness defines the project. It is not a universal client for Plex, Emby or Jellyfin, and the README never claims such support.

The intended user is already running the FNOS media service on a home server and wants a native feeling player on a separate desktop computer. The 2.x line covers Windows x64, macOS x64 and arm64, and Linux x64 and arm64. The project notes list the produced package formats as .exe, .dmg, .deb, .rpm, .pkg.tar.zst and .AppImage, so a distribution exists for each of those combinations rather than a single universal binary.

The architecture is split in two. The repository holds the Flutter front end, while the matching server component lives in a separate repository named fly-narwhal-server. Nothing in the desktop tree substitutes for that backend, so a reader evaluating this client should also evaluate the health of the server project before committing to it.

The 2.x rewrite dropped the JVM and rebuilt the player path

Version 1.x was written with Kotlin Multiplatform and Compose Desktop. Version 2.x was rebuilt on Flutter, which removes the JVM runtime from the shipped package and changes how the window is scheduled and rendered. The project attributes to this rewrite a smaller install package, a shorter start-up chain, faster player initialisation and quicker first frame.

The playback core moved as well. The 2.x line uses media_kit with a full libmpv build as the engine, so hardware decoding and local decoding are both available. Windows full screen was reworked to use a pseudo full screen mode, which fixes a 1.x complaint that other applications could not be shown over the player window while it was in system full screen.

Credentials are stored differently too. Saved login passwords are no longer written to disk in plain text. The implementation uses AES-256-GCM authenticated encryption with an HKDF derived key, a random salt and nonce, an authentication tag and ciphertext integrity checking, and it zeroes sensitive memory after encryption. When the derived key is wrong or the ciphertext has been tampered with, the stored password is cleared automatically instead of being trusted.

Shipping full libmpv is what preserves HDR on macOS and Linux

The difference that matters for playback quality is the packaging of libmpv. On macOS and Linux the release bundles the complete library, which is what allows PGS and SUP subtitles, including HDMV PGS decoding, to be handled locally without a detour through a server.

Dynamic range is the other half. The project states that 2.x can play HDR, HLG and Dolby Vision content while keeping the original dynamic range. It contrasts this with 1.x, where the Compose Desktop rendering path forced a CPU readback of the decoded surface through RGBA and the picture had to be tone mapped to SDR on the server side. The claimed result of the rewrite is lower CPU usage and no loss of dynamic range.

Advanced playback options are also present, including forced H.264 and forced SDR tone mapping, so a user with a display that cannot handle the source range has a manual override. Feature additions beyond the rewrite include a folder view, playback of videos stored on network drives, Live TV, a media information panel and a detailed playback information panel.

The Windows bundle ships one helper, not the whole updater

The Windows packaging story is narrower than the feature list suggests. The project states that windows/CMakeLists.txt by default builds and packages only the native FlyNarwhalInstallHelper.exe, and that updater.exe and the previous helper are not part of the release bundle. In other words, the full desktop updater from the upstream desktop_updater project is not what ships here.

The README is careful about the scope of that borrowing. The transaction, provenance, journal and policy behaviour of the Windows install helper follows desktop_updater 3.1.4, with licensing and scope recorded in third_party/desktop_updater.NOTICE. The project states plainly that it did not copy the upstream check for updates, download logic, user interface, Linux implementation or macOS implementation, and that it does not claim the upstream signature.

For a reviewer, that is the part worth checking. The helper carries a provenance and policy vocabulary, but the enforcement surface is limited to what this project actually implemented. Treat the NOTICE file as the reference for what was taken, not the upstream project description as a description of this client.

The macOS build still needs a manual quarantine removal

The macOS install path is where most first launch friction lives. Because the package is not notarised by Apple, the downloaded app carries a quarantine attribute, and macOS may refuse to open it with a message about an unverifiable developer or a damaged application.

Most release builds are ad hoc signed for FlyNarwhal.app, so the common symptom is the unverifiable developer warning. When the damaged message appears, the project documents a manual fix. Move FlyNarwhal.app into Applications first, then run the following in a terminal:

bash
xattr -dr com.apple.quarantine /Applications/FlyNarwhal.app

After that the app starts normally. Four details are worth knowing before you type it. The command must run after the app is in the Applications folder. Every fresh download from the browser brings a new quarantine mark, so a reinstall means running it again, while versions installed through the in-app updater normally do not carry the mark. The change applies only to the machine you run it on.

Running from source means enabling all three desktop targets first

Building FlyNarwhal yourself needs the Flutter Stable SDK and a working flutter command. Desktop support for each platform has to be switched on explicitly:

bash
  flutter config --enable-windows-desktop
  flutter config --enable-macos-desktop
  flutter config --enable-linux-desktop

Windows also requires Visual Studio 2022 with the Desktop development with C++ workload, macOS needs Xcode and the Command Line Tools, and Linux needs the usual Flutter desktop dependencies such as clang, cmake, ninja-build, pkg-config and libgtk-3-dev. With those in place, the source workflow is short:

bash
git clone https://github.com/FNOSP/FlyNarwhal.git
cd FlyNarwhal
flutter pub get

Launch the desktop app on the platform you prepared:

powershell
flutter run -d windows

The project uses Riverpod and json_serializable, so a change to an annotated model or a provider requires regeneration:

bash
dart run build_runner build --delete-conflicting-outputs

Release builds follow the same split, with flutter build windows --release, flutter build macos --release and flutter build linux --release producing output under build/windows, build/macos and build/linux.

Contributors are expected to target dev-2.x and know their own patch

The contribution rules are unusually strict about scope and about who signs the work. The repository has two branches: dev-2.x is the development branch and receives day to day feature work and fixes, while master is the release branch and only receives merges from dev-2.x after a release succeeds. Pull requests should target dev-2.x.

The project asks for one improvement per pull request, a clear title, and a description that explains the problem being solved and any linked issue. Large or complex changes can be rejected outright, and introducing a new dependency, changing core runtime logic or altering the architecture should be raised as an issue before code is written.

Generated code is part of the contract. Riverpod and json_serializable output has to be regenerated before submitting, and static analysis is expected to be clean:

bash
  flutter analyze

There is also an explicit policy on machine written patches: code produced with AI tooling is not accepted without human review, and the project asks that the contributor understand and adjust what the tool produced rather than paste it unchanged. Commits follow Conventional Commits, with types such as feat, fix, docs, refactor and chore and scopes such as player, login, ui, linux or windows. The project describes itself as a spare time effort and asks for patience during review.

AGPL-3.0, an unofficial disclaimer, and a recent push

Two facts frame how you can use the code. The repository is licensed under AGPL-3.0, which carries source disclosure obligations for network use and for derivative distributions, so anyone embedding or modifying the client should read the licence rather than assume permissive terms. And the project is explicitly unaffiliated with the official FNOS media product, which means it carries no vendor support and no compatibility promise for future server changes.

On upkeep, the last push was on 2026-10-13 and the repository is not archived. The three most recent tagged releases are v2.3.7 on 2026-09-27, v2.3.6 on 2026-09-25 and v2.3.5 on 2026-09-23. The documentation does not describe a fixed release schedule, so treat that list as history rather than as a promise about the next tag.

Upgrade cost for end users is mostly operational: a new artifact has to be downloaded per platform, and on macOS that means repeating the quarantine removal after every browser download. For contributors, upgrade cost sits in the generated code path, since provider and model changes trigger a build_runner pass before analysis.

Editorial conclusion

FlyNarwhal fits home users who already run FNOS media and want a desktop player on a second machine with hardware decoding and HDR kept intact. It does not fit anyone looking for a general media client, and the macOS build still needs a manual quarantine removal on first launch. Before adopting, confirm that a release artifact exists for your exact platform and CPU combination, check that the server side you connect to is the fly-narwhal-server project, and read the AGPL-3.0 terms for your distribution scenario.

Frequently asked questions

Does FlyNarwhal work with any media server or only FNOS media?

It is built specifically for the FNOS media service and is described as an unofficial third-party client. The server side lives in a separate project called fly-narwhal-server, so the desktop repository alone is not a complete deployment.

How do I open FlyNarwhal on macOS when macOS says the app is damaged?

Move FlyNarwhal.app into the Applications folder and remove the quarantine attribute with xattr -dr com.apple.quarantine /Applications/FlyNarwhal.app. You need to repeat it after each fresh browser download, but versions installed through the in-app updater normally do not carry the mark.

Does FlyNarwhal still need a Java runtime?

No. The 2.x series was rewritten on Flutter and no longer depends on the JVM runtime, which is what makes the package lighter and the start-up path shorter than in the earlier Compose Desktop version.

Which platforms and CPU architectures does FlyNarwhal cover?

Version 2.x covers Windows x64, macOS x64 and arm64, and Linux x64 and arm64, with .exe, .dmg, .deb, .rpm, .pkg.tar.zst and .AppImage package formats. The earlier 1.x line covered only Windows and macOS.

How do I build FlyNarwhal from source on Linux?

Install the Flutter Stable SDK, enable the Linux desktop target with flutter config --enable-linux-desktop, have clang, cmake, ninja-build, pkg-config and libgtk-3-dev available, then clone the repository, run flutter pub get and finally flutter run -d linux.

Where should I send a bug fix for FlyNarwhal?

Open a pull request against the dev-2.x branch, since master is the release branch and only receives merges after a release succeeds. Commits should follow Conventional Commits, and flutter analyze plus a build_runner regeneration are expected before submitting.

Official sources

  1. FNOSP/FlyNarwhal on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. README
  5. Releases
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/fnosp-flynarwhal.svg)](https://hysenlabs.com/projects/fnosp-flynarwhal)

Was this useful?