about summary refs log tree commit diff
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2014-12-30 23:21:57 +0100
committeraszlig <aszlig@redmoonstudios.org>2014-12-30 23:21:57 +0100
commit880c985f27c51e9ff32fb61c320b1f6b494b28c0 (patch)
treec80f5d641f3b14187cfdfbb9eac565c76ffe8b75
parentc087c456afeb7dea9a86f69d1767b8d7f8616492 (diff)
parent05f6061d1dea845eb069eebf9dc235fc872d5f89 (diff)
downloadnixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.tar
nixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.tar.gz
nixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.tar.bz2
nixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.tar.lz
nixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.tar.xz
nixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.tar.zst
nixlib-880c985f27c51e9ff32fb61c320b1f6b494b28c0.zip
Merge branch 'better-beets'.
Makes beets actually usable (and configurable) on Nix(OS), if you want
to use more plugins rather than just plain lookup of tracks based on
(fuzzy) string matching.

This also changes the derivation name from "python2.7-beets" to just
"beets".

* Commit summary:
  beets: Check dependencies on activated plugins.
  beets: Check plugin definitions against package.
  beets: Use audiotools backend for replaygain.
  beets: Allow to configure plugin dependencies.
  beets: Switch to using fetchFromGitHub.
  python: Add new package audiotools.
  python: Add new package discogs_client.
  python: Add pyacoustid and dependencies.
  python/mutagen: Update to upstream version 1.27.
  mp3gain: Fix output path bin directory.
  beets: Add myself to maintainers.
  beets: Update to new upstream version 1.3.9.
  beets: Move into its own package directory.
