1{ stdenv, fetchFromGitHub, writeScript, glibcLocales, diffPlugins
2, pythonPackages, imagemagick, gobjectIntrospection, gst_all_1
3
4# Attributes needed for tests of the external plugins
5, callPackage, beets
6
7, enableAcousticbrainz ? true
8, enableAcoustid ? true
9, enableBadfiles ? true, flac ? null, mp3val ? null
10, enableConvert ? true, ffmpeg ? null
11, enableDiscogs ? true
12, enableEmbyupdate ? true
13, enableFetchart ? true
14, enableGmusic ? true
15, enableKeyfinder ? true, keyfinder-cli ? null
16, enableKodiupdate ? true
17, enableLastfm ? true
18, enableMpd ? true
19, enableReplaygain ? true, bs1770gain ? null
20, enableSonosUpdate ? true
21, enableThumbnails ? true
22, enableWeb ? true
23
24# External plugins
25, enableAlternatives ? false
26, enableCopyArtifacts ? false
27
28, bashInteractive, bash-completion
29}:
30
31assert enableAcoustid -> pythonPackages.pyacoustid != null;
32assert enableBadfiles -> flac != null && mp3val != null;
33assert enableConvert -> ffmpeg != null;
34assert enableDiscogs -> pythonPackages.discogs_client != null;
35assert enableFetchart -> pythonPackages.responses != null;
36assert enableGmusic -> pythonPackages.gmusicapi != null;
37assert enableKeyfinder -> keyfinder-cli != null;
38assert enableLastfm -> pythonPackages.pylast != null;
39assert enableMpd -> pythonPackages.mpd2 != null;
40assert enableReplaygain -> bs1770gain != null;
41assert enableSonosUpdate -> pythonPackages.soco != null;
42assert enableThumbnails -> pythonPackages.pyxdg != null;
43assert enableWeb -> pythonPackages.flask != null;
44
45with stdenv.lib;
46
47let
48 optionalPlugins = {
49 acousticbrainz = enableAcousticbrainz;
50 badfiles = enableBadfiles;
51 chroma = enableAcoustid;
52 convert = enableConvert;
53 discogs = enableDiscogs;
54 embyupdate = enableEmbyupdate;
55 fetchart = enableFetchart;
56 gmusic = enableGmusic;
57 keyfinder = enableKeyfinder;
58 kodiupdate = enableKodiupdate;
59 lastgenre = enableLastfm;
60 lastimport = enableLastfm;
61 mpdstats = enableMpd;
62 mpdupdate = enableMpd;
63 replaygain = enableReplaygain;
64 sonosupdate = enableSonosUpdate;
65 thumbnails = enableThumbnails;
66 web = enableWeb;
67 };
68
69 pluginsWithoutDeps = [
70 "absubmit" "beatport" "bench" "bpd" "bpm" "bucket" "cue" "duplicates"
71 "edit" "embedart" "export" "filefilter" "freedesktop" "fromfilename"
72 "ftintitle" "fuzzy" "hook" "ihate" "importadded" "importfeeds" "info"
73 "inline" "ipfs" "lyrics" "mbcollection" "mbsubmit" "mbsync" "metasync"
74 "missing" "permissions" "play" "plexupdate" "random" "rewrite" "scrub"
75 "smartplaylist" "spotify" "the" "types" "zero"
76 ];
77
78 enabledOptionalPlugins = attrNames (filterAttrs (_: id) optionalPlugins);
79
80 allPlugins = pluginsWithoutDeps ++ attrNames optionalPlugins;
81 allEnabledPlugins = pluginsWithoutDeps ++ enabledOptionalPlugins;
82
83 testShell = "${bashInteractive}/bin/bash --norc";
84 completion = "${bash-completion}/share/bash-completion/bash_completion";
85
86 # This is a stripped down beets for testing of the external plugins.
87 externalTestArgs.beets = (beets.override {
88 enableAlternatives = false;
89 enableCopyArtifacts = false;
90 }).overrideAttrs (stdenv.lib.const {
91 doInstallCheck = false;
92 });
93
94 pluginArgs = externalTestArgs // { inherit pythonPackages; };
95
96 plugins = {
97 alternatives = callPackage ./alternatives-plugin.nix pluginArgs;
98 copyartifacts = callPackage ./copyartifacts-plugin.nix pluginArgs;
99 };
100
101in pythonPackages.buildPythonApplication rec {
102 pname = "beets";
103 version = "1.4.7";
104
105 src = fetchFromGitHub {
106 owner = "beetbox";
107 repo = "beets";
108 rev = "v${version}";
109 sha256 = "17gfz0g7pqm6wha8zf63zpw07zgi787w1bjwdcxdh1l3z4m7jc9l";
110 };
111
112 propagatedBuildInputs = [
113 pythonPackages.six
114 pythonPackages.enum34
115 pythonPackages.jellyfish
116 pythonPackages.munkres
117 pythonPackages.musicbrainzngs
118 pythonPackages.mutagen
119 pythonPackages.pyyaml
120 pythonPackages.unidecode
121 pythonPackages.gst-python
122 pythonPackages.pygobject3
123 gobjectIntrospection
124 ] ++ optional enableAcoustid pythonPackages.pyacoustid
125 ++ optional (enableFetchart
126 || enableEmbyupdate
127 || enableKodiupdate
128 || enableAcousticbrainz)
129 pythonPackages.requests
130 ++ optional enableConvert ffmpeg
131 ++ optional enableDiscogs pythonPackages.discogs_client
132 ++ optional enableGmusic pythonPackages.gmusicapi
133 ++ optional enableKeyfinder keyfinder-cli
134 ++ optional enableLastfm pythonPackages.pylast
135 ++ optional enableMpd pythonPackages.mpd2
136 ++ optional enableSonosUpdate pythonPackages.soco
137 ++ optional enableThumbnails pythonPackages.pyxdg
138 ++ optional enableWeb pythonPackages.flask
139 ++ optional enableAlternatives plugins.alternatives
140 ++ optional enableCopyArtifacts plugins.copyartifacts;
141
142 buildInputs = with pythonPackages; [
143 beautifulsoup4
144 imagemagick
145 mock
146 nose
147 rarfile
148 responses
149 ] ++ (with gst_all_1; [
150 gst-plugins-base
151 gst-plugins-good
152 gst-plugins-ugly
153 ]);
154
155 patches = [
156 ./replaygain-default-bs1770gain.patch
157 ./keyfinder-default-bin.patch
158 ];
159
160 postPatch = ''
161 sed -i -e '/assertIn.*item.*path/d' test/test_info.py
162 echo echo completion tests passed > test/rsrc/test_completion.sh
163
164 sed -i -e '/^BASH_COMPLETION_PATHS *=/,/^])$/ {
165 /^])$/i u"${completion}"
166 }' beets/ui/commands.py
167 '' + optionalString enableBadfiles ''
168 sed -i -e '/self\.run_command(\[/ {
169 s,"flac","${flac.bin}/bin/flac",
170 s,"mp3val","${mp3val}/bin/mp3val",
171 }' beetsplug/badfiles.py
172 '' + optionalString enableConvert ''
173 sed -i -e 's,\(util\.command_output(\)\([^)]\+\)),\1[b"${ffmpeg.bin}/bin/ffmpeg" if args[0] == b"ffmpeg" else args[0]] + \2[1:]),' beetsplug/convert.py
174 '' + optionalString enableReplaygain ''
175 sed -i -re '
176 s!^( *cmd *= *b?['\'''"])(bs1770gain['\'''"])!\1${bs1770gain}/bin/\2!
177 ' beetsplug/replaygain.py
178 sed -i -e 's/if has_program.*bs1770gain.*:/if True:/' \
179 test/test_replaygain.py
180 '';
181
182 postInstall = ''
183 mkdir -p $out/share/zsh/site-functions
184 cp extra/_beet $out/share/zsh/site-functions/
185 '';
186
187 doCheck = true;
188
189 preCheck = ''
190 find beetsplug -mindepth 1 \
191 \! -path 'beetsplug/__init__.py' -a \
192 \( -name '*.py' -o -path 'beetsplug/*/__init__.py' \) -print \
193 | sed -n -re 's|^beetsplug/([^/.]+).*|\1|p' \
194 | sort -u > plugins_available
195
196 ${diffPlugins allPlugins "plugins_available"}
197 '';
198
199 checkPhase = ''
200 runHook preCheck
201
202 LANG=en_US.UTF-8 \
203 LOCALE_ARCHIVE=${assert stdenv.isLinux; glibcLocales}/lib/locale/locale-archive \
204 BEETS_TEST_SHELL="${testShell}" \
205 BASH_COMPLETION_SCRIPT="${completion}" \
206 HOME="$(mktemp -d)" \
207 # Exclude failing test https://github.com/beetbox/beets/issues/2652
208 nosetests -v --exclude=test_single_month_nonmatch_ --exclude=test_asciify_variable --exclude=test_asciify_character_expanding_to_slash
209
210 runHook postCheck
211 '';
212
213 doInstallCheck = true;
214
215 installCheckPhase = ''
216 runHook preInstallCheck
217
218 tmphome="$(mktemp -d)"
219
220 EDITOR="${writeScript "beetconfig.sh" ''
221 #!${stdenv.shell}
222 cat > "$1" <<CFG
223 plugins: ${concatStringsSep " " allEnabledPlugins}
224 CFG
225 ''}" HOME="$tmphome" "$out/bin/beet" config -e
226 EDITOR=true HOME="$tmphome" "$out/bin/beet" config -e
227
228 runHook postInstallCheck
229 '';
230
231 makeWrapperArgs = [ "--set GI_TYPELIB_PATH \"$GI_TYPELIB_PATH\"" "--set GST_PLUGIN_SYSTEM_PATH_1_0 \"$GST_PLUGIN_SYSTEM_PATH_1_0\"" ];
232
233 meta = {
234 description = "Music tagger and library organizer";
235 homepage = http://beets.io;
236 license = licenses.mit;
237 maintainers = with maintainers; [ aszlig domenkozar pjones ];
238 platforms = platforms.linux;
239 };
240}