From 0d68a126095bbc6969516f63d99c8a9e44399e55 Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Sun, 1 Jan 2017 04:36:48 -0500 Subject: [PATCH 01/11] Added alternate track field when importing from MusicBrains. Useful when importing multi-sided medias such as vinyls and cassettes. --- beets/autotag/__init__.py | 4 +++- beets/autotag/hooks.py | 3 ++- beets/autotag/mb.py | 5 +++-- beets/library.py | 7 ++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 3e79a4498c..eb3dae519f 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -34,7 +34,7 @@ def apply_item_metadata(item, track_info): """Set an item's metadata from its matched TrackInfo object. - """ + """ item.artist = track_info.artist item.artist_sort = track_info.artist_sort item.artist_credit = track_info.artist_credit @@ -157,3 +157,5 @@ def apply_metadata(album_info, mapping): item.composer = track_info.composer if track_info.arranger is not None: item.arranger = track_info.arranger + + item.alt_track_no = track_info.alt_track_no \ No newline at end of file diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index 40db6e8d3f..e64b425134 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -154,7 +154,7 @@ def __init__(self, title, track_id, artist=None, artist_id=None, length=None, index=None, medium=None, medium_index=None, medium_total=None, artist_sort=None, disctitle=None, artist_credit=None, data_source=None, data_url=None, - media=None, lyricist=None, composer=None, arranger=None): + media=None, lyricist=None, composer=None, arranger=None, alt_track_no=None): self.title = title self.track_id = track_id self.artist = artist @@ -173,6 +173,7 @@ def __init__(self, title, track_id, artist=None, artist_id=None, self.lyricist = lyricist self.composer = composer self.arranger = arranger + self.alt_track_no = alt_track_no # As above, work around a bug in python-musicbrainz-ngs. def decode(self, codec='utf-8'): diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index 55ecfc185d..aad342e981 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -252,8 +252,8 @@ def album_info(release): all_tracks = medium['track-list'] if 'pregap' in medium: all_tracks.insert(0, medium['pregap']) - - for track in all_tracks: + + for track in all_tracks: # Basic information from the recording. index += 1 ti = track_info( @@ -265,6 +265,7 @@ def album_info(release): ) ti.disctitle = disctitle ti.media = format + ti.alt_track_no = track['number'] # Prefer track data, where present, over recording data. if track.get('title'): diff --git a/beets/library.py b/beets/library.py index 32176b68d5..d9ffd38fdd 100644 --- a/beets/library.py +++ b/beets/library.py @@ -322,7 +322,7 @@ def _template_funcs(self): funcs.update(plugins.template_funcs()) return funcs - def store(self, fields=None): + def store(self, fields=None): super(LibModel, self).store(fields) plugins.send('database_change', lib=self._db, model=self) @@ -423,9 +423,10 @@ class Item(LibModel): 'month': types.PaddedInt(2), 'day': types.PaddedInt(2), 'track': types.PaddedInt(2), + 'alt_track_no': types.STRING, 'tracktotal': types.PaddedInt(2), 'disc': types.PaddedInt(2), - 'disctotal': types.PaddedInt(2), + 'disctotal': types.PaddedInt(2), 'lyrics': types.STRING, 'comments': types.STRING, 'bpm': types.INTEGER, @@ -456,7 +457,7 @@ class Item(LibModel): 'original_year': types.PaddedInt(4), 'original_month': types.PaddedInt(2), 'original_day': types.PaddedInt(2), - 'initial_key': MusicalKey(), + 'initial_key': MusicalKey(), 'length': DurationType(), 'bitrate': types.ScaledInt(1000, u'kbps'), From 76b3212e781bcaba85713e5d5c24751adfebb0d2 Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Sun, 1 Jan 2017 04:51:34 -0500 Subject: [PATCH 02/11] Added alternate track numbers for Discogs. --- beets/autotag/hooks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index e64b425134..a9a35e6352 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -154,7 +154,8 @@ def __init__(self, title, track_id, artist=None, artist_id=None, length=None, index=None, medium=None, medium_index=None, medium_total=None, artist_sort=None, disctitle=None, artist_credit=None, data_source=None, data_url=None, - media=None, lyricist=None, composer=None, arranger=None, alt_track_no=None): + media=None, lyricist=None, composer=None, arranger=None, + alt_track_no=None): self.title = title self.track_id = track_id self.artist = artist From 8a00791ecca90999b570f0d3f385d99f288413dd Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Sun, 1 Jan 2017 04:52:32 -0500 Subject: [PATCH 03/11] Oops. Forgot to actually stage the correct file. --- beetsplug/discogs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index cf10a2a36d..9053580242 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -314,7 +314,9 @@ def get_tracks(self, tracklist): # Only real tracks have `position`. Otherwise, it's an index track. if track['position']: index += 1 - tracks.append(self.get_track_info(track, index)) + ti = self.get_track_info(track, index) + ti.alt_track_no = track['position'] + tracks.append(ti) else: index_tracks[index + 1] = track['title'] From 3f67a27989d264fe96005b96eaf86e3750547f3d Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Tue, 10 Jan 2017 18:21:28 -0500 Subject: [PATCH 04/11] Fixed failing test because mocked data was missing property umber. --- test/test_importer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_importer.py b/test/test_importer.py index 500ca027d2..87724f8dac 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -1723,6 +1723,7 @@ def mocked_get_release_by_id(id_, includes=[], release_status=[], 'length': 59, }, 'position': 9, + 'number': 'A2' }], 'position': 5, }], From c58c49d77ff484965215f07975f9f410ad8b6777 Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Tue, 10 Jan 2017 18:39:01 -0500 Subject: [PATCH 05/11] Fixed trailing whitespace issue. Changed alternate track property name. --- beets/autotag/__init__.py | 6 +++--- beets/autotag/hooks.py | 7 ++++--- beets/autotag/mb.py | 6 +++--- beets/library.py | 8 ++++---- beetsplug/discogs.py | 6 +++--- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index eb3dae519f..7487477e5b 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -34,7 +34,7 @@ def apply_item_metadata(item, track_info): """Set an item's metadata from its matched TrackInfo object. - """ + """ item.artist = track_info.artist item.artist_sort = track_info.artist_sort item.artist_credit = track_info.artist_credit @@ -157,5 +157,5 @@ def apply_metadata(album_info, mapping): item.composer = track_info.composer if track_info.arranger is not None: item.arranger = track_info.arranger - - item.alt_track_no = track_info.alt_track_no \ No newline at end of file + + item.track_alt = track_info.track_alt \ No newline at end of file diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index a9a35e6352..3c403fcf42 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -145,6 +145,7 @@ class TrackInfo(object): - ``lyricist``: individual track lyricist name - ``composer``: individual track composer name - ``arranger`: individual track arranger name + - ``track_alt``: alternative track number (tape, vinyl, etc.) Only ``title`` and ``track_id`` are required. The rest of the fields may be None. The indices ``index``, ``medium``, and ``medium_index`` @@ -154,8 +155,8 @@ def __init__(self, title, track_id, artist=None, artist_id=None, length=None, index=None, medium=None, medium_index=None, medium_total=None, artist_sort=None, disctitle=None, artist_credit=None, data_source=None, data_url=None, - media=None, lyricist=None, composer=None, arranger=None, - alt_track_no=None): + media=None, lyricist=None, composer=None, arranger=None, + track_alt=None): self.title = title self.track_id = track_id self.artist = artist @@ -174,7 +175,7 @@ def __init__(self, title, track_id, artist=None, artist_id=None, self.lyricist = lyricist self.composer = composer self.arranger = arranger - self.alt_track_no = alt_track_no + self.track_alt = track_alt # As above, work around a bug in python-musicbrainz-ngs. def decode(self, codec='utf-8'): diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index fc3b1926c3..a0d4dc33af 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -256,8 +256,8 @@ def album_info(release): all_tracks = medium['track-list'] if 'pregap' in medium: all_tracks.insert(0, medium['pregap']) - - for track in all_tracks: + + for track in all_tracks: # Basic information from the recording. index += 1 ti = track_info( @@ -269,7 +269,7 @@ def album_info(release): ) ti.disctitle = disctitle ti.media = format - ti.alt_track_no = track['number'] + ti.track_alt = track['number'] # Prefer track data, where present, over recording data. if track.get('title'): diff --git a/beets/library.py b/beets/library.py index d9ffd38fdd..99a84cee61 100644 --- a/beets/library.py +++ b/beets/library.py @@ -322,7 +322,7 @@ def _template_funcs(self): funcs.update(plugins.template_funcs()) return funcs - def store(self, fields=None): + def store(self, fields=None): super(LibModel, self).store(fields) plugins.send('database_change', lib=self._db, model=self) @@ -423,10 +423,10 @@ class Item(LibModel): 'month': types.PaddedInt(2), 'day': types.PaddedInt(2), 'track': types.PaddedInt(2), - 'alt_track_no': types.STRING, + 'track_alt': types.STRING, 'tracktotal': types.PaddedInt(2), 'disc': types.PaddedInt(2), - 'disctotal': types.PaddedInt(2), + 'disctotal': types.PaddedInt(2), 'lyrics': types.STRING, 'comments': types.STRING, 'bpm': types.INTEGER, @@ -457,7 +457,7 @@ class Item(LibModel): 'original_year': types.PaddedInt(4), 'original_month': types.PaddedInt(2), 'original_day': types.PaddedInt(2), - 'initial_key': MusicalKey(), + 'initial_key': MusicalKey(), 'length': DurationType(), 'bitrate': types.ScaledInt(1000, u'kbps'), diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index 9053580242..3b3f5f201f 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -314,9 +314,9 @@ def get_tracks(self, tracklist): # Only real tracks have `position`. Otherwise, it's an index track. if track['position']: index += 1 - ti = self.get_track_info(track, index) - ti.alt_track_no = track['position'] - tracks.append(ti) + track_info = self.get_track_info(track, index) + track_info.track_alt = track['position'] + tracks.append(track_info) else: index_tracks[index + 1] = track['title'] From 3cd4f1c0910bd50bfaeb2e5aad38f22e6aad1a61 Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Tue, 10 Jan 2017 18:57:42 -0500 Subject: [PATCH 06/11] Fixed failing test where track number was missing from mocked data. --- test/test_mb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_mb.py b/test/test_mb.py index ecbcf3c59b..9e42263073 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -68,6 +68,7 @@ def _make_release(self, date_str='2009', tracks=None, track_length=None, track = { 'recording': recording, 'position': i + 1, + 'number': 'A1', } if track_length: # Track lengths are distinct from recording lengths. @@ -182,12 +183,12 @@ def test_parse_medium_numbers_two_mediums(self): second_track_list = [{ 'recording': tracks[1], 'position': '1', + 'number': 'A1', }] release['medium-list'].append({ 'position': '2', 'track-list': second_track_list, }) - d = mb.album_info(release) self.assertEqual(d.mediums, 2) t = d.tracks @@ -454,6 +455,7 @@ def test_match_album(self): 'length': 42, }, 'position': 9, + 'number': 'A1', }], 'position': 5, }], From bba5a7c7126178802d1e205cccba4abff3fb6bec Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Tue, 10 Jan 2017 19:08:18 -0500 Subject: [PATCH 07/11] Fixed (?) failing test where umber was rack_alt was missing during import. --- test/test_edit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_edit.py b/test/test_edit.py index 2900d092ad..0449f23331 100644 --- a/test/test_edit.py +++ b/test/test_edit.py @@ -276,7 +276,7 @@ class EditDuringImporterTest(TerminalImportSessionSetup, unittest.TestCase, ImportHelper, TestHelper, EditMixin): """TODO """ - IGNORED = ['added', 'album_id', 'id', 'mtime', 'path'] + IGNORED = ['added', 'album_id', 'id', 'mtime', 'path', 'track_alt'] def setUp(self): self.setup_beets() From 0dd763c5ef8e84351cd2a73d628a65fa4eb31638 Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Tue, 10 Jan 2017 19:19:09 -0500 Subject: [PATCH 08/11] Fixed flake8 warning W292 for Python 3.4 about missing newline at end of file. --- beets/autotag/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 7487477e5b..822bb60efc 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -158,4 +158,4 @@ def apply_metadata(album_info, mapping): if track_info.arranger is not None: item.arranger = track_info.arranger - item.track_alt = track_info.track_alt \ No newline at end of file + item.track_alt = track_info.track_alt From 5250ba80202408bb58c00a7157c0331ab0e556b6 Mon Sep 17 00:00:00 2001 From: Mike Cameron Date: Tue, 10 Jan 2017 19:40:23 -0500 Subject: [PATCH 09/11] Added changelog entry of new rack_alt path template value and updated changelog with description of change. --- docs/changelog.rst | 3 +++ docs/reference/pathformat.rst | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4e0d7405fc..a9210554a3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,9 @@ New features: * Added support for DSF files, once a future version of Mutagen is released that supports them. Thanks to :user:`docbobo`. :bug:`459` :bug:`2379` +* A new template path value ``track_alt`` let's you use the tracks actual + number rather than its position media. Useful when importing albums that + have multiple sides, such as tapes and vinyls. Fixes: diff --git a/docs/reference/pathformat.rst b/docs/reference/pathformat.rst index 72453a6e53..6b1fe50218 100644 --- a/docs/reference/pathformat.rst +++ b/docs/reference/pathformat.rst @@ -197,6 +197,7 @@ Ordinary metadata: * original_year, original_month, original_day: The release date of the original version of the album. * track +* track_alt * tracktotal * disc * disctotal From 703f47ae976ed4e95de4cb974d7785ab53b8cea5 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 10 Jan 2017 21:01:36 -0500 Subject: [PATCH 10/11] Use flexible attribute for track_alt No need for a built-in field for a simple string-type optional field like this. --- beets/library.py | 1 - docs/reference/pathformat.rst | 1 - test/test_edit.py | 2 +- test/test_mb.py | 1 + 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/beets/library.py b/beets/library.py index 99a84cee61..32176b68d5 100644 --- a/beets/library.py +++ b/beets/library.py @@ -423,7 +423,6 @@ class Item(LibModel): 'month': types.PaddedInt(2), 'day': types.PaddedInt(2), 'track': types.PaddedInt(2), - 'track_alt': types.STRING, 'tracktotal': types.PaddedInt(2), 'disc': types.PaddedInt(2), 'disctotal': types.PaddedInt(2), diff --git a/docs/reference/pathformat.rst b/docs/reference/pathformat.rst index 6b1fe50218..72453a6e53 100644 --- a/docs/reference/pathformat.rst +++ b/docs/reference/pathformat.rst @@ -197,7 +197,6 @@ Ordinary metadata: * original_year, original_month, original_day: The release date of the original version of the album. * track -* track_alt * tracktotal * disc * disctotal diff --git a/test/test_edit.py b/test/test_edit.py index 0449f23331..2900d092ad 100644 --- a/test/test_edit.py +++ b/test/test_edit.py @@ -276,7 +276,7 @@ class EditDuringImporterTest(TerminalImportSessionSetup, unittest.TestCase, ImportHelper, TestHelper, EditMixin): """TODO """ - IGNORED = ['added', 'album_id', 'id', 'mtime', 'path', 'track_alt'] + IGNORED = ['added', 'album_id', 'id', 'mtime', 'path'] def setUp(self): self.setup_beets() diff --git a/test/test_mb.py b/test/test_mb.py index 9e42263073..ca1bf2a1a0 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -189,6 +189,7 @@ def test_parse_medium_numbers_two_mediums(self): 'position': '2', 'track-list': second_track_list, }) + d = mb.album_info(release) self.assertEqual(d.mediums, 2) t = d.tracks From da86a410fe77f7e37aa5f3527569bc48abb1326a Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Tue, 10 Jan 2017 21:04:51 -0500 Subject: [PATCH 11/11] A little more detail in the changelog --- docs/changelog.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index a9210554a3..eaf8c7d5ab 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,9 +8,11 @@ New features: * Added support for DSF files, once a future version of Mutagen is released that supports them. Thanks to :user:`docbobo`. :bug:`459` :bug:`2379` -* A new template path value ``track_alt`` let's you use the tracks actual - number rather than its position media. Useful when importing albums that - have multiple sides, such as tapes and vinyls. +* The MusicBrainz backend and :doc:`/plugins/discogs` now both provide a new + attribute called ``track_alt`` that stores more nuanced, possibly + non-numeric track index data. For example, some vinyl or tape media will + report the side of the record using a letter instead of a number in that + field. :bug:`1831` :bug:`2363` Fixes: