1{
2 lib,
3 fetchFromGitHub,
4 tag ? "",
5
6 # build time
7 gettext,
8 gobject-introspection,
9 wrapGAppsHook3,
10 writableTmpDirAsHomeHook,
11
12 # runtime
13 adwaita-icon-theme,
14 gdk-pixbuf,
15 glib,
16 glib-networking,
17 gtk3,
18 gtksourceview,
19 kakasi,
20 keybinder3,
21 libappindicator-gtk3,
22 libmodplug,
23 librsvg,
24 libsoup_3,
25
26 # optional features
27 withDbusPython ? false,
28 withMusicBrainzNgs ? false,
29 withPahoMqtt ? false,
30 withPypresence ? false,
31 withSoco ? false,
32
33 # backends
34 withGstPlugins ? withGstreamerBackend,
35 withGstreamerBackend ? true,
36 gst_all_1,
37 withXineBackend ? true,
38 xine-lib,
39
40 # tests
41 dbus,
42 glibcLocales,
43 hicolor-icon-theme,
44 python3,
45 xvfb-run,
46}:
47python3.pkgs.buildPythonApplication rec {
48 pname = "quodlibet${tag}";
49 version = "4.7.1";
50 pyproject = true;
51
52 outputs = [
53 "out"
54 "doc"
55 ];
56
57 src = fetchFromGitHub {
58 owner = "quodlibet";
59 repo = "quodlibet";
60 tag = "release-${version}";
61 hash = "sha256-xr3c1e4tjw2YHuKbvNeUPBIFdHEcpztqXjHVDSSxYlo=";
62 };
63
64 # Fix "E ModuleNotFoundError: No module named 'distutils'" in Python 3.12 or newer
65 patches = [ ./fix-gdist-python-3.12-and-newer.patch ];
66
67 build-system = [ python3.pkgs.setuptools ];
68
69 postPatch = ''
70 # Fix "FileExistsError: File already exists: /nix/store/<...>-quodlibet-4.7.1/bin/quodlibet"
71 substituteInPlace pyproject.toml \
72 --replace-fail 'quodlibet = "quodlibet.main:main"' ""
73 '';
74
75 nativeBuildInputs = [
76 gettext
77 gobject-introspection
78 wrapGAppsHook3
79 ]
80 ++ (with python3.pkgs; [
81 sphinx-rtd-theme
82 sphinxHook
83 ]);
84
85 buildInputs = [
86 adwaita-icon-theme
87 gdk-pixbuf
88 glib
89 glib-networking
90 gtk3
91 gtksourceview
92 kakasi
93 keybinder3
94 libappindicator-gtk3
95 libmodplug
96 libsoup_3
97 ]
98 ++ lib.optionals (withXineBackend) [ xine-lib ]
99 ++ lib.optionals (withGstreamerBackend) (
100 with gst_all_1;
101 [
102 gst-plugins-base
103 gstreamer
104 ]
105 ++ lib.optionals (withGstPlugins) [
106 gst-libav
107 gst-plugins-bad
108 gst-plugins-good
109 gst-plugins-ugly
110 ]
111 );
112
113 dependencies =
114 with python3.pkgs;
115 [
116 feedparser
117 gst-python
118 mutagen
119 pycairo
120 pygobject3
121 ]
122 ++ lib.optionals withDbusPython [ dbus-python ]
123 ++ lib.optionals withMusicBrainzNgs [ musicbrainzngs ]
124 ++ lib.optionals withPahoMqtt [ paho-mqtt ]
125 ++ lib.optionals withPypresence [ pypresence ]
126 ++ lib.optionals withSoco [ soco ]
127 ++ lib.optionals (pythonAtLeast "3.13") [ standard-telnetlib ];
128
129 nativeCheckInputs = [
130 dbus
131 gdk-pixbuf
132 glibcLocales
133 hicolor-icon-theme
134 xvfb-run
135 writableTmpDirAsHomeHook
136 ]
137 ++ (with python3.pkgs; [
138 polib
139 pytest
140 pytest-xdist
141 ]);
142
143 pytestFlags = [
144 # missing translation strings in potfiles
145 "--deselect=tests/test_po.py::TPOTFILESIN::test_missing"
146 # require networking
147 "--deselect=tests/plugin/test_covers.py::test_live_cover_download"
148 "--deselect=tests/test_browsers_iradio.py::TInternetRadio::test_click_add_station"
149 # upstream does actually not enforce source code linting
150 "--ignore=tests/quality"
151 ]
152 ++ lib.optionals (withXineBackend || !withGstPlugins) [
153 "--ignore=tests/plugin/test_replaygain.py"
154 ];
155
156 env.LC_ALL = "en_US.UTF-8";
157
158 preCheck = ''
159 export GDK_PIXBUF_MODULE_FILE=${librsvg}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
160 export XDG_DATA_DIRS="$out/share:${gtk3}/share/gsettings-schemas/${gtk3.name}:$XDG_ICON_DIRS:$XDG_DATA_DIRS"
161 '';
162
163 checkPhase = ''
164 runHook preCheck
165
166 xvfb-run -s '-screen 0 1920x1080x24' \
167 dbus-run-session --config-file=${dbus}/share/dbus-1/session.conf \
168 pytest $pytestFlags
169
170 runHook postCheck
171 '';
172
173 preFixup = lib.optionalString (kakasi != null) ''
174 gappsWrapperArgs+=(--prefix PATH : ${lib.getBin kakasi})
175 '';
176
177 meta = {
178 description = "GTK-based audio player written in Python, using the Mutagen tagging library";
179 longDescription = ''
180 Quod Libet is a GTK-based audio player written in Python, using
181 the Mutagen tagging library. It's designed around the idea that
182 you know how to organize your music better than we do. It lets
183 you make playlists based on regular expressions (don't worry,
184 regular searches work too). It lets you display and edit any
185 tags you want in the file. And it lets you do this for all the
186 file formats it supports. Quod Libet easily scales to libraries
187 of thousands (or even tens of thousands) of songs. It also
188 supports most of the features you expect from a modern media
189 player, like Unicode support, tag editing, Replay Gain, podcasts
190 & internet radio, and all major audio formats.
191 '';
192 homepage = "https://quodlibet.readthedocs.io/en/latest";
193 license = lib.licenses.gpl2Plus;
194 maintainers = with lib.maintainers; [
195 coroa
196 pbogdan
197 ];
198 };
199}