a Jellyfin & Subsonic client for the terminal — powered by mpv, Chromecast and UPnP MediaRenderer
mpv chromecast mpris navidrome jellyfin upnp tui
0

Configure Feed

Select the types of activity you want to include in your feed.

fin / flake.nix
6.4 kB 193 lines
1{ 2 description = "fin - a neon-electric Jellyfin TUI client for mpv & Chromecast"; 3 4 inputs = { 5 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 7 # Current crane doesn't expose a `nixpkgs` input, so we don't follow it. 8 crane.url = "github:ipetkov/crane"; 9 10 fenix = { 11 url = "github:nix-community/fenix"; 12 inputs.nixpkgs.follows = "nixpkgs"; 13 inputs.rust-analyzer-src.follows = ""; 14 }; 15 16 flake-utils.url = "github:numtide/flake-utils"; 17 18 advisory-db = { 19 url = "github:rustsec/advisory-db"; 20 flake = false; 21 }; 22 }; 23 24 outputs = { self, nixpkgs, crane, fenix, flake-utils, advisory-db, ... }: 25 flake-utils.lib.eachDefaultSystem (system: 26 let 27 pkgs = import nixpkgs { 28 inherit system; 29 }; 30 31 inherit (pkgs) lib; 32 33 craneLib = crane.mkLib pkgs; 34 35 src = craneLib.cleanCargoSource ./.; 36 37 # fin uses rustls end-to-end, so no openssl. 38 # mpv is a *runtime* requirement (we spawn it for local playback and 39 # the CLI does a preflight `mpv --version` at startup). We fold it 40 # into PATH via a makeWrapper post-fixup below. 41 commonArgs = { 42 inherit src; 43 44 pname = "fin"; 45 version = "0.6.0"; 46 strictDeps = true; 47 48 # rockbox-playback pulls in rockbox-codecs + rockbox-dsp, whose 49 # build scripts compile Rockbox's C codec/DSP sources with the `cc` 50 # crate — so a C compiler must be on PATH. `stdenv.cc` is the 51 # toolchain for this platform (clang on Darwin, gcc on Linux). 52 # TLS is pure-Rust (rustls), so still no openssl. 53 # Modern nixpkgs (post-25.05) auto-links the Darwin SDK, so no 54 # framework references here — `darwin.apple_sdk_11_0` was removed 55 # as a legacy compatibility stub. 56 nativeBuildInputs = [ 57 pkgs.pkg-config 58 pkgs.stdenv.cc 59 ] ++ lib.optionals pkgs.stdenv.isDarwin [ 60 # coreaudio-sys generates its CoreAudio bindings with bindgen at 61 # build time; bindgenHook provides libclang (LIBCLANG_PATH) and 62 # points clang at the Nix Apple SDK headers. 63 pkgs.rustPlatform.bindgenHook 64 ]; 65 66 buildInputs = lib.optionals pkgs.stdenv.isDarwin [ 67 pkgs.libiconv 68 ] ++ lib.optionals pkgs.stdenv.isLinux [ 69 # cpal links against ALSA on Linux for the local audio output path. 70 # MPRIS needs no dbus dev lib: zbus is a pure-Rust D-Bus 71 # implementation that speaks to the session bus socket directly. 72 pkgs.alsa-lib 73 ]; 74 75 # Workspace has one bin target — build just that. 76 cargoExtraArgs = "--locked --bin fin"; 77 }; 78 79 craneLibLLvmTools = craneLib.overrideToolchain 80 (fenix.packages.${system}.complete.withComponents [ 81 "cargo" 82 "llvm-tools" 83 "rustc" 84 ]); 85 86 # Cache the dependency graph separately from the crate source. 87 cargoArtifacts = craneLib.buildDepsOnly commonArgs; 88 89 finUnwrapped = craneLib.buildPackage (commonArgs // { 90 inherit cargoArtifacts; 91 doCheck = false; 92 }); 93 94 # Wrap the binary so `mpv` is always discoverable at runtime, even 95 # when installed via `nix profile install`. 96 fin = pkgs.symlinkJoin { 97 name = "fin-${finUnwrapped.version}"; 98 paths = [ finUnwrapped ]; 99 nativeBuildInputs = [ pkgs.makeWrapper ]; 100 postBuild = '' 101 wrapProgram $out/bin/fin \ 102 --prefix PATH : ${lib.makeBinPath [ pkgs.mpv ]} 103 ''; 104 meta = { 105 description = "A neon-electric Jellyfin TUI client for mpv & Chromecast"; 106 homepage = "https://github.com/tsirysndr/fin"; 107 license = lib.licenses.mpl20; 108 mainProgram = "fin"; 109 platforms = lib.platforms.unix; 110 }; 111 }; 112 113 in 114 { 115 checks = { 116 inherit fin; 117 118 fin-clippy = craneLib.cargoClippy (commonArgs // { 119 inherit cargoArtifacts; 120 cargoClippyExtraArgs = "--all-targets -- --deny warnings"; 121 }); 122 123 fin-doc = craneLib.cargoDoc (commonArgs // { 124 inherit cargoArtifacts; 125 }); 126 127 fin-fmt = craneLib.cargoFmt { 128 inherit src; 129 }; 130 131 fin-audit = craneLib.cargoAudit { 132 inherit src advisory-db; 133 }; 134 135 fin-nextest = craneLib.cargoNextest (commonArgs // { 136 inherit cargoArtifacts; 137 partitions = 1; 138 partitionType = "count"; 139 }); 140 } // lib.optionalAttrs (system == "x86_64-linux") { 141 fin-coverage = craneLib.cargoTarpaulin (commonArgs // { 142 inherit cargoArtifacts; 143 }); 144 }; 145 146 packages = { 147 default = fin; 148 fin = fin; 149 fin-unwrapped = finUnwrapped; 150 151 fin-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (commonArgs // { 152 inherit cargoArtifacts; 153 }); 154 }; 155 156 apps.default = flake-utils.lib.mkApp { 157 drv = fin; 158 name = "fin"; 159 }; 160 161 devShells.default = pkgs.mkShell { 162 inputsFrom = builtins.attrValues self.checks.${system}; 163 164 # Build-time tools. pkg-config is required so cpal's build.rs can 165 # resolve libasound on Linux; stdenv.cc supplies the C compiler the 166 # rockbox-codecs / rockbox-dsp build scripts need to compile 167 # Rockbox's C sources. 168 nativeBuildInputs = with pkgs; [ 169 cargo 170 rustc 171 rustfmt 172 clippy 173 rust-analyzer 174 mpv 175 pkg-config 176 stdenv.cc 177 ]; 178 179 # Link-time libraries. Position matters: pkg-config only picks up 180 # `.pc` files from `buildInputs`, so alsa-lib MUST live here (not 181 # in nativeBuildInputs) for the cpal → ALSA link to resolve. 182 buildInputs = with pkgs; lib.optionals stdenv.isDarwin [ 183 libiconv 184 ] ++ lib.optionals stdenv.isLinux [ 185 alsa-lib 186 ]; 187 188 shellHook = '' 189 echo " fin dev shell mpv $(mpv --version | head -n1 | cut -d' ' -f2) ready" 190 ''; 191 }; 192 }); 193}