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