diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1a95e7a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +### 0.1.1 (2021-09-09) + +* Fixed issue when attempting to replace a missing field. + +### 0.1 (2021-09-08) + +* Initial release. \ No newline at end of file diff --git a/beetsplug/__init__.py b/beetsplug/__init__.py index 0bfb5a6..3ad9513 100644 --- a/beetsplug/__init__.py +++ b/beetsplug/__init__.py @@ -1,2 +1,2 @@ from pkgutil import extend_path -__path__ = extend_path(__path__, __name__) \ No newline at end of file +__path__ = extend_path(__path__, __name__) diff --git a/beetsplug/importreplace.py b/beetsplug/importreplace.py index eb041d6..7fe766f 100644 --- a/beetsplug/importreplace.py +++ b/beetsplug/importreplace.py @@ -7,36 +7,40 @@ class ImportReplace(BeetsPlugin): - item_fields = set() - album_fields = set() - replacements = [] + _item_fields = set() + _album_fields = set() + _replacements = [] def __init__(self): super(ImportReplace, self).__init__() - self.item_fields = self.config['item_fields'].as_str_seq() - self.album_fields = self.config['album_fields'].as_str_seq() + self._item_fields = self.config['item_fields'].as_str_seq() + self._album_fields = self.config['album_fields'].as_str_seq() for pattern, repl in self.config['replace'].get(dict).items(): repl = repl or '' - self.replacements.append((re.compile(pattern), repl)) - self.register_listener('trackinfo_received', self.trackinfo_received) - self.register_listener('albuminfo_received', self.albuminfo_received) + self._replacements.append((re.compile(pattern), repl)) + self.register_listener('trackinfo_received', self._trackinfo_received) + self.register_listener('albuminfo_received', self._albuminfo_received) - def trackinfo_received(self, info: TrackInfo): - for field in self.item_fields: + def _trackinfo_received(self, info: TrackInfo): + for field in self._item_fields: if field in info: - replaced = self.replace_field(info.__getattr__(field)) - info.__setattr__(field, replaced) + value = info.__getattr__(field) + if value: + replaced = self._replace_field(value) + info.__setattr__(field, replaced) - def albuminfo_received(self, info: AlbumInfo): - for field in self.album_fields: + def _albuminfo_received(self, info: AlbumInfo): + for field in self._album_fields: if field in info: - replaced = self.replace_field(info.__getattr__(field)) - info.__setattr__(field, replaced) + value = info.__getattr__(field) + if value: + replaced = self._replace_field(value) + info.__setattr__(field, replaced) for track in info.tracks: - self.trackinfo_received(track) + self._trackinfo_received(track) - def replace_field(self, text: str) -> str: - return reduce(self.replace, self.replacements, text) + def _replace_field(self, text: str) -> str: + return reduce(self._replace, self._replacements, text) - def replace(self, text: str, replacement: (Pattern, str)) -> str: + def _replace(self, text: str, replacement: (Pattern, str)) -> str: return replacement[0].sub(repl=replacement[1], string=text) diff --git a/setup.py b/setup.py index d681ae6..352ae4a 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='beets-importreplace', - version='0.1', + version='0.1.1', description='beets plugin to perform replacements on import metadata', long_description=open('README.md').read(), author='Edgars Supe', diff --git a/tests/test_importreplace.py b/tests/test_importreplace.py new file mode 100644 index 0000000..6c61919 --- /dev/null +++ b/tests/test_importreplace.py @@ -0,0 +1,56 @@ +import unittest + +import beets as beets +from beets.autotag.hooks import AlbumInfo +from beets.autotag.hooks import TrackInfo +from beetsplug.importreplace import ImportReplace + + +class ImportReplaceTest(unittest.TestCase): + + def _create_track_info(self, title: str = None, artist: str = None, + artist_sort: str = None, artist_credit: str = None): + return TrackInfo(title=title, artist=artist, artist_sort=artist_sort, + artist_credit=artist_credit) + + def _create_album_info(self, tracks: [TrackInfo] = None, album: str = None, + artist: str = None, artist_sort: str = None, + artist_credit: str = None): + return AlbumInfo(tracks=tracks or [], album=album, artist=artist, + artist_sort=artist_sort, artist_credit=artist_credit) + + def _set_config(self, item_fields: [str], album_fields: [str], + replace: {str: str}): + beets.config['importreplace']['item_fields'] = item_fields + beets.config['importreplace']['album_fields'] = album_fields + beets.config['importreplace']['replace'] = replace + + def test_replaces_only_config_fields(self): + """Check if plugin replaces text in only the specified fields""" + self._set_config(item_fields=['title'], album_fields=['album'], + replace={'a': 'x'}) + tracks = [self._create_track_info(title='Fao', artist='Bar')] + album_info = self._create_album_info(tracks=tracks, album='albumTest', + artist='Bar') + subject = ImportReplace() + subject._albuminfo_received(album_info) + self.assertEqual(album_info.album, 'xlbumTest') + self.assertEqual(album_info.artist, 'Bar') + self.assertEqual(album_info.tracks[0].title, 'Fxo') + self.assertEqual(album_info.tracks[0].artist, 'Bar') + + def test_handles_empty_fields(self): + """Verify that plugin works when field marked for replacement + is absent""" + self._set_config(item_fields=['title', 'artist'], + album_fields=['album', 'artist'], + replace={'a': 'x'}) + tracks = [self._create_track_info(title='Fao', artist=None)] + album_info = self._create_album_info(tracks=tracks, album='albumTest', + artist=None) + subject = ImportReplace() + subject._albuminfo_received(album_info) + self.assertEqual(album_info.album, 'xlbumTest') + self.assertEqual(album_info.artist, None) + self.assertEqual(album_info.tracks[0].title, 'Fxo') + self.assertEqual(album_info.tracks[0].artist, None)