Files
spotifast/flake.nix
T
Carmine Paolino 7cc0384d70 Play MilkDrop in a window of its own
MilkDrop, Winamp's visualiser through libprojectM, opens as its own
borderless, fullscreenable window, the way Winamp ran it. It runs in a
child process: winit allows one event loop per process and eframe owns the
app's, and a second eframe viewport corrupts the mini player's see-through
surface on Wayland, so MilkDrop is this same binary re-launched with
`--milkdrop-child`, with its own window, OpenGL context, and event loop. It
touches nothing the app draws, so the mini player's transparency is safe and
shaped skins keep their shape. A child process runs its event loop on its
own main thread, so this works the same on Linux, macOS, and Windows.

The sound reaches the child through a shared-memory ring the audio tap fills
(src/milkdrop/shm.rs); the app sends it settings and a close on its stdin as
JSON and hears back where it sits and when it closes on its stdout
(src/milkdrop/host.rs, src/milkdrop/child.rs). The child exits on its own if
the app's pipe closes, so it never orphans. Drag to move, double-click or F
for full screen, Esc to come back or close, the corner to resize, the arrows
or N/P for the next and previous preset, L to keep one. The frame rate is a
setting (30, 60, or uncapped).

A vis button in the big window's top bar, the V menu on the mini player,
Ctrl+Shift+K, or Settings opens it. Presets live in the `milkdrop` folder of
the config directory; nothing ships in the binary, and Settings downloads
the two packs projectM curates.

libprojectM is a C++ library built from source through projectm-sys, so
building now wants CMake, a C++ compiler, and libclang;
`--no-default-features` leaves MilkDrop out and needs none of them. The
aarch64 Windows release build goes without it, since projectm-sys only
builds libprojectM for x64 there.
2026-08-31 10:31:49 +02:00

161 lines
4.8 KiB
Nix

{
description = "Spotify, native and fast";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# rust-toolchain.toml pins the compiler so local builds and CI agree.
# This reads that file rather than restating the version here.
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
self,
nixpkgs,
rust-overlay,
...
}:
let
systems = [
"aarch64-darwin"
"x86_64-darwin"
"aarch64-linux"
"x86_64-linux"
];
forAllSystems =
f:
nixpkgs.lib.genAttrs systems (
system:
f (
import nixpkgs {
inherit system;
overlays = [ (import rust-overlay) ];
}
)
);
in
{
devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
packages =
with pkgs;
[
(rust-bin.fromRustupToolchainFile ./rust-toolchain.toml)
rust-analyzer
pkg-config
# libprojectM (MilkDrop) is built from source by CMake, and its
# bindings by bindgen, which needs libclang.
cmake
rustPlatform.bindgenHook
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
apple-sdk
]
++ lib.optionals stdenv.hostPlatform.isLinux [
alsa-lib
libpulseaudio
libxkbcommon
wayland
libGL
libx11
libxcursor
libxi
libxrandr
];
# The GUI dlopens its Wayland, X11 and GL libraries at run time.
LD_LIBRARY_PATH = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux (
pkgs.lib.makeLibraryPath (
with pkgs;
[
libxkbcommon
wayland
libGL
libx11
libxcursor
libxi
libxrandr
]
)
);
};
});
packages = forAllSystems (pkgs: rec {
default = fastpotify;
fastpotify =
let
toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
rustPlatform = pkgs.makeRustPlatform {
cargo = toolchain;
rustc = toolchain;
};
runtimeLibs = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (
with pkgs;
[
libxkbcommon
wayland
libGL
libx11
libxcursor
libxi
libxrandr
]
);
in
rustPlatform.buildRustPackage {
pname = "fastpotify";
version = (pkgs.lib.importTOML ./Cargo.toml).package.version;
src = self;
cargoLock.lockFile = ./Cargo.lock;
nativeBuildInputs =
with pkgs;
[
pkg-config
# libprojectM (MilkDrop) is built from source by CMake, and
# its bindings by bindgen, which needs libclang.
cmake
rustPlatform.bindgenHook
]
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ makeWrapper ];
buildInputs =
pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (
with pkgs;
[
alsa-lib
libpulseaudio
# libprojectM links OpenGL directly.
libGL
]
)
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin [ pkgs.apple-sdk ];
# The GUI dlopens its Wayland, X11 and GL libraries at run time.
postFixup = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
wrapProgram $out/bin/fastpotify \
--prefix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath runtimeLibs}
'';
postInstall = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
install -Dm644 packaging/applications/fastpotify.desktop \
$out/share/applications/fastpotify.desktop
install -Dm644 packaging/icons/fastpotify.svg \
$out/share/icons/hicolor/scalable/apps/fastpotify.svg
'';
meta = {
description = "Fast native Spotify client with local playback and Spotify Connect";
homepage = "https://fastpotify.rocks";
license = pkgs.lib.licenses.mit;
mainProgram = "fastpotify";
};
};
});
formatter = forAllSystems (pkgs: pkgs.nixfmt-tree);
};
}