From 764fcc6b4c82aee67efe900546241ff1e41b0155 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Tue, 8 Sep 2015 12:45:19 +0100 Subject: [PATCH 1/9] Add `library_name` configuration property --- beetsplug/plexupdate.py | 14 ++++++++------ docs/plugins/plexupdate.rst | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/beetsplug/plexupdate.py b/beetsplug/plexupdate.py index 02ed2324c..340bcdf4d 100644 --- a/beetsplug/plexupdate.py +++ b/beetsplug/plexupdate.py @@ -18,7 +18,7 @@ from beets import config from beets.plugins import BeetsPlugin -def get_music_section(host, port, token): +def get_music_section(host, port, token, library_name): """Getting the section key for the music library in Plex. """ api_endpoint = append_token('library/sections', token) @@ -30,15 +30,15 @@ def get_music_section(host, port, token): # Parse xml tree and extract music section key. tree = ET.fromstring(r.text) for child in tree.findall('Directory'): - if child.get('title') == 'Music': + if child.get('title') == library_name: return child.get('key') -def update_plex(host, port, token): +def update_plex(host, port, token, library_name): """Sends request to the Plex api to start a library refresh. """ # Getting section key and build url. - section_key = get_music_section(host, port, token) + section_key = get_music_section(host, port, token, library_name) api_endpoint = 'library/sections/{0}/refresh'.format(section_key) api_endpoint = append_token(api_endpoint, token) url = urljoin('http://{0}:{1}'.format(host, port), api_endpoint) @@ -64,7 +64,8 @@ class PlexUpdate(BeetsPlugin): config['plex'].add({ u'host': u'localhost', u'port': 32400, - u'token': u''}) + u'token': u'', + u'library_name': u'Music'}) self.register_listener('database_change', self.listen_for_db_change) @@ -82,7 +83,8 @@ class PlexUpdate(BeetsPlugin): update_plex( config['plex']['host'].get(), config['plex']['port'].get(), - config['plex']['token'].get()) + config['plex']['token'].get(), + config['plex']['library_name'].get()) self._log.info('... started.') except requests.exceptions.RequestException: diff --git a/docs/plugins/plexupdate.rst b/docs/plugins/plexupdate.rst index f99e6de66..4ac047660 100644 --- a/docs/plugins/plexupdate.rst +++ b/docs/plugins/plexupdate.rst @@ -39,3 +39,5 @@ The available options under the ``plex:`` section are: Default: 32400. - **token**: The Plex Home token. Default: Empty. +- **library_name**: The name of the Plex library to update. + Default: ``Music`` From 2b37d8f7758e332d15b5d34055f721782ae2e388 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Tue, 8 Sep 2015 14:50:49 +0100 Subject: [PATCH 2/9] Add library_name parameter to plexupdate tests --- test/test_plexupdate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_plexupdate.py b/test/test_plexupdate.py index 9949be933..942d9185b 100644 --- a/test/test_plexupdate.py +++ b/test/test_plexupdate.py @@ -88,7 +88,8 @@ class PlexUpdateTest(unittest.TestCase, TestHelper): self.assertEqual(get_music_section( self.config['plex']['host'], self.config['plex']['port'], - self.config['plex']['token']), '2') + self.config['plex']['token'], + self.config['plex']['library_name'].get()), '2') @responses.activate def test_update_plex(self): @@ -100,7 +101,8 @@ class PlexUpdateTest(unittest.TestCase, TestHelper): self.assertEqual(update_plex( self.config['plex']['host'], self.config['plex']['port'], - self.config['plex']['token']).status_code, 200) + self.config['plex']['token'], + self.config['plex']['library_name'].get()).status_code, 200) def suite(): From 225ba282cdcf57b62a4659857f16e319118c961d Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 8 Sep 2015 12:07:03 -0700 Subject: [PATCH 3/9] Fix #1592 again: wrap title_gain in handler --- beetsplug/replaygain.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/beetsplug/replaygain.py b/beetsplug/replaygain.py index e621e9b21..8186b42f4 100644 --- a/beetsplug/replaygain.py +++ b/beetsplug/replaygain.py @@ -700,6 +700,23 @@ class AudioToolsBackend(Backend): """ return [self._compute_track_gain(item) for item in items] + def _title_gain(self, rg, audiofile): + """Get the gain result pair from PyAudioTools using the `ReplayGain` + instance `rg` for the given `audiofile`. + + Wraps `rg.title_gain(audiofile.to_pcm())` and throws a + `ReplayGainError` when the library fails. + """ + try: + # The method needs an audiotools.PCMReader instance that can + # be obtained from an audiofile instance. + return rg.title_gain(audiofile.to_pcm()) + except ValueError as exc: + # `audiotools.replaygain` can raise a `ValueError` if the sample + # rate is incorrect. + self._log.debug('error in rg.title_gain() call: {}', exc) + raise ReplayGainError('audiotools audio data error') + def _compute_track_gain(self, item): """Compute ReplayGain value for the requested item. @@ -707,17 +724,10 @@ class AudioToolsBackend(Backend): """ audiofile = self.open_audio_file(item) rg = self.init_replaygain(audiofile, item) - # Each call to title_gain on a replaygain object return peak and gain + + # Each call to title_gain on a ReplayGain object returns peak and gain # of the track. - # Note that the method needs an audiotools.PCMReader instance that can - # be obtained from an audiofile instance. - try: - rg_track_gain, rg_track_peak = rg.title_gain(audiofile.to_pcm()) - except ValueError as exc: - # `audiotools.replaygain` can raise a `ValueError` if the sample - # rate is incorrect. - self._log.debug('error in rg.title_gain() call: {}', exc) - raise ReplayGainError('audiotools audio data error') + rg_track_gain, rg_track_peak = rg._title_gain(rg, audiofile) self._log.debug(u'ReplayGain for track {0} - {1}: {2:.2f}, {3:.2f}', item.artist, item.title, rg_track_gain, rg_track_peak) @@ -740,7 +750,7 @@ class AudioToolsBackend(Backend): track_gains = [] for item in album.items(): audiofile = self.open_audio_file(item) - rg_track_gain, rg_track_peak = rg.title_gain(audiofile.to_pcm()) + rg_track_gain, rg_track_peak = self._title_gain(rg, audiofile) track_gains.append( Gain(gain=rg_track_gain, peak=rg_track_peak) ) From 40f9f6593eb5ba8bc44cb3c805f81ded79a1b0ec Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Wed, 9 Sep 2015 22:31:23 +0100 Subject: [PATCH 4/9] Changelog for #1595 --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index bb090a20e..dec5bc28a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -20,6 +20,8 @@ The new features: :bug:`1591` :bug:`733` * :doc:`/plugins/play`: You can now configure the number of tracks that trigger a "lots of music" warning. :bug:`1577` +* :doc:`/plugins/plexupdate`: A new ``library_name`` option allows you to select + which Plex library to update. :bug:`1572` :bug:`1595` Fixes: From 4a225ee291bea00366fa37ede1f1731bf1b4ada8 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Thu, 10 Sep 2015 05:07:14 +0100 Subject: [PATCH 5/9] Allow a custom music section name to be provided when generating a response --- test/test_plexupdate.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/test_plexupdate.py b/test/test_plexupdate.py index 942d9185b..1699890f8 100644 --- a/test/test_plexupdate.py +++ b/test/test_plexupdate.py @@ -8,9 +8,12 @@ import responses class PlexUpdateTest(unittest.TestCase, TestHelper): - def add_response_get_music_section(self): + def add_response_get_music_section(self, section_name = 'Music'): """Create response for mocking the get_music_section function. """ + + escaped_section_name = section_name.replace('"', '\\"') + body = ( '' '' ' Date: Thu, 10 Sep 2015 05:08:16 +0100 Subject: [PATCH 6/9] Add test for custom named music section (`library_name` property) (#1595) --- test/test_plexupdate.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_plexupdate.py b/test/test_plexupdate.py index 1699890f8..67796e3b2 100644 --- a/test/test_plexupdate.py +++ b/test/test_plexupdate.py @@ -94,6 +94,17 @@ class PlexUpdateTest(unittest.TestCase, TestHelper): self.config['plex']['token'], self.config['plex']['library_name'].get()), '2') + @responses.activate + def test_get_named_music_section(self): + # Adding response. + self.add_response_get_music_section('My Music Library') + + self.assertEqual(get_music_section( + self.config['plex']['host'], + self.config['plex']['port'], + self.config['plex']['token'], + 'My Music Library'), '2') + @responses.activate def test_update_plex(self): # Adding responses. From 622c5d1e0f06004ba2b39ba941118eb37385c5e5 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Thu, 10 Sep 2015 05:14:07 +0100 Subject: [PATCH 7/9] Fix unexpected spaces around keyword / parameter equals --- test/test_plexupdate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_plexupdate.py b/test/test_plexupdate.py index 67796e3b2..58388f728 100644 --- a/test/test_plexupdate.py +++ b/test/test_plexupdate.py @@ -8,7 +8,7 @@ import responses class PlexUpdateTest(unittest.TestCase, TestHelper): - def add_response_get_music_section(self, section_name = 'Music'): + def add_response_get_music_section(self, section_name='Music'): """Create response for mocking the get_music_section function. """ From 2f333968c50e09c514672b35a3daa298a27a3783 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Thu, 10 Sep 2015 22:18:13 +0100 Subject: [PATCH 8/9] Add test for removing art files (`remove_art_file` property) (#1591) --- test/test_embedart.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_embedart.py b/test/test_embedart.py index 055899a5f..5130643bb 100644 --- a/test/test_embedart.py +++ b/test/test_embedart.py @@ -82,6 +82,23 @@ class EmbedartCliTest(_common.TestCase, TestHelper): mediafile = MediaFile(syspath(item.path)) self.assertEqual(mediafile.images[0].data, self.image_data) + def test_embed_art_remove_art_file(self): + self._setup_data() + album = self.add_album_fixture() + + logging.getLogger('beets.embedart').setLevel(logging.DEBUG) + + handle, tmp_path = tempfile.mkstemp() + os.write(handle, self.image_data) + os.close(handle) + + album.artpath = tmp_path + album.store() + + config['embedart']['remove_art_file'] = True + self.run_command('embedart') + self.assertFalse(os.path.isfile(tmp_path)) + def test_art_file_missing(self): self.add_album_fixture() logging.getLogger('beets.embedart').setLevel(logging.DEBUG) From b1cef2606b8e568f1d9fec56b2c038d9dceee661 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Thu, 10 Sep 2015 22:48:47 +0100 Subject: [PATCH 9/9] Delete the artwork file if the test failed --- test/test_embedart.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_embedart.py b/test/test_embedart.py index 5130643bb..a4c88a429 100644 --- a/test/test_embedart.py +++ b/test/test_embedart.py @@ -97,7 +97,10 @@ class EmbedartCliTest(_common.TestCase, TestHelper): config['embedart']['remove_art_file'] = True self.run_command('embedart') - self.assertFalse(os.path.isfile(tmp_path)) + + if os.path.isfile(tmp_path): + os.remove(tmp_path) + self.fail('Artwork file {0} was not deleted'.format(tmp_path)) def test_art_file_missing(self): self.add_album_fixture()