From 6e16800919d8981697b75cfcbcc98b4ce1a73e6e Mon Sep 17 00:00:00 2001 From: Kinuax Date: Wed, 8 May 2024 08:40:01 +0200 Subject: [PATCH] New approach --- rolabesti/controllers/config.py | 2 +- rolabesti/controllers/parser.py | 70 ++++++++++++++++++-------------- tests/controllers/test_parser.py | 32 ++++++++++++--- tests/utils.py | 1 - 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/rolabesti/controllers/config.py b/rolabesti/controllers/config.py index 0b7cede..44faf65 100644 --- a/rolabesti/controllers/config.py +++ b/rolabesti/controllers/config.py @@ -24,7 +24,7 @@ def __call__(self) -> None: del self.parameters["list_"] del self.parameters["reset"] - if all(map(lambda parameter: parameter is None, self.parameters.values())): + if all(parameter is None for parameter in self.parameters.values()): self.logger.log("[green]no new settings to configure[/green]") return diff --git a/rolabesti/controllers/parser.py b/rolabesti/controllers/parser.py index b5ba672..dc693b4 100644 --- a/rolabesti/controllers/parser.py +++ b/rolabesti/controllers/parser.py @@ -1,4 +1,3 @@ -import re from pathlib import Path from mutagen import MutagenError @@ -9,56 +8,65 @@ from rolabesti.models import ID3Tags, Track -PATTERNS = { - r"/Places/([^/]+)/Genres/([^/]+)/Albums/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ( - "place", "genre", "album", "side", "title"), - r"/Places/([^/]+)/Genres/([^/]+)/([^/]+)/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ( - "place", "genre", "artist", "album", "side", "title"), - r"/Places/([^/]+)/Genres/([^/]+)/([^/]+)/([^/]+)\.[mM][pP]3$": ("place", "genre", "artist", "title"), - r"/Places/([^/]+)/Genres/([^/]+)/([^/]+)\.[mM][pP]3$": ("place", "genre", "title"), - r"/Places/([^/]+)/([^/]+)\.[mM][pP]3$": ("place", "title"), - r"/Places/([^/]+)/Albums/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ("place", "album", "side", "title"), - r"/Places/([^/]+)/([^/]+)/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ("place", "artist", "album", "side", "title"), - r"/Places/([^/]+)/([^/]+)/([^/]+)\.[mM][pP]3$": ("place", "artist", "title"), - r"/Genres/([^/]+)/Albums/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ("genre", "album", "side", "title"), - r"/Genres/([^/]+)/([^/]+)/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ("genre", "artist", "album", "side", "title"), - r"/Genres/([^/]+)/([^/]+)/([^/]+)\.[mM][pP]3$": ("genre", "artist", "title"), - r"/Genres/([^/]+)/([^/]+)\.[mM][pP]3$": ("genre", "title"), - r"/Artists/([^/]+)/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ("artist", "album", "side", "title"), - r"/Artists/([^/]+)/([^/]+)\.[mM][pP]3$": ("artist", "title"), - r"/Albums/([^/]+)/(?:([^/]+)/)?([^/]+)\.[mM][pP]3$": ("album", "side", "title"), - r"/([^/]+)\.[mM][pP]3$": ("title",), -} +patterns = [ + [{"Places": -8, "Genres": -6, "Albums": -4}, {"place": -7, "genre": -5, "album": -3}], + [{"Places": -7, "Genres": -5, "Albums": -3}, {"place": -6, "genre": -4, "album": -2}], + [{"Places": -8, "Genres": -6}, {"place": -7, "genre": -5, "artist": -4, "album": -3}], + [{"Places": -7, "Genres": -5}, {"place": -6, "genre": -4, "artist": -3, "album": -2}], + [{"Places": -6, "Genres": -4}, {"place": -5, "genre": -3, "artist": -2}], + [{"Places": -5, "Genres": -3}, {"place": -4, "genre": -2}], + [{"Places": -6, "Albums": -4}, {"place": -5, "album": -3}], + [{"Places": -5, "Albums": -3}, {"place": -4, "album": -2}], + [{"Places": -6}, {"place": -5, "artist": -4, "album": -3}], + [{"Places": -5}, {"place": -4, "artist": -3, "album": -2}], + [{"Places": -4}, {"place": -3, "artist": -2}], + [{"Places": -3}, {"place": -2}], + [{"Genres": -6, "Albums": -4}, {"genre": -5, "album": -3}], + [{"Genres": -5, "Albums": -3}, {"genre": -4, "album": -2}], + [{"Genres": -6}, {"genre": -5, "artist": -4, "album": -3}], + [{"Genres": -5}, {"genre": -4, "artist": -3, "album": -2}], + [{"Genres": -4}, {"genre": -3, "artist": -2}], + [{"Genres": -3}, {"genre": -2}], + [{"Artists": -5}, {"artist": -4, "album": -3}], + [{"Artists": -4}, {"artist": -3, "album": -2}], + [{"Artists": -3}, {"artist": -2}], + [{"Albums": -4}, {"album": -3}], + [{"Albums": -3}, {"album": -2}], +] class Parser: """Parsing related functionality.""" + def parse(self, trackpath: Path) -> Track | None: """ Parse track located at trackpath and return a Track object. If there is an error, return None. """ - if (path_fields := self._parse_path_fields(trackpath)) is None: - return if (id3_tags := self._parse_id3_tags(trackpath)) is None: return if (length := self._parse_length(trackpath)) is None: return + path_fields = self._parse_path_fields(trackpath) + path_fields["title"] = trackpath.stem if (track := self._build_track(trackpath, path_fields, id3_tags, length)) is None: return return track @staticmethod - def _parse_path_fields(trackpath: Path) -> dict | None: + def _parse_path_fields(trackpath: Path) -> dict: """ - Match and parse trackpath against PATTERNS. - Return a dictionary with parsed fields if there is a match. - If there is no matching pattern, return None. + Parse trackpath and return a dictionary with the path fields. + If there is no matching pattern, return an empty dictionary. """ - for regex, fields in PATTERNS.items(): - match = re.search(regex, str(trackpath)) - if match: - return {field: value for field, value in zip(fields, match.groups()) if value} + for pattern in patterns: + try: + if all(field == trackpath.parts[index] for field, index in pattern[0].items()): + return {field: trackpath.parts[index] for field, index in pattern[1].items()} + except IndexError: + # Discard trackpath unable to match pattern. + pass + return {} @staticmethod def _parse_id3_tags(trackpath: Path) -> dict | None: diff --git a/tests/controllers/test_parser.py b/tests/controllers/test_parser.py index f58f676..00049b1 100644 --- a/tests/controllers/test_parser.py +++ b/tests/controllers/test_parser.py @@ -18,7 +18,28 @@ @pytest.mark.parametrize("trackpath, length", [ - (Path().joinpath("path-to-music-directory", "Places", f"{place}", "Genres", f"{genre}", "Albums", f"{album}", f"{side}", f"{title}.mp3"), 5), + (Path() / "Places" / place / "Genres" / genre / "Albums" / album / f"{title}.mp3", 3), + (Path() / "Places" / place / "Genres" / genre / artist / album / side / f"{title}.mp3", 4), + (Path() / "Places" / place / "Genres" / genre / artist / album / f"{title}.mp3", 4), + (Path() / "Places" / place / "Genres" / genre / artist / f"{title}.mp3", 3), + (Path() / "Places" / place / "Genres" / genre / f"{title}.mp3", 2), + (Path() / "Places" / place / "Albums" / album / side / f"{title}.mp3", 2), + (Path() / "Places" / place / "Albums" / album / f"{title}.mp3", 2), + (Path() / "Places" / place / artist / album / side / f"{title}.mp3", 3), + (Path() / "Places" / place / artist / album / f"{title}.mp3", 3), + (Path() / "Places" / place / artist / f"{title}.mp3", 2), + (Path() / "Places" / place / f"{title}.mp3", 1), + (Path() / "Genres" / genre / "Albums" / album / side / f"{title}.mp3", 2), + (Path() / "Genres" / genre / "Albums" / album / f"{title}.mp3", 2), + (Path() / "Genres" / genre / artist / album / side / f"{title}.mp3", 3), + (Path() / "Genres" / genre / artist / album / f"{title}.mp3", 3), + (Path() / "Genres" / genre / artist / f"{title}.mp3", 2), + (Path() / "Genres" / genre / f"{title}.mp3", 1), + (Path() / "Albums" / album / side / f"{title}.mp3", 1), + (Path() / "Albums" / album / f"{title}.mp3", 1), + (Path() / "Artists" / artist / album / side / f"{title}.mp3", 2), + (Path() / "Artists" / artist / album / f"{title}.mp3", 2), + (Path() / "Artists" / artist / f"{title}.mp3", 1), ]) def test_parse_path_fields_with_supported_trackpaths( trackpath: Path, @@ -31,13 +52,12 @@ def test_parse_path_fields_with_supported_trackpaths( @pytest.mark.parametrize("trackpath", [ - (Path(f"/path/to/music/directory/Places/{place}/Genre/{genre}"), ), - (Path(f"/path/to/music/directory/Places/{place}/Genre/{genre}/{title}"), ), - (Path(f"/path/to/music/directory/Places/{place}/{title}.pdf"), ), - (Path("@#wW#$DS23VTW#@%$wsVWExEW234ER^#^#$%"), ), + Path() / "Places" / place, + Path() / "Albums" / album, + Path() / "some" / "path", ]) def test_parse_path_fields_with_unsupported_trackpaths( trackpath: Path, ) -> None: path_fields = parser._parse_path_fields(trackpath) - assert path_fields is None + assert path_fields == {} diff --git a/tests/utils.py b/tests/utils.py index 5986fef..c2f6537 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -3,6 +3,5 @@ def get_random_string() -> str: - return "asdf" seed = string.ascii_letters + string.digits return "".join(random.sample(seed, len(seed)))