My horrible mpv Nix flake
"This is my song And nothing can make it die It's been so long and it's stronger I know why" — Labi Siffre, My Song (YouTube)
Note: Some blog posts advocate for a way of doing something. This is not that. This post is to document what works for me.
An mpv install on aarch64-darwin consists of two things:
- An
mpvbinary. - An
mpv.apppackage that can be installed to/Applications.
I want both of these. The obvious approach is to use the mpv package on
Nixpkgs. However, this requires building swift which on my M2 machine takes a
long time to build, and periodically breaks (most recently fixed 4 days
ago). Alternatively, you can install mpv outside of Nix,
either manually or using Homebrew.
What if you don’t like either of these options?
It’s easy enough to write a flake that pulls the latest release from GitHub and
installs it. This removes the swift build dependency yet keeps everything in
Nix. That looks like this:
# mpv/flake.nix
{
description = "mpv binary flake (to avoid compiling swift)";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
pkgs = import nixpkgs { system = "aarch64-darwin"; };
variant = "macos-15-arm";
version = "v0.41.0";
in
{
packages.aarch64-darwin.default = pkgs.stdenv.mkDerivation {
pname = "mpv";
inherit version;
src = builtins.fetchurl {
url = "https://github.com/mpv-player/mpv/releases/download/v${version}/mpv-v${version}-${variant}.zip";
sha256 = "sha256-SJz2pU9XxU+GrY187a9bsmhIdw1Y3AWQISFOL2ie55k=";
};
dontBuild = true;
nativeBuildInputs = with pkgs ; [
unzip
];
unpackPhase = ''
unzip $src
tar -xzf mpv.tar.gz
'';
installPhase = ''
runHook preInstall
mkdir -p $out/Applications
mv mpv.app $out/Applications
mkdir -p $out/bin
ln -s $out/Applications/mpv.app/Contents/MacOS/mpv $out/bin/mpv
runHook postInstall
'';
};
};
}
Checking for updates
Optionally, you can add a script to check for updates. This is straightforward:
-
Put the version is a file called
mpv-version:v0.41.0 -
Update the flake to read from
mpv-version:let version = pkgs.lib.removeSuffix "\n" (builtins.readFile ./mpv-version); in # ... -
Finally, add the
check-for-updatesscript:#!/usr/bin/env zsh # # mpv/check-for-updates # set -euo pipefail ROOT_DIR=${0:a:h} VERSION_FILE="$ROOT_DIR/mpv-version" # Read local version local_version=$(<"$VERSION_FILE") # Fetch latest version from GitHub and strip leading "v" latest_version=$( curl -fsSL https://api.github.com/repos/mpv-player/mpv/releases/latest \ | jq -r '.tag_name | sub("^v"; "")' ) if [[ "$local_version" == "$latest_version" ]]; then echo "✓ mpv v$local_version is up to date" else echo "✗ ERROR: mpv is outdated" echo "✗ Update available: $local_version → $latest_version" exit 1 fi
Crime 1: Installing the .app
This almost behaves like a regular click-and-drag install of mpv. However, the .app is somewhere in the recesses of the Nix store. Typically:
/nix/store/abc123-mpv/Applications/mpv.app
Once it’s installed, I run a script that cp -Rs it to /Applications.
Crime 2: Adding it to the dock
If you want the app to be docked, you’ll need to add it to the dock yourself
with a utility such as dockutil.
What’s the catch? dockutil itself depends upon swift, so you need to write
a flake for dockutil as well!:
{
description = "dockutil binary flake (to avoid compiling swift)";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
pkgs = import nixpkgs { system = "aarch64-darwin"; };
version = pkgs.lib.removeSuffix "\n" (builtins.readFile ./dockutil-version);
in
{
packages.aarch64-darwin.default = pkgs.stdenv.mkDerivation {
pname = "dockutil";
inherit version;
src = builtins.fetchurl {
url = "https://github.com/kcrawford/dockutil/releases/download/${version}/dockutil-${version}.pkg";
sha256 = "sha256-9g24Jz/oDXxIJFiL7bU4pTh2dcORftsAENq59S0/JYI=";
};
dontBuild = true;
nativeBuildInputs = with pkgs ; [
libarchive
p7zip
];
unpackPhase = ''
7z x $src
bsdtar -xf Payload~
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
install -Dm755 usr/local/bin/dockutil -t $out/bin
runHook postInstall
'';
};
};
}
It’s flakes all the way down…