-rw-r--r--pkgs/applications/audio/mp3gain/default.nix3
-rw-r--r--pkgs/tools/audio/beets/default.nix177
-rw-r--r--pkgs/tools/audio/beets/mediafile-codec-fix.patch25
-rw-r--r--pkgs/tools/audio/beets/replaygain-default-audiotools.patch17
-rw-r--r--pkgs/top-level/all-packages.nix2
-rw-r--r--pkgs/top-level/python-packages.nix117
6 files changed, 297 insertions, 44 deletions
diff --git a/pkgs/applications/audio/mp3gain/default.nix b/pkgs/applications/audio/mp3gain/default.nix
index 340658f813d7..3fef8398e9c9 100644
--- a/pkgs/applications/audio/mp3gain/default.nix
+++ b/pkgs/applications/audio/mp3gain/default.nix
@@ -14,8 +14,7 @@ stdenv.mkDerivation {
   buildFlags = [ "OSTYPE=linux" ];
 
   installPhase = ''
-    mkdir -p $out/usr/bin
-    cp mp3gain $out/usr/bin
+    install -vD mp3gain "$out/bin/mp3gain"
   '';
 
   meta = {
diff --git a/pkgs/tools/audio/beets/default.nix b/pkgs/tools/audio/beets/default.nix
new file mode 100644
index 000000000000..7e14154eb201
--- /dev/null
+++ b/pkgs/tools/audio/beets/default.nix
@@ -0,0 +1,177 @@
+{ stdenv, fetchFromGitHub, writeScript
+, buildPythonPackage, pythonPackages, python
+
+, enableAcoustid   ? true
+, enableBeatport   ? true
+, enableDiscogs    ? true
+, enableEchonest   ? true
+, enableFetchart   ? true
+, enableLastfm     ? true
+, enableMpd        ? true
+, enableReplaygain ? true
+, enableWeb        ? true
+
+, bashInteractive, bashCompletion
+}:
+
+assert enableAcoustid    -> pythonPackages.pyacoustid     != null;
+assert enableBeatport    -> pythonPackages.responses      != null;
+assert enableDiscogs     -> pythonPackages.discogs_client != null;
+assert enableEchonest    -> pythonPackages.pyechonest     != null;
+assert enableFetchart    -> pythonPackages.responses      != null;
+assert enableLastfm      -> pythonPackages.pylast         != null;
+assert enableMpd         -> pythonPackages.mpd            != null;
+assert enableReplaygain  -> pythonPackages.audiotools     != null;
+assert enableWeb         -> pythonPackages.flask          != null;
+
+with stdenv.lib;
+
+let
+  optionalPlugins = {
+    beatport = enableBeatport;
+    chroma = enableAcoustid;
+    discogs = enableDiscogs;
+    echonest = enableEchonest;
+    echonest_tempo = enableEchonest;
+    fetchart = enableFetchart;
+    lastgenre = enableLastfm;
+    lastimport = enableLastfm;
+    mpdstats = enableMpd;
+    mpdupdate = enableMpd;
+    replaygain = enableReplaygain;
+    web = enableWeb;
+  };
+
+  pluginsWithoutDeps = [
+    "bench" "bpd" "bpm" "bucket" "convert" "duplicates" "embedart" "freedesktop"
+    "fromfilename" "ftintitle" "fuzzy" "ihate" "importadded" "importfeeds"
+    "info" "inline" "keyfinder" "lyrics" "mbcollection" "mbsync" "missing"
+    "play" "random" "rewrite" "scrub" "smartplaylist" "spotify" "the" "types"
+    "zero"
+  ];
+
+  enabledOptionalPlugins = attrNames (filterAttrs (_: id) optionalPlugins);
+
+  allPlugins = pluginsWithoutDeps ++ attrNames optionalPlugins;
+  allEnabledPlugins = pluginsWithoutDeps ++ enabledOptionalPlugins;
+
+  # Discogs plugin wants to have an API token, so skip install checks.
+  allTestablePlugins = remove "discogs" allEnabledPlugins;
+
+  testShell = "${bashInteractive}/bin/bash --norc";
+  completion = "${bashCompletion}/share/bash-completion/bash_completion";
+
+in buildPythonPackage rec {
+  name = "beets-${version}";
+  version = "1.3.9";
+  namePrefix = "";
+
+  src = fetchFromGitHub {
+    owner = "sampsyo";
+    repo = "beets";
+    rev = "v${version}";
+    sha256 = "1srhkiyjqx6i3gn20ihf087l5pa77yh5b81ivc52lj491fda7xqk";
+  };
+
+  propagatedBuildInputs = [
+    pythonPackages.enum34
+    pythonPackages.munkres
+    pythonPackages.musicbrainzngs
+    pythonPackages.mutagen
+    pythonPackages.pyyaml
+    pythonPackages.unidecode
+    python.modules.sqlite3
+    python.modules.readline
+  ] ++ optional enableAcoustid                     pythonPackages.pyacoustid
+    ++ optional (enableBeatport || enableFetchart) pythonPackages.requests2
+    ++ optional enableDiscogs                      pythonPackages.discogs_client
+    ++ optional enableEchonest                     pythonPackages.pyechonest
+    ++ optional enableLastfm                       pythonPackages.pylast
+    ++ optional enableMpd                          pythonPackages.mpd
+    ++ optional enableReplaygain                   pythonPackages.audiotools
+    ++ optional enableWeb                          pythonPackages.flask;
+
+  buildInputs = with pythonPackages; [
+    beautifulsoup4
+    flask
+    mock
+    nose
+    pyechonest
+    pylast
+    rarfile
+    requests2
+    responses
+  ];
+
+  patches = [
+    ./mediafile-codec-fix.patch
+    ./replaygain-default-audiotools.patch
+  ];
+
+  postPatch = ''
+    sed -i -e '/assertIn.*item.*path/d' test/test_info.py
+    echo echo completion tests passed > test/test_completion.sh
+
+    sed -i -e '/^BASH_COMPLETION_PATHS *=/,/^])$/ {
+      /^])$/i u"${completion}"
+    }' beets/ui/commands.py
+  '';
+
+  doCheck = true;
+
+  preCheck = ''
+    (${concatMapStrings (s: "echo \"${s}\";") allPlugins}) \
+      | sort -u > plugins_defined
+    find beetsplug -mindepth 1 \
+      \! -path 'beetsplug/__init__.py' -a \
+      \( -name '*.py' -o -path 'beetsplug/*/__init__.py' \) -print \
+      | sed -n -re 's|^beetsplug/([^/.]+).*|\1|p' \
+      | sort -u > plugins_available
+
+    if ! mismatches="$(diff -y plugins_defined plugins_available)"; then
+      echo "The the list of defined plugins (left side) doesn't match" \
+           "the list of available plugins (right side):" >&2
+      echo "$mismatches" >&2
+      exit 1
+    fi
+  '';
+
+  checkPhase = ''
+    runHook preCheck
+
+    BEETS_TEST_SHELL="${testShell}" \
+    BASH_COMPLETION_SCRIPT="${completion}" \
+    HOME="$(mktemp -d)" \
+      nosetests -v
+
+    runHook postCheck
+  '';
+
+  doInstallCheck = true;
+
+  installCheckPhase = ''
+    runHook preInstallCheck
+
+    tmphome="$(mktemp -d)"
+
+    EDITOR="${writeScript "beetconfig.sh" ''
+      #!${stdenv.shell}
+      cat > "$1" <<CFG
+      plugins: ${concatStringsSep " " allTestablePlugins}
+      musicbrainz:
+        user: dummy
+        pass: dummy
+      CFG
+    ''}" HOME="$tmphome" "$out/bin/beet" config -e
+    EDITOR=true HOME="$tmphome" "$out/bin/beet" config -e
+
+    runHook postInstallCheck
+  '';
+
+  meta = {
+    homepage = http://beets.radbox.org;
+    description = "Music tagger and library organizer";
+    license = stdenv.lib.licenses.mit;
+    maintainers = with stdenv.lib.maintainers; [ iElectric aszlig ];
+  };
+}
diff --git a/pkgs/tools/audio/beets/mediafile-codec-fix.patch b/pkgs/tools/audio/beets/mediafile-codec-fix.patch
new file mode 100644
index 000000000000..7eaa5e19590e
--- /dev/null
+++ b/pkgs/tools/audio/beets/mediafile-codec-fix.patch
@@ -0,0 +1,25 @@
+From 903e88a228d6bd93bd1884c59dd23dd9f04a1199 Mon Sep 17 00:00:00 2001
+From: Adrian Sampson <adrian@radbox.org>
+Date: Wed, 26 Nov 2014 19:04:40 -0800
+Subject: [PATCH] Fix codec reference in MediaFile (fix #1117)
+
+---
+ beets/mediafile.py | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/beets/mediafile.py b/beets/mediafile.py
+index ce42621..a459e09 100644
+--- a/beets/mediafile.py
++++ b/beets/mediafile.py
+@@ -1340,8 +1340,9 @@ def __init__(self, path, id3v23=False):
+             raise FileTypeError(path)
+         elif (type(self.mgfile).__name__ == 'M4A' or
+               type(self.mgfile).__name__ == 'MP4'):
+-            if hasattr(self.mgfile.info, 'codec'):
+-                if self.mgfile.codec and self.mgfile.codec.startswith('alac'):
++            info = self.mgfile.info
++            if hasattr(info, 'codec'):
++                if info.codec and info.codec.startswith('alac'):
+                     self.type = 'alac'
+                 else:
+                     self.type = 'aac'
diff --git a/pkgs/tools/audio/beets/replaygain-default-audiotools.patch b/pkgs/tools/audio/beets/replaygain-default-audiotools.patch
new file mode 100644
index 000000000000..d852ea6fecaa
--- /dev/null
+++ b/pkgs/tools/audio/beets/replaygain-default-audiotools.patch
@@ -0,0 +1,17 @@
+diff --git a/beetsplug/replaygain.py b/beetsplug/replaygain.py
+index 40b3a3a..9b54a5a 100644
+--- a/beetsplug/replaygain.py
++++ b/beetsplug/replaygain.py
+@@ -627,11 +627,10 @@ class ReplayGainPlugin(BeetsPlugin):
+         super(ReplayGainPlugin, self).__init__()
+         self.import_stages = [self.imported]
+ 
+-        # default backend is 'command' for backward-compatibility.
+         self.config.add({
+             'overwrite': False,
+             'auto': True,
+-            'backend': u'command',
++            'backend': u'audiotools',
+             'targetlevel': 89,
+         })
+ 
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index f066f339f08f..aef3dc31166a 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -757,6 +757,8 @@ let
 
   beanstalkd = callPackage ../servers/beanstalkd { };
 
+  beets = callPackage ../tools/audio/beets { };
+
   bgs = callPackage ../tools/X11/bgs { };
 
   biber = callPackage ../tools/typesetting/biber {
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index 77e380105c84..1f84bf222200 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -531,6 +531,36 @@ let
     };
   });
 
