From 5233e0fcddcba20fb9b79dc650dc137197316791 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 19 Jan 2017 11:31:25 -0800 Subject: [PATCH 01/42] Avoid stdout encoding issues (#2393) --- beets/ui/__init__.py | 17 +++++++++++------ docs/changelog.rst | 3 +++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index ae30a9c60..d69870737 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -126,8 +126,7 @@ def print_(*strings, **kwargs): Python 3. The `end` keyword argument behaves similarly to the built-in `print` - (it defaults to a newline). The value should have the same string - type as the arguments. + (it defaults to a newline). """ if not strings: strings = [u''] @@ -136,11 +135,17 @@ def print_(*strings, **kwargs): txt = u' '.join(strings) txt += kwargs.get('end', u'\n') - # Send bytes to the stdout stream on Python 2. + # Encode the string and write it to stdout. + txt = txt.encode(_out_encoding(), 'replace') if six.PY2: - txt = txt.encode(_out_encoding(), 'replace') - - sys.stdout.write(txt) + # On Python 2, sys.stdout expects bytes. + sys.stdout.write(txt) + else: + # On Python 3, sys.stdout expects text strings and uses the + # exception-throwing encoding error policy. To avoid throwing + # errors and use our configurable encoding override, we use the + # underlying bytes buffer instead. + sys.stdout.buffer.write(txt) # Configuration wrappers. diff --git a/docs/changelog.rst b/docs/changelog.rst index 4fa8aa50f..3b920e51a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -24,6 +24,9 @@ Fixes: * :doc:`/plugins/replaygain`: Fix Python 3 compatibility in the ``bs1770gain`` backend. :bug:`2382` * :doc:`/plugins/bpd`: Report playback times as integer. :bug:`2394` +* On Python 3, the :ref:`terminal_encoding` setting is respected again for + output and printing will no longer crash on systems configured with a + limited encoding. 1.4.3 (January 9, 2017) From a99d5d2ed2081172a3d486a492319cd87e02d141 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 19 Jan 2017 11:42:46 -0800 Subject: [PATCH 02/42] On Python 3 in tests, record `str` output directly This is a little ugly. Eventually, it would be nice to create a single output stream set up with the appropriate encoding settings *at startup* and use that repeatedly, instead of having `print_` check the settings every time. This output stream could be cleanly replaced with a mock harness for testing. Yet another reason to desire a big "beets context" object... --- beets/ui/__init__.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index d69870737..df370b52e 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -136,16 +136,22 @@ def print_(*strings, **kwargs): txt += kwargs.get('end', u'\n') # Encode the string and write it to stdout. - txt = txt.encode(_out_encoding(), 'replace') if six.PY2: # On Python 2, sys.stdout expects bytes. - sys.stdout.write(txt) + out = txt.encode(_out_encoding(), 'replace') + sys.stdout.write(out) else: # On Python 3, sys.stdout expects text strings and uses the # exception-throwing encoding error policy. To avoid throwing # errors and use our configurable encoding override, we use the # underlying bytes buffer instead. - sys.stdout.buffer.write(txt) + if hasattr(sys.stdout, 'buffer'): + out = txt.encode(_out_encoding(), 'replace') + sys.stdout.buffer.write(out) + else: + # In our test harnesses (e.g., DummyOut), sys.stdout.buffer + # does not exist. We instead just record the text string. + sys.stdout.write(txt) # Configuration wrappers. From 77d155cdea473873b8e179eefa180901f12c1623 Mon Sep 17 00:00:00 2001 From: Pauligrinder Date: Mon, 23 Jan 2017 12:43:40 +0200 Subject: [PATCH 03/42] Add a plugin to update a Kodi music library I created one for an older version before, but it didn't work since the change to Python 3. So I created a new one that works. --- beetsplug/kodiupdate.py | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 beetsplug/kodiupdate.py diff --git a/beetsplug/kodiupdate.py b/beetsplug/kodiupdate.py new file mode 100644 index 000000000..236f914bf --- /dev/null +++ b/beetsplug/kodiupdate.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +"""Updates a Kodi library whenever the beets library is changed. This is based on the Plex Update plugin. + +Put something like the following in your config.yaml to configure: + kodi: + host: localhost + port: 8080 + user: user + pwd: secret +""" +from __future__ import division, absolute_import, print_function + +import requests +import json +from requests.auth import HTTPBasicAuth +from beets import config +from beets.plugins import BeetsPlugin + + +def update_kodi(host, port, user, password): + """Sends request to the Kodi api to start a library refresh. + """ + url = "http://{0}:{1}/jsonrpc/".format(host, port) + + # The kodi jsonrpc documentation states that Content-Type: application/json is mandatory + headers = {'Content-Type': 'application/json'} + # Create the payload. Id seems to be mandatory. + payload = {'jsonrpc': '2.0', 'method':'AudioLibrary.Scan', 'id':1} + r = requests.post(url, auth=HTTPBasicAuth(user, password), json=payload, headers=headers) + return r + +class KodiUpdate(BeetsPlugin): + def __init__(self): + super(KodiUpdate, self).__init__() + + # Adding defaults. + config['kodi'].add({ + u'host': u'localhost', + u'port': 8080, + u'user': u'kodi', + u'pwd': u'kodi'}) + + self.register_listener('database_change', self.listen_for_db_change) + + def listen_for_db_change(self, lib, model): + """Listens for beets db change and register the update for the end""" + self.register_listener('cli_exit', self.update) + + def update(self, lib): + """When the client exists try to send refresh request to Kodi server. + """ + self._log.info(u'Updating Kodi library...') + + # Try to send update request. + try: + update_kodi( + config['kodi']['host'].get(), + config['kodi']['port'].get(), + config['kodi']['user'].get(), + config['kodi']['pwd'].get()) + self._log.info(u'... started.') + + except requests.exceptions.RequestException: + self._log.warning(u'Update failed.') + From ca8832809daf6e57b5bd61a3b2c03640b22dbe9c Mon Sep 17 00:00:00 2001 From: Pauligrinder Date: Mon, 23 Jan 2017 13:14:36 +0200 Subject: [PATCH 04/42] Removed a couple of unnecessary imports json and requests.BasicAuthentication --- beetsplug/kodiupdate.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/beetsplug/kodiupdate.py b/beetsplug/kodiupdate.py index 236f914bf..31c978dd6 100644 --- a/beetsplug/kodiupdate.py +++ b/beetsplug/kodiupdate.py @@ -12,8 +12,6 @@ Put something like the following in your config.yaml to configure: from __future__ import division, absolute_import, print_function import requests -import json -from requests.auth import HTTPBasicAuth from beets import config from beets.plugins import BeetsPlugin @@ -27,7 +25,7 @@ def update_kodi(host, port, user, password): headers = {'Content-Type': 'application/json'} # Create the payload. Id seems to be mandatory. payload = {'jsonrpc': '2.0', 'method':'AudioLibrary.Scan', 'id':1} - r = requests.post(url, auth=HTTPBasicAuth(user, password), json=payload, headers=headers) + r = requests.post(url, auth=(user, password), json=payload, headers=headers) return r class KodiUpdate(BeetsPlugin): From 3e4c9b8c06fb78477aa95e1056f44b9c17ed7d0b Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Mon, 20 Feb 2017 16:24:17 -0800 Subject: [PATCH 05/42] discogs: support simple auth. The official OAuth authentication seems to have broken, so allow usage of simple configuration instead. See-Also: https://github.com/discogs/discogs_client/issues/78 Signed-off-by: Robin H. Johnson --- beetsplug/discogs.py | 8 ++++++++ docs/plugins/discogs.rst | 22 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index 3b3f5f201..c9e4f3c18 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -54,9 +54,11 @@ class DiscogsPlugin(BeetsPlugin): 'apisecret': 'plxtUTqoCzwxZpqdPysCwGuBSmZNdZVy', 'tokenfile': 'discogs_token.json', 'source_weight': 0.5, + 'user_token': None, }) self.config['apikey'].redact = True self.config['apisecret'].redact = True + self.config['user_token'].redact = True self.discogs_client = None self.register_listener('import_begin', self.setup) @@ -66,6 +68,12 @@ class DiscogsPlugin(BeetsPlugin): c_key = self.config['apikey'].as_str() c_secret = self.config['apisecret'].as_str() + user_token = self.config['user_token'].as_str() + + if user_token is not None and user_token != '': + self.discogs_client = Client(USER_AGENT, user_token=user_token) + return + # Get the OAuth token from a file or log in. try: with open(self._tokenfile()) as f: diff --git a/docs/plugins/discogs.rst b/docs/plugins/discogs.rst index eb60cca58..56413eed6 100644 --- a/docs/plugins/discogs.rst +++ b/docs/plugins/discogs.rst @@ -14,10 +14,9 @@ To use the ``discogs`` plugin, first enable it in your configuration (see pip install discogs-client -You will also need to register for a `Discogs`_ account. The first time you -run the :ref:`import-cmd` command after enabling the plugin, it will ask you -to authorize with Discogs by visiting the site in a browser. Subsequent runs -will not require re-authorization. +You will also need to register for a `Discogs`_ account, and provide +authentication credentials via a personal access token or an OAuth2 +authorization. Matches from Discogs will now show up during import alongside matches from MusicBrainz. @@ -25,6 +24,21 @@ MusicBrainz. If you have a Discogs ID for an album you want to tag, you can also enter it at the "enter Id" prompt in the importer. +OAuth authorization +``````````````````` +The first time you run the :ref:`import-cmd` command after enabling the plugin, +it will ask you to authorize with Discogs by visiting the site in a browser. +Subsequent runs will not require re-authorization. + +Authentication via personal access token +```````````````````````````````````````` +To get a personal access token (called a user token in the `discogs-client`_ +documentation), login to `Discogs`_, and visit the +`Developer settings page +`_. Press the ``Generate new +token`` button, and place the generated token in your configuration, as the +``user_token`` config option in the ``discogs`` section. + Troubleshooting --------------- From a29b29f533d3efb71f3df56fd2bb406679b8712d Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 21 Feb 2017 09:49:22 -0500 Subject: [PATCH 06/42] Docs improvements for #2447 --- beetsplug/discogs.py | 4 ++-- docs/plugins/discogs.rst | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index c9e4f3c18..a9b708619 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -68,9 +68,9 @@ class DiscogsPlugin(BeetsPlugin): c_key = self.config['apikey'].as_str() c_secret = self.config['apisecret'].as_str() + # Try using a configured user token (bypassing OAuth login). user_token = self.config['user_token'].as_str() - - if user_token is not None and user_token != '': + if user_token: self.discogs_client = Client(USER_AGENT, user_token=user_token) return diff --git a/docs/plugins/discogs.rst b/docs/plugins/discogs.rst index 56413eed6..a02b34590 100644 --- a/docs/plugins/discogs.rst +++ b/docs/plugins/discogs.rst @@ -24,15 +24,19 @@ MusicBrainz. If you have a Discogs ID for an album you want to tag, you can also enter it at the "enter Id" prompt in the importer. -OAuth authorization +OAuth Authorization ``````````````````` + The first time you run the :ref:`import-cmd` command after enabling the plugin, it will ask you to authorize with Discogs by visiting the site in a browser. Subsequent runs will not require re-authorization. -Authentication via personal access token +Authentication via Personal Access Token ```````````````````````````````````````` -To get a personal access token (called a user token in the `discogs-client`_ + +As an alternative to OAuth, you can get a token from Discogs and add it to +your configuration. +To get a personal access token (called a "user token" in the `discogs-client`_ documentation), login to `Discogs`_, and visit the `Developer settings page `_. Press the ``Generate new From 6cb9504403f5acba07d1614f037cbd37e65735f5 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 21 Feb 2017 09:49:56 -0500 Subject: [PATCH 07/42] Changelog for #2447 --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4734ba05a..2fbb453c7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -48,6 +48,8 @@ Fixes: command is not found or exists with an error. :bug:`2430` :bug:`2433` * :doc:`/plugins/lyrics`: The Google search backend no longer crashes when the server responds with an error. :bug:`2437` +* :doc:`/plugins/discogs`: You can now authenticate with Discogs using a + personal access token. :bug:`2447` 1.4.3 (January 9, 2017) From d6905fa4c0ba3fcf8ddfbc1d8cc1c863c4c6dc62 Mon Sep 17 00:00:00 2001 From: Stephane Fontaine Date: Tue, 21 Feb 2017 21:29:52 +0400 Subject: [PATCH 08/42] Decode bytes to str before call to path_test Fixes #2443 --- beets/importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beets/importer.py b/beets/importer.py index bbe152cd4..690a499ff 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -988,7 +988,7 @@ class ArchiveImportTask(SentinelImportTask): `toppath` to that directory. """ for path_test, handler_class in self.handlers(): - if path_test(self.toppath): + if path_test(util.py3_path(self.toppath)): break try: From 74c0e0d6e9075df94361a4588d4c4271e062e88f Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 21 Feb 2017 13:56:20 -0500 Subject: [PATCH 09/42] Fix default for user_token Always match the expected type. --- beetsplug/discogs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index a9b708619..0957b3403 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -54,7 +54,7 @@ class DiscogsPlugin(BeetsPlugin): 'apisecret': 'plxtUTqoCzwxZpqdPysCwGuBSmZNdZVy', 'tokenfile': 'discogs_token.json', 'source_weight': 0.5, - 'user_token': None, + 'user_token': '', }) self.config['apikey'].redact = True self.config['apisecret'].redact = True From 8bfdabb0c60acbd379f20b6682b114943233bf17 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 21 Feb 2017 21:43:13 -0500 Subject: [PATCH 10/42] Changelog entry for #2448 --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 2fbb453c7..c3f950d2d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -50,6 +50,8 @@ Fixes: server responds with an error. :bug:`2437` * :doc:`/plugins/discogs`: You can now authenticate with Discogs using a personal access token. :bug:`2447` +* Fix Python 3 compatibility when extracting rar archives in the importer. + Thanks to :user:`Lompik`. :bug:`2443` :bug:`2448` 1.4.3 (January 9, 2017) From 77a6b0edf8d38a3600b27c6754915dc64e56b8d7 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 21 Feb 2017 22:00:31 -0500 Subject: [PATCH 11/42] duplicates: Fix 2nd bug in #2444 about path types --- beetsplug/duplicates.py | 7 ++++--- docs/changelog.rst | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/beetsplug/duplicates.py b/beetsplug/duplicates.py index 5ca314d3f..93d53c58a 100644 --- a/beetsplug/duplicates.py +++ b/beetsplug/duplicates.py @@ -21,7 +21,8 @@ import shlex from beets.plugins import BeetsPlugin from beets.ui import decargs, print_, Subcommand, UserError -from beets.util import command_output, displayable_path, subprocess +from beets.util import command_output, displayable_path, subprocess, \ + bytestring_path from beets.library import Item, Album import six @@ -112,14 +113,14 @@ class DuplicatesPlugin(BeetsPlugin): self.config.set_args(opts) album = self.config['album'].get(bool) checksum = self.config['checksum'].get(str) - copy = self.config['copy'].get(str) + copy = bytestring_path(self.config['copy'].as_str()) count = self.config['count'].get(bool) delete = self.config['delete'].get(bool) fmt = self.config['format'].get(str) full = self.config['full'].get(bool) keys = self.config['keys'].as_str_seq() merge = self.config['merge'].get(bool) - move = self.config['move'].get(str) + move = bytestring_path(self.config['move'].as_str()) path = self.config['path'].get(bool) tiebreak = self.config['tiebreak'].get(dict) strict = self.config['strict'].get(bool) diff --git a/docs/changelog.rst b/docs/changelog.rst index c3f950d2d..f7315e8c1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -52,6 +52,8 @@ Fixes: personal access token. :bug:`2447` * Fix Python 3 compatibility when extracting rar archives in the importer. Thanks to :user:`Lompik`. :bug:`2443` :bug:`2448` +* :doc:`/plugins/duplicates`: Fix Python 3 compatibility when using the + ``copy`` and ``move`` options. :bug:`2444` 1.4.3 (January 9, 2017) From b1ee9716bfb11a2999e4280715c6d4a0abdf7d71 Mon Sep 17 00:00:00 2001 From: rachmadaniHaryono Date: Fri, 24 Feb 2017 10:18:56 +0800 Subject: [PATCH 12/42] chg: dev: add main module. --- beets/__main__.py | 6 ++++++ beets/ui/__init__.py | 10 ++++++++++ 2 files changed, 16 insertions(+) create mode 100644 beets/__main__.py diff --git a/beets/__main__.py b/beets/__main__.py new file mode 100644 index 000000000..8cb407ae6 --- /dev/null +++ b/beets/__main__.py @@ -0,0 +1,6 @@ +"""main module.""" +import sys +from .ui import main + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index ae30a9c60..907687588 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -946,6 +946,16 @@ class SubcommandsOptionParser(CommonOptionsParser): self.subcommands = [] + def get_prog_name(self): + """Get program name. + + Returns: + Program name. + """ + prog_name = super(SubcommandsOptionParser, self).get_prog_name() + prog_name = 'beets' if prog_name == '__main__.py' else prog_name + return prog_name + def add_subcommand(self, *cmds): """Adds a Subcommand object to the parser's list of commands. """ From 87311d69f19c2fb391d7d6ab7085753d8afb101d Mon Sep 17 00:00:00 2001 From: rachmadaniHaryono Date: Fri, 24 Feb 2017 13:47:22 +0800 Subject: [PATCH 13/42] fix: dev: fix c101 from flake8. --- beets/__main__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/beets/__main__.py b/beets/__main__.py index 8cb407ae6..7b5fc798f 100644 --- a/beets/__main__.py +++ b/beets/__main__.py @@ -1,4 +1,5 @@ """main module.""" +# -*- coding: utf-8 -*- import sys from .ui import main From 2dff0254190e0f6d9361b25b96d7c5662b1d4f66 Mon Sep 17 00:00:00 2001 From: rachmadaniHaryono Date: Sat, 25 Feb 2017 03:46:26 +0800 Subject: [PATCH 14/42] chg: dev: let program decide the name. --- beets/ui/__init__.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 907687588..ae30a9c60 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -946,16 +946,6 @@ class SubcommandsOptionParser(CommonOptionsParser): self.subcommands = [] - def get_prog_name(self): - """Get program name. - - Returns: - Program name. - """ - prog_name = super(SubcommandsOptionParser, self).get_prog_name() - prog_name = 'beets' if prog_name == '__main__.py' else prog_name - return prog_name - def add_subcommand(self, *cmds): """Adds a Subcommand object to the parser's list of commands. """ From 8fa50a41cda9dd8a460182d262090059a7de1665 Mon Sep 17 00:00:00 2001 From: rachmadaniHaryono Date: Sat, 25 Feb 2017 12:13:47 +0800 Subject: [PATCH 15/42] chg: dev: add doc and license. --- beets/__main__.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/beets/__main__.py b/beets/__main__.py index 7b5fc798f..5f10c5b9b 100644 --- a/beets/__main__.py +++ b/beets/__main__.py @@ -1,5 +1,31 @@ -"""main module.""" # -*- coding: utf-8 -*- +"""main module. + +This module will be executed when beets module is run with `-m`. + +Example : `python -m beets` + +Related links about __main__.py: + +* python3 docs entry: https://docs.python.org/3/library/__main__.html +* related SO: http://stackoverflow.com/q/4042905 +""" +# This file is part of beets. +# Copyright 2017, 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. + +from __future__ import division, absolute_import, print_function + import sys from .ui import main From 0fe2279129787ac5a369b0b6e402f0283e915fe2 Mon Sep 17 00:00:00 2001 From: rachmadaniHaryono Date: Sat, 25 Feb 2017 12:14:53 +0800 Subject: [PATCH 16/42] chg: docs: add changelog entry. --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index f7315e8c1..f9051dd73 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -31,6 +31,7 @@ New features: * A new :ref:`hardlink` config option instructs the importer to create hard links on filesystems that support them. Thanks to :user:`jacobwgillespie`. :bug:`2445` +* Added support to run program from module, e.g. `python -m beets`. Fixes: From 35e2ecf3dd64f2fc8a7fe7455e4b2207434d0994 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 25 Feb 2017 13:37:44 -0500 Subject: [PATCH 17/42] Fix order of header comment vs. docstring (#2453) --- beets/__main__.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/beets/__main__.py b/beets/__main__.py index 5f10c5b9b..608cc0bd0 100644 --- a/beets/__main__.py +++ b/beets/__main__.py @@ -1,15 +1,4 @@ # -*- coding: utf-8 -*- -"""main module. - -This module will be executed when beets module is run with `-m`. - -Example : `python -m beets` - -Related links about __main__.py: - -* python3 docs entry: https://docs.python.org/3/library/__main__.html -* related SO: http://stackoverflow.com/q/4042905 -""" # This file is part of beets. # Copyright 2017, Adrian Sampson. # @@ -24,6 +13,18 @@ Related links about __main__.py: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. +"""main module. + +This module will be executed when beets module is run with `-m`. + +Example : `python -m beets` + +Related links about __main__.py: + +* python3 docs entry: https://docs.python.org/3/library/__main__.html +* related SO: http://stackoverflow.com/q/4042905 +""" + from __future__ import division, absolute_import, print_function import sys From a8d47f2c309c2fe97a162234a371308e332a2c92 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 25 Feb 2017 13:39:14 -0500 Subject: [PATCH 18/42] Simpler __main__ docstring (#2453) --- beets/__main__.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/beets/__main__.py b/beets/__main__.py index 608cc0bd0..8010ca0dd 100644 --- a/beets/__main__.py +++ b/beets/__main__.py @@ -13,16 +13,8 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -"""main module. - -This module will be executed when beets module is run with `-m`. - -Example : `python -m beets` - -Related links about __main__.py: - -* python3 docs entry: https://docs.python.org/3/library/__main__.html -* related SO: http://stackoverflow.com/q/4042905 +"""The __main__ module lets you run the beets CLI interface by typing +`python -m beets`. """ from __future__ import division, absolute_import, print_function From 1ee53d4e76a55914ddf59ddeb3fb48dd3241afee Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 25 Feb 2017 13:40:15 -0500 Subject: [PATCH 19/42] Fix up changelog for #2453 --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f9051dd73..a0ae8d43b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -31,7 +31,7 @@ New features: * A new :ref:`hardlink` config option instructs the importer to create hard links on filesystems that support them. Thanks to :user:`jacobwgillespie`. :bug:`2445` -* Added support to run program from module, e.g. `python -m beets`. +* You can now run beets by typing `python -m beets`. :bug:`2453` Fixes: From 1305c9407f7ad7beaf6d72a46756cf556ea838ec Mon Sep 17 00:00:00 2001 From: Teh Awesomer Date: Sat, 25 Feb 2017 12:01:34 -0800 Subject: [PATCH 20/42] mbsubmit plugin : numeric sort in print_tracks (for >=10 track releases) --- beetsplug/mbsubmit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/mbsubmit.py b/beetsplug/mbsubmit.py index 58b357dd3..02bd5f697 100644 --- a/beetsplug/mbsubmit.py +++ b/beetsplug/mbsubmit.py @@ -56,5 +56,5 @@ class MBSubmitPlugin(BeetsPlugin): return [PromptChoice(u'p', u'Print tracks', self.print_tracks)] def print_tracks(self, session, task): - for i in task.items: + for i in sorted(task.items, key=lambda i: i.track): print_data(None, i, self.config['format'].as_str()) From 1c9d42da95e09b67dc496a328d81ba79e179f84d Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 25 Feb 2017 15:30:36 -0500 Subject: [PATCH 21/42] Changelog/thanks for #2457 --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index a0ae8d43b..60d60bc40 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -55,6 +55,8 @@ Fixes: Thanks to :user:`Lompik`. :bug:`2443` :bug:`2448` * :doc:`/plugins/duplicates`: Fix Python 3 compatibility when using the ``copy`` and ``move`` options. :bug:`2444` +* :doc:`/plugins/mbsubmit`: The tracks are now sorted. Thanks to + :user:`awesomer`. :bug:`2457` 1.4.3 (January 9, 2017) From d7a12dbe1cb2722496e6a7796a07100ef1b97804 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 27 Feb 2017 13:23:07 -0500 Subject: [PATCH 22/42] Update recommended Python version to 3.6 On the topic of #2460, which points this out for the Windows beets.reg extra. --- docs/guides/main.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index 7feacb6bf..e2e1665da 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -82,7 +82,7 @@ into this if you've installed Python yourself with `Homebrew`_ or otherwise.) If this happens, you can install beets for the current user only (sans ``sudo``) by typing ``pip install --user beets``. If you do that, you might want -to add ``~/Library/Python/2.7/bin`` to your ``$PATH``. +to add ``~/Library/Python/3.6/bin`` to your ``$PATH``. .. _System Integrity Protection: https://support.apple.com/en-us/HT204899 .. _Homebrew: http://brew.sh @@ -93,7 +93,7 @@ Installing on Windows Installing beets on Windows can be tricky. Following these steps might help you get it right: -1. If you don't have it, `install Python`_ (you want Python 2.7). +1. If you don't have it, `install Python`_ (you want Python 3.6). 2. If you haven't done so already, set your ``PATH`` environment variable to include Python and its scripts. To do so, you have to get the "Properties" From 53ccdad964ea7e1ed19db0e296074bc9fc03004b Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 28 Feb 2017 18:44:10 -0500 Subject: [PATCH 23/42] Update guide for installing Python on Windows As pointed out in #2461. I also notice that the installer now has a checkbox to extend the PATH, so I'm recommending that. --- docs/guides/main.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index e2e1665da..b4e62f472 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -93,14 +93,17 @@ Installing on Windows Installing beets on Windows can be tricky. Following these steps might help you get it right: -1. If you don't have it, `install Python`_ (you want Python 3.6). +1. If you don't have it, `install Python`_ (you want Python 3.6). On the last + screen, the installer gives you the option to "add Python to PATH." Check + this box. If you do that, you can skip the next step. 2. If you haven't done so already, set your ``PATH`` environment variable to include Python and its scripts. To do so, you have to get the "Properties" window for "My Computer", then choose the "Advanced" tab, then hit the "Environment Variables" button, and then look for the ``PATH`` variable in the table. Add the following to the end of the variable's value: - ``;C:\Python27;C:\Python27\Scripts``. + ``;C:\Python36;C:\Python36\Scripts``. You may need to adjust these paths to + point to your Python installation. 3. Next, `install pip`_ (if you don't have it already) by downloading and running the `get-pip.py`_ script. From c420f5917334f937959ba713959e1395e8008873 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 28 Feb 2017 18:46:16 -0500 Subject: [PATCH 24/42] Remove the "install pip" step Python versions 2.7.9+ and 3.4+ come with pip, so we no longer need to instruct people to install it. See #2461. --- docs/guides/main.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index b4e62f472..c90bfc98f 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -105,12 +105,9 @@ get it right: ``;C:\Python36;C:\Python36\Scripts``. You may need to adjust these paths to point to your Python installation. -3. Next, `install pip`_ (if you don't have it already) by downloading and - running the `get-pip.py`_ script. +3. Now install beets by running: ``pip install beets`` -4. Now install beets by running: ``pip install beets`` - -5. You're all set! Type ``beet`` at the command prompt to make sure everything's +4. You're all set! Type ``beet`` at the command prompt to make sure everything's in order. Windows users may also want to install a context menu item for importing files From 55f9b27428961e42a0e195f5d3a9dfbea0b79ed3 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 28 Feb 2017 18:49:52 -0500 Subject: [PATCH 25/42] More admonition to check the beets.reg paths See #2461. --- docs/guides/main.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index c90bfc98f..ec23e8a8f 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -111,10 +111,10 @@ get it right: in order. Windows users may also want to install a context menu item for importing files -into beets. Just download and open `beets.reg`_ to add the necessary keys to the -registry. You can then right-click a directory and choose "Import with beets". -If Python is in a nonstandard location on your system, you may have to edit the -command path manually. +into beets. Download the `beets.reg`_ file and open it in a text file to make +sure the paths to Python match your system. Then double-click the file add the +necessary keys to your registry. You can then right-click a directory and +choose "Import with beets". Because I don't use Windows myself, I may have missed something. If you have trouble or you have more detail to contribute here, please direct it to From f315a17bb21e4c8eb57f8de5fc5f47557d3ad99b Mon Sep 17 00:00:00 2001 From: Pauligrinder Date: Wed, 1 Mar 2017 10:39:40 +0200 Subject: [PATCH 26/42] Added the copyright header Also added config['kodi']['pwd'].redact = True as suggested. --- beetsplug/kodiupdate.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/beetsplug/kodiupdate.py b/beetsplug/kodiupdate.py index 31c978dd6..47ad76d7a 100644 --- a/beetsplug/kodiupdate.py +++ b/beetsplug/kodiupdate.py @@ -1,4 +1,17 @@ # -*- coding: utf-8 -*- +# This file is part of beets. +# Copyright 2017, Pauli Kettunen. +# +# 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. """Updates a Kodi library whenever the beets library is changed. This is based on the Plex Update plugin. @@ -39,6 +52,7 @@ class KodiUpdate(BeetsPlugin): u'user': u'kodi', u'pwd': u'kodi'}) + config['kodi']['pwd'].redact = True self.register_listener('database_change', self.listen_for_db_change) def listen_for_db_change(self, lib, model): From 659c17f8257767a8c2b00ff9100d9971a105d692 Mon Sep 17 00:00:00 2001 From: Pauligrinder Date: Wed, 1 Mar 2017 11:11:54 +0200 Subject: [PATCH 27/42] Code fixed according to flake8 --- beetsplug/kodiupdate.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/beetsplug/kodiupdate.py b/beetsplug/kodiupdate.py index 47ad76d7a..78f120d89 100644 --- a/beetsplug/kodiupdate.py +++ b/beetsplug/kodiupdate.py @@ -13,7 +13,8 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -"""Updates a Kodi library whenever the beets library is changed. This is based on the Plex Update plugin. +"""Updates a Kodi library whenever the beets library is changed. +This is based on the Plex Update plugin. Put something like the following in your config.yaml to configure: kodi: @@ -34,13 +35,22 @@ def update_kodi(host, port, user, password): """ url = "http://{0}:{1}/jsonrpc/".format(host, port) - # The kodi jsonrpc documentation states that Content-Type: application/json is mandatory + """Content-Type: application/json is mandatory + according to the kodi jsonrpc documentation""" + headers = {'Content-Type': 'application/json'} + # Create the payload. Id seems to be mandatory. - payload = {'jsonrpc': '2.0', 'method':'AudioLibrary.Scan', 'id':1} - r = requests.post(url, auth=(user, password), json=payload, headers=headers) + payload = {'jsonrpc': '2.0', 'method': 'AudioLibrary.Scan', 'id': 1} + r = requests.post( + url, + auth=(user, password), + json=payload, + headers=headers) + return r + class KodiUpdate(BeetsPlugin): def __init__(self): super(KodiUpdate, self).__init__() @@ -56,7 +66,7 @@ class KodiUpdate(BeetsPlugin): self.register_listener('database_change', self.listen_for_db_change) def listen_for_db_change(self, lib, model): - """Listens for beets db change and register the update for the end""" + """Listens for beets db change and register the update""" self.register_listener('cli_exit', self.update) def update(self, lib): @@ -75,4 +85,3 @@ class KodiUpdate(BeetsPlugin): except requests.exceptions.RequestException: self._log.warning(u'Update failed.') - From 877d4af3443113ef3d33a912a972864828a298d7 Mon Sep 17 00:00:00 2001 From: Pauli Kettunen Date: Wed, 1 Mar 2017 14:55:17 +0200 Subject: [PATCH 28/42] Added documentation for kodiupdate --- docs/plugins/kodiupdate.rst | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/plugins/kodiupdate.rst diff --git a/docs/plugins/kodiupdate.rst b/docs/plugins/kodiupdate.rst new file mode 100644 index 000000000..243e384f2 --- /dev/null +++ b/docs/plugins/kodiupdate.rst @@ -0,0 +1,44 @@ +KodiUpdate Plugin +================= + +``kodiupdate`` is a very simple plugin for beets that lets you automatically +update `Kodi`_'s music library whenever you change your beets library. + +To use ``kodiupdate`` plugin, enable it in your configuration +(see :ref:`using-plugins`). +Then, you'll probably want to configure the specifics of your Kodi host. +You can do that using a ``kodi:`` section in your ``config.yaml``, +which looks like this:: + + kodi: + host: localhost + port: 8080 + user: kodi + pwd: kodi + +To use the ``kodiupdate`` plugin you need to install the `requests`_ library with: + + pip install requests + +You'll also need to enable jsonrpc in Kodi in order the use the plugin. +(System/Settings/Network/Services > Allow control of Kodi via HTTP) + +With that all in place, you'll see beets send the "update" command to your Kodi +host every time you change your beets library. + +.. _Kodi: http://kodi.tv/ +.. _requests: http://docs.python-requests.org/en/latest/ + +Configuration +------------- + +The available options under the ``kodi:`` section are: + +- **host**: The Kodi host name. + Default: ``localhost`` +- **port**: The Kodi host port. + Default: 8080 +- **user**: The Kodi host user. + Default: ``kodi`` +- **pwd**: The Kodi host password. + Default: ``kodi`` From c3c9c50b6ac6967c29773e0c1c2fdfab7f9c47e7 Mon Sep 17 00:00:00 2001 From: Mayuresh Kadu Date: Wed, 1 Mar 2017 13:06:47 +0000 Subject: [PATCH 29/42] Updated main.rst - Updates to seeing your music Modified "Seeing your Music" section to add explanation of the ``-f`` param of the list command. I strongly believe that first time users would very much like to start by overriding the default format of displaying results. --- docs/guides/main.rst | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index e2e1665da..d221ff810 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -230,11 +230,14 @@ songs. Thus:: The Magnetic Fields - Distortion - Three-Way The Magnetic Fields - Distortion - California Girls The Magnetic Fields - Distortion - Old Fools + $ beet ls hissing gronlandic of Montreal - Hissing Fauna, Are You the Destroyer? - Gronlandic Edit + $ beet ls bird The Knife - The Knife - Bird The Mae Shi - Terrorbird - Revelation Six + $ beet ls album:bird The Mae Shi - Terrorbird - Revelation Six @@ -245,16 +248,33 @@ put the field before the term, separated by a : character. So ``album:bird`` only looks for ``bird`` in the "album" field of your songs. (Need to know more? :doc:`/reference/query/` will answer all your questions.) -The ``beet list`` command has another useful option worth mentioning, ``-a``, -which searches for albums instead of songs:: +The ``beet list`` command has couple of other useful options worth mentioning. + +``-a``, which searches for albums instead of songs:: $ beet ls -a forever Bon Iver - For Emma, Forever Ago Freezepop - Freezepop Forever +``-f``, which lets you specify what gets displayed in the results of a search:: + + $ beet ls -a forever -f "[$format] $album ($year) - $artist - $title" + [MP3] For Emma, Forever Ago (2009) - Bon Iver - Flume + [AAC] Freezepop Forever (2011) - Freezepop - Harebrained Scheme + + As you can see, Beets has replaced the fields specified by the ``$`` prefix + (e.g. $format, $year) with values for each item in the results. A full + list of fields available for use can be found by running ``beet fields``. If + you'd like beet to use this format as default (without having to use ``-f``) + simply add it to your config file like this:: + + format_item: "[$format] $album ($year) - $artist - $title" + + And yes, the enclosing double-quotes are necessary. + So handy! -Beets also has a ``stats`` command, just in case you want to see how much music +And finally, Beets also has a ``stats`` command, just in case you want to see how much music you have:: $ beet stats From d22a2570081d5cbee9daccb3060b93e5b83d1390 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Wed, 1 Mar 2017 20:22:30 -0500 Subject: [PATCH 30/42] Main guide: clarify meaning of plain keyword query Fixes #2463. --- docs/guides/main.rst | 4 +++- docs/reference/query.rst | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index ec23e8a8f..4b5381a3a 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -238,7 +238,9 @@ songs. Thus:: $ beet ls album:bird The Mae Shi - Terrorbird - Revelation Six -As you can see, search terms by default search all attributes of songs. (They're +By default, a search term will match any of a handful of :ref:`common +attributes ` of songs. +(They're also implicitly joined by ANDs: a track must match *all* criteria in order to match the query.) To narrow a search term to a particular metadata field, just put the field before the term, separated by a : character. So ``album:bird`` diff --git a/docs/reference/query.rst b/docs/reference/query.rst index 2f3366d4c..b4789aa10 100644 --- a/docs/reference/query.rst +++ b/docs/reference/query.rst @@ -6,6 +6,8 @@ searches that select tracks and albums from your library. This page explains the query string syntax, which is meant to vaguely resemble the syntax used by Web search engines. +.. _keywordquery: + Keyword ------- From 212ece8b8b24b8c22418ab45fd2576e5a9af65e8 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 2 Mar 2017 10:35:29 -0500 Subject: [PATCH 31/42] Docs: Windows Python installer checkbox location See #2462. --- docs/guides/main.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index 4b5381a3a..e0e06099c 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -93,9 +93,9 @@ Installing on Windows Installing beets on Windows can be tricky. Following these steps might help you get it right: -1. If you don't have it, `install Python`_ (you want Python 3.6). On the last - screen, the installer gives you the option to "add Python to PATH." Check - this box. If you do that, you can skip the next step. +1. If you don't have it, `install Python`_ (you want Python 3.6). The + installer should give you the option to "add Python to PATH." Check this + box. If you do that, you can skip the next step. 2. If you haven't done so already, set your ``PATH`` environment variable to include Python and its scripts. To do so, you have to get the "Properties" From 697c7c0b1ff3e4b468a70c7e687e1e0855722a2e Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 2 Mar 2017 10:37:26 -0500 Subject: [PATCH 32/42] Docs: explicitly say what ~ means Again, see #2462. --- docs/guides/main.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index e0e06099c..923f3e806 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -142,8 +142,8 @@ place to start:: Change that first path to a directory where you'd like to keep your music. Then, for ``library``, choose a good place to keep a database file that keeps an index of your music. (The config's format is `YAML`_. You'll want to configure your -text editor to use spaces, not real tabs, for indentation.) - +text editor to use spaces, not real tabs, for indentation. Also, ``~`` means +your home directory in these paths, even on Windows.) The default configuration assumes you want to start a new organized music folder (that ``directory`` above) and that you'll *copy* cleaned-up music into that From a0cbba961f79728a421088b41a0915a600f3c8c3 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 2 Mar 2017 10:45:09 -0500 Subject: [PATCH 33/42] Add the Kodi docs to the TOC tree --- docs/plugins/index.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index 0e851d7da..eaeec02aa 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -66,6 +66,7 @@ like this:: inline ipfs keyfinder + kodiupdate lastgenre lastimport lyrics @@ -148,6 +149,8 @@ Interoperability * :doc:`embyupdate`: Automatically notifies `Emby`_ whenever the beets library changes. * :doc:`importfeeds`: Keep track of imported files via ``.m3u`` playlist file(s) or symlinks. * :doc:`ipfs`: Import libraries from friends and get albums from them via ipfs. +* :doc:`kodiupdate`: Automatically notifies `Kodi`_ whenever the beets library + changes. * :doc:`mpdupdate`: Automatically notifies `MPD`_ whenever the beets library changes. * :doc:`play`: Play beets queries in your music player. @@ -160,6 +163,7 @@ Interoperability .. _Emby: http://emby.media .. _Plex: http://plex.tv +.. _Kodi: http://kodi.tv Miscellaneous ------------- From 791f60b49065dc450e901f62c21a98fb843e7957 Mon Sep 17 00:00:00 2001 From: Mayuresh Kadu Date: Fri, 3 Mar 2017 13:06:09 +0000 Subject: [PATCH 34/42] further updates to Main.rst/ "Seeing your music" Revisions to the text explaining "-f" switch, as discussed in PR #2464 of the parent. --- docs/guides/main.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index d221ff810..fff4c6e82 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -264,13 +264,7 @@ The ``beet list`` command has couple of other useful options worth mentioning. As you can see, Beets has replaced the fields specified by the ``$`` prefix (e.g. $format, $year) with values for each item in the results. A full - list of fields available for use can be found by running ``beet fields``. If - you'd like beet to use this format as default (without having to use ``-f``) - simply add it to your config file like this:: - - format_item: "[$format] $album ($year) - $artist - $title" - - And yes, the enclosing double-quotes are necessary. + list of fields available for use can be found by running ``beet fields``. So handy! From 1fbb557c1c7126c8afac95f500dcc6454853f2ee Mon Sep 17 00:00:00 2001 From: Mayuresh Kadu Date: Fri, 3 Mar 2017 13:11:23 +0000 Subject: [PATCH 35/42] Further updates to main.rst/ "Seeing your music" Un-indented text explaining "-f" switch. --- docs/guides/main.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index fff4c6e82..36ff43ff3 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -262,9 +262,9 @@ The ``beet list`` command has couple of other useful options worth mentioning. [MP3] For Emma, Forever Ago (2009) - Bon Iver - Flume [AAC] Freezepop Forever (2011) - Freezepop - Harebrained Scheme - As you can see, Beets has replaced the fields specified by the ``$`` prefix - (e.g. $format, $year) with values for each item in the results. A full - list of fields available for use can be found by running ``beet fields``. +As you can see, Beets has replaced the fields specified by the ``$`` prefix (e.g. +$format, $year) with values for each item in the results. A full list of fields +available for use can be found by running ``beet fields``. So handy! From 9e755cf7fe64fce6c978ba80f05cd85dbb97165d Mon Sep 17 00:00:00 2001 From: Mayuresh Kadu Date: Fri, 3 Mar 2017 13:14:24 +0000 Subject: [PATCH 36/42] Update main.rst/ Seeing your music Undid adding extra lines to the output. As @sampsyo has rightly pointed out - these would not have appeared in the output. --- docs/guides/main.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index 36ff43ff3..57983e222 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -230,14 +230,11 @@ songs. Thus:: The Magnetic Fields - Distortion - Three-Way The Magnetic Fields - Distortion - California Girls The Magnetic Fields - Distortion - Old Fools - $ beet ls hissing gronlandic of Montreal - Hissing Fauna, Are You the Destroyer? - Gronlandic Edit - $ beet ls bird The Knife - The Knife - Bird The Mae Shi - Terrorbird - Revelation Six - $ beet ls album:bird The Mae Shi - Terrorbird - Revelation Six From 4211050e2cf835272de6ab7e6a8f5d744f888fae Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 3 Mar 2017 10:02:57 -0600 Subject: [PATCH 37/42] Docs refinements for Kodi plugin #2411 --- docs/plugins/kodiupdate.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/plugins/kodiupdate.rst b/docs/plugins/kodiupdate.rst index 243e384f2..a1ec04775 100644 --- a/docs/plugins/kodiupdate.rst +++ b/docs/plugins/kodiupdate.rst @@ -1,12 +1,12 @@ KodiUpdate Plugin ================= -``kodiupdate`` is a very simple plugin for beets that lets you automatically -update `Kodi`_'s music library whenever you change your beets library. +The ``kodiupdate`` plugin lets you automatically update `Kodi`_'s music +library whenever you change your beets library. To use ``kodiupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). -Then, you'll probably want to configure the specifics of your Kodi host. +Then, you'll want to configure the specifics of your Kodi host. You can do that using a ``kodi:`` section in your ``config.yaml``, which looks like this:: @@ -16,12 +16,12 @@ which looks like this:: user: kodi pwd: kodi -To use the ``kodiupdate`` plugin you need to install the `requests`_ library with: +To use the ``kodiupdate`` plugin you need to install the `requests`_ library with:: pip install requests -You'll also need to enable jsonrpc in Kodi in order the use the plugin. -(System/Settings/Network/Services > Allow control of Kodi via HTTP) +You'll also need to enable JSON-RPC in Kodi in order the use the plugin. +In Kodi's interface, navigate to System/Settings/Network/Services and choose "Allow control of Kodi via HTTP." With that all in place, you'll see beets send the "update" command to your Kodi host every time you change your beets library. From 38d2aeaed9d0bc30ad103efc7b045c5827f7aa9f Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 3 Mar 2017 10:04:46 -0600 Subject: [PATCH 38/42] Changelog for Kodi plugin (#2411) --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 60d60bc40..2ceed486d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,8 @@ New features: links on filesystems that support them. Thanks to :user:`jacobwgillespie`. :bug:`2445` * You can now run beets by typing `python -m beets`. :bug:`2453` +* A new :doc:`/plugins/kodiupdate` lets you keep your Kodi library in sync + with beets. Thanks to :user:`Pauligrinder`. :bug:`2411` Fixes: From a8c46d8b32724d23b6abcc30730f6d54a2238e35 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 3 Mar 2017 10:17:49 -0600 Subject: [PATCH 39/42] Brevity/clarity improvements for #2464 --- docs/guides/main.rst | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/guides/main.rst b/docs/guides/main.rst index c230b662a..f0b3635c2 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -247,27 +247,23 @@ put the field before the term, separated by a : character. So ``album:bird`` only looks for ``bird`` in the "album" field of your songs. (Need to know more? :doc:`/reference/query/` will answer all your questions.) -The ``beet list`` command has couple of other useful options worth mentioning. - -``-a``, which searches for albums instead of songs:: +The ``beet list`` command also has an ``-a`` option, which searches for albums instead of songs:: $ beet ls -a forever Bon Iver - For Emma, Forever Ago Freezepop - Freezepop Forever -``-f``, which lets you specify what gets displayed in the results of a search:: +There's also an ``-f`` option (for *format*) that lets you specify what gets displayed in the results of a search:: $ beet ls -a forever -f "[$format] $album ($year) - $artist - $title" [MP3] For Emma, Forever Ago (2009) - Bon Iver - Flume [AAC] Freezepop Forever (2011) - Freezepop - Harebrained Scheme - -As you can see, Beets has replaced the fields specified by the ``$`` prefix (e.g. -$format, $year) with values for each item in the results. A full list of fields -available for use can be found by running ``beet fields``. - -So handy! -And finally, Beets also has a ``stats`` command, just in case you want to see how much music +In the format option, field references like `$format` and `$year` are filled +in with data from each result. You can see a full list of available fields by +running ``beet fields``. + +Beets also has a ``stats`` command, just in case you want to see how much music you have:: $ beet stats From d356356111977c06e4227011aed919ca4ab2df74 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 3 Mar 2017 11:59:50 -0600 Subject: [PATCH 40/42] Fix #2466: GIO returns bytes, so decode them --- beetsplug/thumbnails.py | 8 +++++++- docs/changelog.rst | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/beetsplug/thumbnails.py b/beetsplug/thumbnails.py index 1ea90f01e..838206156 100644 --- a/beetsplug/thumbnails.py +++ b/beetsplug/thumbnails.py @@ -289,4 +289,10 @@ class GioURI(URIGetter): raise finally: self.libgio.g_free(uri_ptr) - return uri + + try: + return uri.decode(util._fsencoding()) + except UnicodeDecodeError: + raise RuntimeError( + "Could not decode filename from GIO: {!r}".format(uri) + ) diff --git a/docs/changelog.rst b/docs/changelog.rst index 2ceed486d..7e86755fb 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -59,6 +59,8 @@ Fixes: ``copy`` and ``move`` options. :bug:`2444` * :doc:`/plugins/mbsubmit`: The tracks are now sorted. Thanks to :user:`awesomer`. :bug:`2457` +* :doc:`/plugins/thumbnails`: Fix a string-related crash on Python 3. + :bug:`2466` 1.4.3 (January 9, 2017) From 17ad3e83dbe20126ff0048c29e1c1dd245845645 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 3 Mar 2017 12:10:26 -0600 Subject: [PATCH 41/42] Test updates for #2466 fix --- test/test_thumbnails.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_thumbnails.py b/test/test_thumbnails.py index d287c073a..dc03f06f7 100644 --- a/test/test_thumbnails.py +++ b/test/test_thumbnails.py @@ -276,12 +276,12 @@ class ThumbnailsTest(unittest.TestCase, TestHelper): if not gio.available: self.skipTest(u"GIO library not found") - self.assertEqual(gio.uri(u"/foo"), b"file:///") # silent fail - self.assertEqual(gio.uri(b"/foo"), b"file:///foo") - self.assertEqual(gio.uri(b"/foo!"), b"file:///foo!") + self.assertEqual(gio.uri(u"/foo"), u"file:///") # silent fail + self.assertEqual(gio.uri(b"/foo"), u"file:///foo") + self.assertEqual(gio.uri(b"/foo!"), u"file:///foo!") self.assertEqual( gio.uri(b'/music/\xec\x8b\xb8\xec\x9d\xb4'), - b'file:///music/%EC%8B%B8%EC%9D%B4') + u'file:///music/%EC%8B%B8%EC%9D%B4') def suite(): From ad4cd7a447e5ff8504481e9e7259ae02c39dfb3b Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 6 Mar 2017 22:58:00 -0500 Subject: [PATCH 42/42] Fix #2469: Beatport track limit It looks like the API uses pagination, and the default page size is 10. An easy fix is to just request lots of tracks per page (here, 100). A nicer thing to do in the future would be to actually traverse multiple pages. --- beetsplug/beatport.py | 3 ++- docs/changelog.rst | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/beetsplug/beatport.py b/beetsplug/beatport.py index c62abf7ab..8a73efa16 100644 --- a/beetsplug/beatport.py +++ b/beetsplug/beatport.py @@ -161,7 +161,8 @@ class BeatportClient(object): :returns: Tracks in the matching release :rtype: list of :py:class:`BeatportTrack` """ - response = self._get('/catalog/3/tracks', releaseId=beatport_id) + response = self._get('/catalog/3/tracks', releaseId=beatport_id, + perPage=100) return [BeatportTrack(t) for t in response] def get_track(self, beatport_id): diff --git a/docs/changelog.rst b/docs/changelog.rst index 7e86755fb..9ad8b3b4d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -61,6 +61,8 @@ Fixes: :user:`awesomer`. :bug:`2457` * :doc:`/plugins/thumbnails`: Fix a string-related crash on Python 3. :bug:`2466` +* :doc:`/plugins/beatport`: More than just 10 songs are now fetched per album. + :bug:`2469` 1.4.3 (January 9, 2017)