From 38650a1a7e4e6a57dc98435dcf7356d2896ee105 Mon Sep 17 00:00:00 2001 From: mungai-njoroge Date: Wed, 22 Nov 2023 15:44:31 +0300 Subject: [PATCH] Refactor file: taglib.py and utils/parsers.py Add dataclass and pathlib imports in taglib.py Add clean_filename, ParseData, and extract_artist_title functions in taglib.py Modify get_tags function in taglib.py to use extract_artist_title function Modify LyricsProvider class in lyrics.py to add timeout parameter in session.get Remove parse_artist_from_filename and parse_title_from_filename functions in utils/parsers.py Add split_artists function in utils/parsers.py Remove parse_artist_from_filename and parse_title_from_filename functions in utils/parsers.py Add remove_prod function in utils/parsers.py Refactor code and improve code readability --- app/lib/taglib.py | 60 ++++++++++++++++++++++++++++++++++++++----- app/plugins/lyrics.py | 2 +- app/utils/parsers.py | 33 ------------------------ 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/app/lib/taglib.py b/app/lib/taglib.py index 4083bf4..05c227d 100644 --- a/app/lib/taglib.py +++ b/app/lib/taglib.py @@ -1,5 +1,8 @@ +from dataclasses import dataclass import os from io import BytesIO +from pathlib import Path +import re import pendulum from PIL import Image, UnidentifiedImageError @@ -7,7 +10,7 @@ from tinytag import TinyTag from app.settings import Defaults, Paths from app.utils.hashing import create_hash -from app.utils.parsers import parse_artist_from_filename, parse_title_from_filename +from app.utils.parsers import split_artists from app.utils.wintools import win_replace_slash @@ -85,6 +88,45 @@ def parse_date(date_str: str | None) -> int | None: return None +def clean_filename(filename: str): + if "official" in filename.lower(): + return re.sub(r"\s*\([^)]*official[^)]*\)", "", filename, flags=re.IGNORECASE) + + return filename + + +@dataclass +class ParseData: + artist: str + title: str + + def __post_init__(self): + self.artist = split_artists(self.artist) + + +def extract_artist_title(filename: str): + path = Path(filename).with_suffix("") + + path = clean_filename(str(path)) + split_result = path.split(" - ") + split_result = [x.strip() for x in split_result] + + if len(split_result) == 1: + return ParseData("", split_result[0]) + + if len(split_result) > 2: + try: + int(split_result[0]) + + return ParseData(split_result[1], " - ".join(split_result[2:])) + except ValueError: + pass + + artist = split_result[0] + title = split_result[1] + return ParseData(artist, title) + + def get_tags(filepath: str): """ Returns the tags for a given audio file. @@ -112,22 +154,28 @@ def get_tags(filepath: str): if no_artist and not no_albumartist: tags.artist = tags.albumartist + parse_data = None + to_filename = ["title", "album"] for tag in to_filename: p = getattr(tags, tag) if p == "" or p is None: - maybe = parse_title_from_filename(filename) - setattr(tags, tag, maybe) + parse_data = extract_artist_title(filename) + title = parse_data.title + setattr(tags, tag, title) parse = ["artist", "albumartist"] for tag in parse: p = getattr(tags, tag) if p == "" or p is None: - maybe = parse_artist_from_filename(filename) + if not parse_data: + parse_data = extract_artist_title(filename) - if maybe: - setattr(tags, tag, ", ".join(maybe)) + artist = parse_data.artist + + if artist: + setattr(tags, tag, ", ".join(artist)) else: setattr(tags, tag, "Unknown") diff --git a/app/plugins/lyrics.py b/app/plugins/lyrics.py index 2cb2473..76024dd 100644 --- a/app/plugins/lyrics.py +++ b/app/plugins/lyrics.py @@ -75,7 +75,7 @@ class LyricsProvider(LRCProvider): return None try: - response = self.session.get(url, params=query) + response = self.session.get(url, params=query, timeout=10) except requests.exceptions.ConnectionError: return None diff --git a/app/utils/parsers.py b/app/utils/parsers.py index 6fb30b2..92b3530 100644 --- a/app/utils/parsers.py +++ b/app/utils/parsers.py @@ -18,39 +18,6 @@ def split_artists(src: str): return [a for a in artists if a] -def parse_artist_from_filename(title: str): - """ - Extracts artist names from a song title using regex. - """ - - regex = r"^(.+?)\s*[-–—]\s*(?:.+?)$" - match = re.search(regex, title, re.IGNORECASE) - - if not match: - return [] - - artists = match.group(1) - artists = split_artists(artists) - return artists - - -def parse_title_from_filename(title: str): - """ - Extracts track title from a song title using regex. - """ - - regex = r"^(?:.+?)\s*[-–—]\s*(.+?)$" - match = re.search(regex, title, re.IGNORECASE) - - if not match: - return title - - res = match.group(1) - # remove text in brackets starting with "official" case-insensitive - res = re.sub(r"\s*\([^)]*official[^)]*\)", "", res, flags=re.IGNORECASE) - return res.strip() - - def remove_prod(title: str) -> str: """ Removes the producer string in a track title using regex.