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
5.7 kB 183 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.3.1"; 46 strictDeps = true; 47 48 # No native TLS or system libs needed — pure Rust deps. 49 # Modern nixpkgs (post-25.05) auto-links the Darwin SDK, so no 50 # framework references here — `darwin.apple_sdk_11_0` was removed 51 # as a legacy compatibility stub. 52 nativeBuildInputs = [ 53 pkgs.pkg-config 54 ] ++ lib.optionals pkgs.stdenv.isDarwin [ 55 # coreaudio-sys generates its CoreAudio bindings with bindgen at 56 # build time; bindgenHook provides libclang (LIBCLANG_PATH) and 57 # points clang at the Nix Apple SDK headers. 58 pkgs.rustPlatform.bindgenHook 59 ]; 60 61 buildInputs = lib.optionals pkgs.stdenv.isDarwin [ 62 pkgs.libiconv 63 ] ++ lib.optionals pkgs.stdenv.isLinux [ 64 # cpal links against ALSA on Linux for the local audio output path. 65 pkgs.alsa-lib 66 ]; 67 68 # Workspace has one bin target — build just that. 69 cargoExtraArgs = "--locked --bin fin"; 70 }; 71 72 craneLibLLvmTools = craneLib.overrideToolchain 73 (fenix.packages.${system}.complete.withComponents [ 74 "cargo" 75 "llvm-tools" 76 "rustc" 77 ]); 78 79 # Cache the dependency graph separately from the crate source. 80 cargoArtifacts = craneLib.buildDepsOnly commonArgs; 81 82 finUnwrapped = craneLib.buildPackage (commonArgs // { 83 inherit cargoArtifacts; 84 doCheck = false; 85 }); 86 87 # Wrap the binary so `mpv` is always discoverable at runtime, even 88 # when installed via `nix profile install`. 89 fin = pkgs.symlinkJoin { 90 name = "fin-${finUnwrapped.version}"; 91 paths = [ finUnwrapped ]; 92 nativeBuildInputs = [ pkgs.makeWrapper ]; 93 postBuild = '' 94 wrapProgram $out/bin/fin \ 95 --prefix PATH : ${lib.makeBinPath [ pkgs.mpv ]} 96 ''; 97 meta = { 98 description = "A neon-electric Jellyfin TUI client for mpv & Chromecast"; 99 homepage = "https://github.com/tsirysndr/fin"; 100 license = lib.licenses.mpl20; 101 mainProgram = "fin"; 102 platforms = lib.platforms.unix; 103 }; 104 }; 105 106 in 107 { 108 checks = { 109 inherit fin; 110 111 fin-clippy = craneLib.cargoClippy (commonArgs // { 112 inherit cargoArtifacts; 113 cargoClippyExtraArgs = "--all-targets -- --deny warnings"; 114 }); 115 116 fin-doc = craneLib.cargoDoc (commonArgs // { 117 inherit cargoArtifacts; 118 }); 119 120 fin-fmt = craneLib.cargoFmt { 121 inherit src; 122 }; 123 124 fin-audit = craneLib.cargoAudit { 125 inherit src advisory-db; 126 }; 127 128 fin-nextest = craneLib.cargoNextest (commonArgs // { 129 inherit cargoArtifacts; 130 partitions = 1; 131 partitionType = "count"; 132 }); 133 } // lib.optionalAttrs (system == "x86_64-linux") { 134 fin-coverage = craneLib.cargoTarpaulin (commonArgs // { 135 inherit cargoArtifacts; 136 }); 137 }; 138 139 packages = { 140 default = fin; 141 fin = fin; 142 fin-unwrapped = finUnwrapped; 143 144 fin-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (commonArgs // { 145 inherit cargoArtifacts; 146 }); 147 }; 148 149 apps.default = flake-utils.lib.mkApp { 150 drv = fin; 151 name = "fin"; 152 }; 153 154 devShells.default = pkgs.mkShell { 155 inputsFrom = builtins.attrValues self.checks.${system}; 156 157 # Build-time tools. pkg-config is required so cpal's build.rs can 158 # resolve libasound on Linux. 159 nativeBuildInputs = with pkgs; [ 160 cargo 161 rustc 162 rustfmt 163 clippy 164 rust-analyzer 165 mpv 166 pkg-config 167 ]; 168 169 # Link-time libraries. Position matters: pkg-config only picks up 170 # `.pc` files from `buildInputs`, so alsa-lib MUST live here (not 171 # in nativeBuildInputs) for the cpal → ALSA link to resolve. 172 buildInputs = with pkgs; lib.optionals stdenv.isDarwin [ 173 libiconv 174 ] ++ lib.optionals stdenv.isLinux [ 175 alsa-lib 176 ]; 177 178 shellHook = '' 179 echo " fin dev shell mpv $(mpv --version | head -n1 | cut -d' ' -f2) ready" 180 ''; 181 }; 182 }); 183}