+  audioread = buildPythonPackage rec {
+    name = "audioread-1.2.1";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/a/audioread/${name}.tar.gz";
+      md5 = "01a80357f38dbd9bf8d7403802df89ac";
+    };
+
+    meta = {
+      description = "Cross-platform audio decoding";
+      homepage = "https://github.com/sampsyo/audioread";
+      license = stdenv.lib.licenses.mit;
+    };
+  };
+
+  audiotools = buildPythonPackage rec {
+    name = "audiotools-2.22";
+
+    src = pkgs.fetchurl {
+      url = "mirror://sourceforge/audiotools/${name}.tar.gz";
+      sha256 = "1c52pggsbxdbj8h92njf4h0jgfndh4yv58ad723pidys47nw1y71";
+    };
+
+    meta = {
+      description = "Utilities and Python modules for handling audio.";
+      homepage = "http://audiotools.sourceforge.net/";
+      license = stdenv.lib.licenses.gpl2Plus;
+    };
+  };
+
   autopep8 = buildPythonPackage (rec {
     name = "autopep8-1.0.4";
 
@@ -789,44 +819,6 @@ let
     };
   };
 
-  beets = buildPythonPackage rec {
-    name = "beets-1.3.6";
-
-    src = pkgs.fetchurl {
-      url = "http://pypi.python.org/packages/source/b/beets/${name}.tar.gz";
-      md5 = "59615a54b3ac3983159e77ff9dda373e";
-    };
-
-    # tests depend on $HOME setting
-    preConfigure = "export HOME=$TMPDIR";
-
-    propagatedBuildInputs =
-      [ self.pyyaml
-        self.unidecode
-        self.mutagen
-        self.munkres
-        self.musicbrainzngs
-        self.enum34
-        self.pylast
-        self.rarfile
-        self.flask
-        modules.sqlite3
-        modules.readline
-      ];
-
-    buildInputs = with self; [ mock pyechonest six responses nose ];
-
-    # 10 tests are failing
-    doCheck = false;
-
-    meta = {
-      homepage = http://beets.radbox.org;
-      description = "Music tagger and library organizer";
-      license = licenses.mit;
-      maintainers = [ stdenv.lib.maintainers.iElectric ];
-    };
-  };
-
   circus = buildPythonPackage rec {
     name = "circus-0.11.1";
 
@@ -2191,6 +2183,23 @@ let
     };
   };
 
