From ff81bbf8f5b7ce008ea49dd2c979ad7ba5be8f50 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Wed, 30 Dec 2015 22:03:50 -0600 Subject: [PATCH 01/14] ABrainz: Added first pass of plugin. Only prints MBID and response status code to console. --- beetsplug/acoustic.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 beetsplug/acoustic.py diff --git a/beetsplug/acoustic.py b/beetsplug/acoustic.py new file mode 100644 index 000000000..4eb7ea2de --- /dev/null +++ b/beetsplug/acoustic.py @@ -0,0 +1,38 @@ +from __future__ import (division, absolute_import, print_function, + unicode_literals) + + +from beets import plugins, ui +import requests + +ACOUSTIC_URL = "http://acousticbrainz.org/" +LEVEL = "/high-level" +PLUGIN_DESCRIPTION = "Fetch metadata from AcousticBrainz" + + +class AcousticPlugin(plugins.BeetsPlugin): + def __init__(self): + super(AcousticPlugin, self).__init__() + + def commands(self): + cmd = ui.Subcommand('acoustic', help=PLUGIN_DESCRIPTION) + + def func(lib, opts, args): + fetch_info(lib) + + cmd.func = func + return [cmd] + + +# Currently outputs MBID and corresponding request status code +def fetch_info(lib): + for item in lib.items(): + if item.mb_trackid: + r = requests.get(generate_url(item.mb_trackid)) + print(item.mb_trackid) + print(r.status_code) + + +# Generates url of AcousticBrainz end point for given MBID +def generate_url(mbid): + return ACOUSTIC_URL + mbid + LEVEL From 29e6cbedfe4fa3eb31ca033ef776c98eafa605c6 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Wed, 30 Dec 2015 22:27:53 -0600 Subject: [PATCH 02/14] ABrainz: Added copyright header, docstrings, and followed long line standards. --- beetsplug/acoustic.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/beetsplug/acoustic.py b/beetsplug/acoustic.py index 4eb7ea2de..99eb024a8 100644 --- a/beetsplug/acoustic.py +++ b/beetsplug/acoustic.py @@ -1,3 +1,20 @@ +# -*- coding: utf-8 -*- +# This file is part of beets. +# Copyright 2016, Adrian Sampson. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +""" Fetch various AcousticBrainz metadata using MBID +""" from __future__ import (division, absolute_import, print_function, unicode_literals) @@ -7,7 +24,6 @@ import requests ACOUSTIC_URL = "http://acousticbrainz.org/" LEVEL = "/high-level" -PLUGIN_DESCRIPTION = "Fetch metadata from AcousticBrainz" class AcousticPlugin(plugins.BeetsPlugin): @@ -15,7 +31,8 @@ class AcousticPlugin(plugins.BeetsPlugin): super(AcousticPlugin, self).__init__() def commands(self): - cmd = ui.Subcommand('acoustic', help=PLUGIN_DESCRIPTION) + cmd = ui.Subcommand('acoustic', + help="fetch metadata from AcousticBrainz") def func(lib, opts, args): fetch_info(lib) @@ -24,8 +41,9 @@ class AcousticPlugin(plugins.BeetsPlugin): return [cmd] -# Currently outputs MBID and corresponding request status code def fetch_info(lib): + """Currently outputs MBID and corresponding request status code + """ for item in lib.items(): if item.mb_trackid: r = requests.get(generate_url(item.mb_trackid)) @@ -33,6 +51,7 @@ def fetch_info(lib): print(r.status_code) -# Generates url of AcousticBrainz end point for given MBID def generate_url(mbid): + """Generates url of AcousticBrainz end point for given MBID + """ return ACOUSTIC_URL + mbid + LEVEL From 9daa02b5b0b9726dec5b85c51e639646b256b1d3 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Wed, 30 Dec 2015 23:34:56 -0600 Subject: [PATCH 03/14] ABrainz: Added write for three attributes to metadata and easier dictionary traversal format. --- beetsplug/acoustic.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/beetsplug/acoustic.py b/beetsplug/acoustic.py index 99eb024a8..62ea8aa6f 100644 --- a/beetsplug/acoustic.py +++ b/beetsplug/acoustic.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # This file is part of beets. -# Copyright 2016, Adrian Sampson. +# Copyright 2016, Ohm Patel. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -18,9 +18,9 @@ from __future__ import (division, absolute_import, print_function, unicode_literals) +import requests from beets import plugins, ui -import requests ACOUSTIC_URL = "http://acousticbrainz.org/" LEVEL = "/high-level" @@ -46,12 +46,32 @@ def fetch_info(lib): """ for item in lib.items(): if item.mb_trackid: - r = requests.get(generate_url(item.mb_trackid)) - print(item.mb_trackid) - print(r.status_code) + rs = requests.get(generate_url(item.mb_trackid)).json() + + item.abrainz_danceable = get_value(rs, ["highlevel", + "danceability", + "all", + "danceable"]) + item.abrainz_happy = get_value(rs, ["highlevel", + "mood_happy", + "all", + "happy"]) + item.abrainz_party = get_value(rs, ["highlevel", + "mood_party", + "all", + "party"]) + + item.write() + item.store() def generate_url(mbid): """Generates url of AcousticBrainz end point for given MBID """ return ACOUSTIC_URL + mbid + LEVEL + + +def get_value(data, map_path): + """Allows traversal of dictionary with cleaner formatting + """ + return reduce(lambda d, k: d[k], map_path, data) From 59a1333732c12cf32cf2408103cd98f579c9f7e7 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Wed, 30 Dec 2015 23:38:19 -0600 Subject: [PATCH 04/14] ABrainz: Renamed danceable to dance to match five character attribute --- beetsplug/acoustic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/beetsplug/acoustic.py b/beetsplug/acoustic.py index 62ea8aa6f..eab5d2c72 100644 --- a/beetsplug/acoustic.py +++ b/beetsplug/acoustic.py @@ -48,10 +48,10 @@ def fetch_info(lib): if item.mb_trackid: rs = requests.get(generate_url(item.mb_trackid)).json() - item.abrainz_danceable = get_value(rs, ["highlevel", - "danceability", - "all", - "danceable"]) + item.abrainz_dance = get_value(rs, ["highlevel", + "danceability", + "all", + "danceable"]) item.abrainz_happy = get_value(rs, ["highlevel", "mood_happy", "all", From ed6d9087a9ac60224ac0029cb5cce8a965dc2ba8 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 00:50:49 -0600 Subject: [PATCH 05/14] ABrainz: Added error catching and renamed to abrainz --- beetsplug/{acoustic.py => abrainz.py} | 44 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 18 deletions(-) rename beetsplug/{acoustic.py => abrainz.py} (54%) diff --git a/beetsplug/acoustic.py b/beetsplug/abrainz.py similarity index 54% rename from beetsplug/acoustic.py rename to beetsplug/abrainz.py index eab5d2c72..4ebc3d0d6 100644 --- a/beetsplug/acoustic.py +++ b/beetsplug/abrainz.py @@ -31,35 +31,40 @@ class AcousticPlugin(plugins.BeetsPlugin): super(AcousticPlugin, self).__init__() def commands(self): - cmd = ui.Subcommand('acoustic', + cmd = ui.Subcommand('abrainz', help="fetch metadata from AcousticBrainz") def func(lib, opts, args): - fetch_info(lib) + fetch_info(self, lib) cmd.func = func return [cmd] -def fetch_info(lib): +def fetch_info(self, lib): """Currently outputs MBID and corresponding request status code """ for item in lib.items(): if item.mb_trackid: - rs = requests.get(generate_url(item.mb_trackid)).json() + rs = requests.get(generate_url(item.mb_trackid)) - item.abrainz_dance = get_value(rs, ["highlevel", - "danceability", - "all", - "danceable"]) - item.abrainz_happy = get_value(rs, ["highlevel", - "mood_happy", - "all", - "happy"]) - item.abrainz_party = get_value(rs, ["highlevel", - "mood_party", - "all", - "party"]) + try: + rs.json() + except ValueError: + self._log.debug('abrainz: Invalid Response: {}', rs.text) + + item.danceable = get_value(self._log, rs.json(), ["highlevel", + "danceability", + "all", + "danceable"]) + item.mood_happy = get_value(self._log, rs.json(), ["highlevel", + "mood_happy", + "all", + "happy"]) + item.mood_party = get_value(self._log, rs.json(), ["highlevel", + "mood_party", + "all", + "party"]) item.write() item.store() @@ -71,7 +76,10 @@ def generate_url(mbid): return ACOUSTIC_URL + mbid + LEVEL -def get_value(data, map_path): +def get_value(log, data, map_path): """Allows traversal of dictionary with cleaner formatting """ - return reduce(lambda d, k: d[k], map_path, data) + try: + return reduce(lambda d, k: d[k], map_path, data) + except KeyError: + log.debug('Invalid Path: {}', map_path) From d15d7efbf4eda44b421e6f3a11e5cc86eb1b9acd Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 00:53:05 -0600 Subject: [PATCH 06/14] ABrainz: Removed repeated portion of error message --- beetsplug/abrainz.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/abrainz.py b/beetsplug/abrainz.py index 4ebc3d0d6..615b2a2b8 100644 --- a/beetsplug/abrainz.py +++ b/beetsplug/abrainz.py @@ -51,7 +51,7 @@ def fetch_info(self, lib): try: rs.json() except ValueError: - self._log.debug('abrainz: Invalid Response: {}', rs.text) + self._log.debug('Invalid Response: {}', rs.text) item.danceable = get_value(self._log, rs.json(), ["highlevel", "danceability", From bcd4c6d556d6686af6d570afe9cb492df1e5e0a8 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 01:12:52 -0600 Subject: [PATCH 07/14] ABrainz: Added initial documentation --- docs/plugins/abrainz.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docs/plugins/abrainz.rst diff --git a/docs/plugins/abrainz.rst b/docs/plugins/abrainz.rst new file mode 100644 index 000000000..c53a1921b --- /dev/null +++ b/docs/plugins/abrainz.rst @@ -0,0 +1,16 @@ +ABrainz Plugin +=========== + +The ``abrainz`` plugin provides a command that traverses through a library and tags tracks with valid MusicBrainz IDs with additional metadata such as +* ```danceable``` + + Predicts how easy the track is danceable to +* ```mood_happy``` + + Predicts the probability this track is played to invoke happiness +* ```mood_party``` + + Predicts the probability this track is played in a party environment + +Enable the ``abrainz`` plugin in your configuration (see :ref:`using-plugins`) and run with: + + $ beet abrainz + +Additional command-line options coming soon. \ No newline at end of file From 61830958e692ec9a7e0b4786a2cc3ca98d250f05 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 01:14:30 -0600 Subject: [PATCH 08/14] ABrainz: Fix slight bugs on Doc page --- docs/plugins/abrainz.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/plugins/abrainz.rst b/docs/plugins/abrainz.rst index c53a1921b..3739f9d24 100644 --- a/docs/plugins/abrainz.rst +++ b/docs/plugins/abrainz.rst @@ -2,11 +2,12 @@ ABrainz Plugin =========== The ``abrainz`` plugin provides a command that traverses through a library and tags tracks with valid MusicBrainz IDs with additional metadata such as -* ```danceable``` + +* ``danceable`` + Predicts how easy the track is danceable to -* ```mood_happy``` +* ``mood_happy`` + Predicts the probability this track is played to invoke happiness -* ```mood_party``` +* ``mood_party`` + Predicts the probability this track is played in a party environment Enable the ``abrainz`` plugin in your configuration (see :ref:`using-plugins`) and run with: From fdd1534cf35dd803de72660a4e569113c7a227a2 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 01:19:28 -0600 Subject: [PATCH 09/14] ABrainz: Doc title underline too short --- docs/plugins/abrainz.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/abrainz.rst b/docs/plugins/abrainz.rst index 3739f9d24..471d31fcb 100644 --- a/docs/plugins/abrainz.rst +++ b/docs/plugins/abrainz.rst @@ -1,5 +1,5 @@ ABrainz Plugin -=========== +============== The ``abrainz`` plugin provides a command that traverses through a library and tags tracks with valid MusicBrainz IDs with additional metadata such as From ff89716a4d6eb3fb0bc1a72c71fd097b09198273 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 01:23:44 -0600 Subject: [PATCH 10/14] ABrainz: Add abrainz doc to toctree --- docs/plugins/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index 5da5ee0be..4b10275e8 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -31,6 +31,7 @@ Each plugin has its own set of options that can be defined in a section bearing .. toctree:: :hidden: + abrainz badfiles bpd bpm @@ -94,6 +95,7 @@ Autotagger Extensions Metadata -------- +* :doc:`abrainz`: Fetch various AcousticBrainz metadata * :doc:`bpm`: Measure tempo using keystrokes. * :doc:`echonest`: Automatically fetch `acoustic attributes`_ from `the Echo Nest`_ (tempo, energy, danceability, ...). From 5201e1cde742935170040815d6cbda6237d03b4d Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 08:56:55 -0600 Subject: [PATCH 11/14] Rename --- beetsplug/{abrainz.py => acousticbrainz.py} | 0 docs/plugins/{abrainz.rst => acousticbrainz.rst} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename beetsplug/{abrainz.py => acousticbrainz.py} (100%) rename docs/plugins/{abrainz.rst => acousticbrainz.rst} (100%) diff --git a/beetsplug/abrainz.py b/beetsplug/acousticbrainz.py similarity index 100% rename from beetsplug/abrainz.py rename to beetsplug/acousticbrainz.py diff --git a/docs/plugins/abrainz.rst b/docs/plugins/acousticbrainz.rst similarity index 100% rename from docs/plugins/abrainz.rst rename to docs/plugins/acousticbrainz.rst From 6337b7ff084fdaf186b5eabc3cffa554b09a74d0 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 08:57:19 -0600 Subject: [PATCH 12/14] Rename commands and files --- beetsplug/acousticbrainz.py | 2 +- docs/plugins/acousticbrainz.rst | 8 ++++---- docs/plugins/index.rst | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/beetsplug/acousticbrainz.py b/beetsplug/acousticbrainz.py index 615b2a2b8..bb33e0515 100644 --- a/beetsplug/acousticbrainz.py +++ b/beetsplug/acousticbrainz.py @@ -31,7 +31,7 @@ class AcousticPlugin(plugins.BeetsPlugin): super(AcousticPlugin, self).__init__() def commands(self): - cmd = ui.Subcommand('abrainz', + cmd = ui.Subcommand('acousticbrainz', help="fetch metadata from AcousticBrainz") def func(lib, opts, args): diff --git a/docs/plugins/acousticbrainz.rst b/docs/plugins/acousticbrainz.rst index 471d31fcb..f48104766 100644 --- a/docs/plugins/acousticbrainz.rst +++ b/docs/plugins/acousticbrainz.rst @@ -1,7 +1,7 @@ -ABrainz Plugin +Acousticbrainz Plugin ============== -The ``abrainz`` plugin provides a command that traverses through a library and tags tracks with valid MusicBrainz IDs with additional metadata such as +The ``acoustricbrainz`` plugin provides a command that traverses through a library and tags tracks with valid MusicBrainz IDs with additional metadata such as * ``danceable`` + Predicts how easy the track is danceable to @@ -10,8 +10,8 @@ The ``abrainz`` plugin provides a command that traverses through a library and t * ``mood_party`` + Predicts the probability this track is played in a party environment -Enable the ``abrainz`` plugin in your configuration (see :ref:`using-plugins`) and run with: +Enable the ``acousticbrainz`` plugin in your configuration (see :ref:`using-plugins`) and run with: $ beet abrainz -Additional command-line options coming soon. \ No newline at end of file +Additional command-line options coming soon. diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index 4b10275e8..0c1c4ce11 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -31,7 +31,7 @@ Each plugin has its own set of options that can be defined in a section bearing .. toctree:: :hidden: - abrainz + acousticbrainz badfiles bpd bpm @@ -95,7 +95,7 @@ Autotagger Extensions Metadata -------- -* :doc:`abrainz`: Fetch various AcousticBrainz metadata +* :doc:`acousticbrainz`: Fetch various AcousticBrainz metadata * :doc:`bpm`: Measure tempo using keystrokes. * :doc:`echonest`: Automatically fetch `acoustic attributes`_ from `the Echo Nest`_ (tempo, energy, danceability, ...). From fa9039381cdb91a8ecb97c306eef3a406fa938b3 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 09:01:13 -0600 Subject: [PATCH 13/14] Update docs --- docs/plugins/acousticbrainz.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/acousticbrainz.rst b/docs/plugins/acousticbrainz.rst index f48104766..7019671a2 100644 --- a/docs/plugins/acousticbrainz.rst +++ b/docs/plugins/acousticbrainz.rst @@ -1,5 +1,5 @@ Acousticbrainz Plugin -============== +===================== The ``acoustricbrainz`` plugin provides a command that traverses through a library and tags tracks with valid MusicBrainz IDs with additional metadata such as @@ -12,6 +12,6 @@ The ``acoustricbrainz`` plugin provides a command that traverses through a libra Enable the ``acousticbrainz`` plugin in your configuration (see :ref:`using-plugins`) and run with: - $ beet abrainz + $ beet acousticbrainz Additional command-line options coming soon. From ad57943819078d36843c2e0037edae4c9ebe2138 Mon Sep 17 00:00:00 2001 From: Ohm Patel Date: Thu, 31 Dec 2015 09:35:01 -0600 Subject: [PATCH 14/14] Updated Copyright Year --- beetsplug/acousticbrainz.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/acousticbrainz.py b/beetsplug/acousticbrainz.py index bb33e0515..fa1d71b5f 100644 --- a/beetsplug/acousticbrainz.py +++ b/beetsplug/acousticbrainz.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # This file is part of beets. -# Copyright 2016, Ohm Patel. +# Copyright 2015-2016, Ohm Patel. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the