+  discogs_client = buildPythonPackage rec {
+    name = "discogs-client-2.0.2";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/d/discogs-client/${name}.tar.gz";
+      md5 = "2cc57e1d134aa93404e779b9311676fa";
+    };
+
+    propagatedBuildInputs = with self; [ oauth2 requests ];
+
+    meta = {
+      description = "Official Python API client for Discogs";
+      license = licenses.bsd2;
+      homepage = "https://github.com/discogs/discogs_client";
+    };
+  };
+
   dns = buildPythonPackage rec {
     name = "dnspython-${version}";
     version = "1.12.0";
@@ -5760,15 +5769,15 @@ let
   };
 
   mutagen = buildPythonPackage (rec {
-    name = "mutagen-1.23";
+    name = "mutagen-1.27";
 
     src = pkgs.fetchurl {
       url = "http://pypi.python.org/packages/source/m/mutagen/${name}.tar.gz";
-      sha256 = "12f70aaf5ggdzll76bhhkn64b27xy9s1acx417dbsaqnnbis8s76";
+      md5 = "6a9bb5cc33214add35348f1bb3448340";
     };
 
-    # one unicode test fails
-    doCheck = false;
+    # Needed for tests only
+    buildInputs = [ pkgs.faad2 pkgs.flac pkgs.vorbisTools pkgs.liboggz ];
 
     meta = {
       description = "Python multimedia tagging library";
@@ -6984,6 +6993,30 @@ let
   };
 
 
+  pyacoustid = buildPythonPackage rec {
+    name = "pyacoustid-1.1.0";
+
+    src = pkgs.fetchurl {
+      url = "https://pypi.python.org/packages/source/p/pyacoustid/${name}.tar.gz";
+      md5 = "b27c714d530300b917eb869726334226";
+    };
+
+    propagatedBuildInputs = with self; [ requests audioread ];
+
+    postPatch = ''
+      sed -i \
+          -e '/^FPCALC_COMMAND *=/s|=.*|= "${pkgs.chromaprint}/bin/fpcalc"|' \
+          acoustid.py
+    '';
+
+    meta = {
+      description = "Bindings for Chromaprint acoustic fingerprinting";
+      homepage = "https://github.com/sampsyo/pyacoustid";
+      license = stdenv.lib.licenses.mit;
+    };
+  };
+
+
   pyalgotrade = buildPythonPackage {
     name = "pyalogotrade-0.16";