From ab6a68427eda298ac005bbb05780d23b88cc25a6 Mon Sep 17 00:00:00 2001 From: geo-martino Date: Tue, 16 Jan 2024 17:58:48 -0500 Subject: [PATCH] sort imports + tweaks to write local tags logic --- README.md | 2 +- musify/local/collection.py | 3 ++- musify/local/track/base/writer.py | 10 +++++++++- musify/local/track/flac.py | 12 +++++------- musify/local/track/m4a.py | 12 +++++------- musify/local/track/mp3.py | 12 +++++------- musify/local/track/wma.py | 12 +++++------- musify/shared/api/request.py | 2 +- musify/shared/logger.py | 2 +- musify/spotify/api/item.py | 5 +++-- musify/spotify/api/playlist.py | 3 ++- tests/processors/test_sort.py | 2 +- tests/shared/remote/processors/check.py | 2 +- tests/shared/test_logger.py | 2 +- tests/spotify/api/test_spotify_api_item.py | 2 +- 15 files changed, 43 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index ac8889e5..e22a82fe 100644 --- a/README.md +++ b/README.md @@ -384,7 +384,7 @@ python -m pip install musify ## Currently Supported - **Music Streaming Services**: `Spotify` -- **Audio filetypes**: `.wma` `.flac` `.mp3` `.m4a` +- **Audio filetypes**: `.wma` `.flac` `.m4a` `.mp3` - **Local playlist filetypes**: `.m3u` `.xautopf` - **Local Libraries**: `MusicBee` diff --git a/musify/local/collection.py b/musify/local/collection.py index 4c887e8c..b43f0af3 100644 --- a/musify/local/collection.py +++ b/musify/local/collection.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -import sys from abc import ABCMeta, abstractmethod from collections.abc import Mapping, Collection, Iterable, Container from datetime import datetime @@ -9,6 +8,8 @@ from os.path import splitext, join, basename, exists, isdir from typing import Any +import sys + from musify.local.base import LocalItem from musify.local.exception import LocalCollectionError from musify.local.track import LocalTrack, SyncResultTrack, load_track, TRACK_FILETYPES diff --git a/musify/local/track/base/writer.py b/musify/local/track/base/writer.py index 2c7d4033..891c18b5 100644 --- a/musify/local/track/base/writer.py +++ b/musify/local/track/base/writer.py @@ -234,7 +234,7 @@ def save(self, tags: UnitIterable[Tags] = Tags.ALL, replace: bool = False, dry_r return SyncResultTrack(saved=save, updated=updated) @abstractmethod - def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) -> bool: + def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) -> bool | None: """ Generic method for updating a tag value in the file. @@ -243,6 +243,14 @@ def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) - :param dry_run: Run function, but do not modify file at all. :return: True if the file was updated or would have been when dry_run is True, False otherwise. """ + if tag_id is None: + return False + + if tag_value is None: + remove = not dry_run and tag_id in self.file and self.file[tag_id] + if remove: + del self.file[tag_id] + return remove def _write_title(self, dry_run: bool = True) -> bool: """ diff --git a/musify/local/track/flac.py b/musify/local/track/flac.py index 476cd8ff..a6371d83 100644 --- a/musify/local/track/flac.py +++ b/musify/local/track/flac.py @@ -43,18 +43,16 @@ def _check_for_images(self) -> bool: return len(self._file.pictures) > 0 def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) -> bool: - if tag_value is None: - remove = not dry_run and tag_id in self.file and self.file[tag_id] - if remove: - del self.file[tag_id] - return remove + result = super()._write_tag(tag_id=tag_id, tag_value=tag_value, dry_run=dry_run) + if result is not None: + return result - if not dry_run and tag_id is not None: + if not dry_run: if isinstance(tag_value, (list, set, tuple)): self._file[tag_id] = list(map(str, tag_value)) else: self._file[tag_id] = str(tag_value) - return tag_id is not None + return True def _write_images(self, dry_run: bool = True) -> bool: updated = False diff --git a/musify/local/track/m4a.py b/musify/local/track/m4a.py index 180b0b19..d1374b54 100644 --- a/musify/local/track/m4a.py +++ b/musify/local/track/m4a.py @@ -78,13 +78,11 @@ def _read_images(self) -> list[Image.Image] | None: return [Image.open(BytesIO(bytes(value))) for value in values] if values is not None else None def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) -> bool: - if tag_value is None: - remove = not dry_run and tag_id in self.file and self.file[tag_id] - if remove: - del self.file[tag_id] - return remove + result = super()._write_tag(tag_id=tag_id, tag_value=tag_value, dry_run=dry_run) + if result is not None: + return result - if not dry_run and tag_id is not None: + if not dry_run: if tag_id.startswith("----:com.apple.iTunes"): self._file[tag_id] = [ mutagen.mp4.MP4FreeForm(str(v).encode("utf-8"), 1) for v in to_collection(tag_value) @@ -95,7 +93,7 @@ def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) - self._file[tag_id] = [tag_value] else: self._file[tag_id] = to_collection(tag_value, list) - return tag_id is not None + return True def _write_track(self, dry_run: bool = True) -> bool: tag_id = next(iter(self.tag_map.track_number), None) diff --git a/musify/local/track/mp3.py b/musify/local/track/mp3.py index 04abcb6e..6a5664ef 100644 --- a/musify/local/track/mp3.py +++ b/musify/local/track/mp3.py @@ -70,15 +70,13 @@ def _read_images(self) -> list[Image.Image] | None: return [Image.open(BytesIO(value.data)) for value in values] if values is not None else None def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) -> bool: - if tag_value is None: - remove = not dry_run and tag_id in self.file and self.file[tag_id] - if remove: - del self.file[tag_id] - return remove + result = super()._write_tag(tag_id=tag_id, tag_value=tag_value, dry_run=dry_run) + if result is not None: + return result - if not dry_run and tag_id is not None: + if not dry_run: self._file[tag_id] = getattr(mutagen.id3, tag_id)(3, text=str(tag_value)) - return tag_id is not None + return True def _write_genres(self, dry_run: bool = True) -> bool: values = ";".join(self.genres or []) diff --git a/musify/local/track/wma.py b/musify/local/track/wma.py index 809b47c8..cd2b6be3 100644 --- a/musify/local/track/wma.py +++ b/musify/local/track/wma.py @@ -86,13 +86,11 @@ def _read_images(self) -> list[Image.Image] | None: return images def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) -> bool: - if tag_value is None: - remove = not dry_run and tag_id in self.file and self.file[tag_id] - if remove: - del self.file[tag_id] - return remove + result = super()._write_tag(tag_id=tag_id, tag_value=tag_value, dry_run=dry_run) + if result is not None: + return result - if not dry_run and tag_id is not None: + if not dry_run: if isinstance(tag_value, (list, set, tuple)): if all(isinstance(v, mutagen.asf.ASFByteArrayAttribute) for v in tag_value): self._file[tag_id] = tag_value @@ -100,7 +98,7 @@ def _write_tag(self, tag_id: str | None, tag_value: Any, dry_run: bool = True) - self._file[tag_id] = [mutagen.asf.ASFUnicodeAttribute(str(v)) for v in tag_value] else: self._file[tag_id] = mutagen.asf.ASFUnicodeAttribute(str(tag_value)) - return tag_id is not None + return True def _write_images(self, dry_run: bool = True) -> bool: tag_id = next(iter(self.tag_map.images), None) diff --git a/musify/shared/api/request.py b/musify/shared/api/request.py index 391ee4b1..238e5baf 100644 --- a/musify/shared/api/request.py +++ b/musify/shared/api/request.py @@ -3,11 +3,11 @@ from datetime import datetime as dt from datetime import timedelta from http import HTTPStatus -from time import sleep from typing import Any from requests import Response, Session from requests_cache import CachedSession +from time import sleep from musify.shared.api.authorise import APIAuthoriser from musify.shared.api.exception import APIError diff --git a/musify/shared/logger.py b/musify/shared/logger.py index 7235c651..91abe6ca 100644 --- a/musify/shared/logger.py +++ b/musify/shared/logger.py @@ -5,13 +5,13 @@ import os import re import shutil -import sys from collections.abc import Iterable from datetime import datetime from glob import glob from os.path import join, dirname, splitext, split, basename, isfile, sep, isdir from typing import Any +import sys from tqdm.auto import tqdm from musify import PROGRAM_NAME diff --git a/musify/spotify/api/item.py b/musify/spotify/api/item.py index 770a77c7..e6e31ddc 100644 --- a/musify/spotify/api/item.py +++ b/musify/spotify/api/item.py @@ -1,10 +1,11 @@ import re from abc import ABCMeta from collections.abc import Collection, Mapping, MutableMapping -from itertools import batched from typing import Any from urllib.parse import parse_qs, urlparse +from itertools import batched + from musify.shared.api.exception import APIError from musify.shared.remote.api import APIMethodInputType from musify.shared.remote.enum import RemoteObjectType, RemoteIDType @@ -54,7 +55,7 @@ def _get_items_multi( kind = self._get_unit(key=key, kind=kind) bar = self.logger.get_progress_bar( - iterable=id_list, desc=f"Getting {kind}", unit=kind, disable=len(id_list) < self._bar_threshold * 10 + iterable=id_list, desc=f"Getting {kind}", unit=kind, disable=len(id_list) < self._bar_threshold ) results: list[dict[str, Any]] = [] diff --git a/musify/spotify/api/playlist.py b/musify/spotify/api/playlist.py index 8f2eaf20..f15cbcfe 100644 --- a/musify/spotify/api/playlist.py +++ b/musify/spotify/api/playlist.py @@ -1,8 +1,9 @@ from abc import ABCMeta from collections.abc import Collection, Mapping -from itertools import batched from typing import Any +from itertools import batched + from musify import PROGRAM_NAME, PROGRAM_URL from musify.shared.remote.enum import RemoteIDType, RemoteObjectType from musify.shared.remote.exception import RemoteIDTypeError diff --git a/tests/processors/test_sort.py b/tests/processors/test_sort.py index 696b3c5c..54a119b4 100644 --- a/tests/processors/test_sort.py +++ b/tests/processors/test_sort.py @@ -1,9 +1,9 @@ from collections.abc import Callable -from itertools import groupby from random import choice, randrange import pytest import xmltodict +from itertools import groupby from musify.local.track import LocalTrack from musify.local.track.field import LocalTrackField diff --git a/tests/shared/remote/processors/check.py b/tests/shared/remote/processors/check.py index 8eee4fef..0c570f9b 100644 --- a/tests/shared/remote/processors/check.py +++ b/tests/shared/remote/processors/check.py @@ -1,9 +1,9 @@ import re from abc import ABC, abstractmethod -from itertools import batched from random import randrange, choice import pytest +from itertools import batched from pytest_mock import MockerFixture from musify.local.track import LocalTrack diff --git a/tests/shared/test_logger.py b/tests/shared/test_logger.py index f65e0b48..7be90175 100644 --- a/tests/shared/test_logger.py +++ b/tests/shared/test_logger.py @@ -1,7 +1,6 @@ import logging import os import string -import sys from copy import copy, deepcopy from datetime import datetime, timedelta from glob import glob @@ -9,6 +8,7 @@ from random import choice import pytest +import sys from musify.shared.logger import MusifyLogger, INFO_EXTRA, REPORT, STAT, LOGGING_DT_FORMAT from musify.shared.logger import format_full_func_name, LogFileFilter, CurrentTimeRotatingFileHandler diff --git a/tests/spotify/api/test_spotify_api_item.py b/tests/spotify/api/test_spotify_api_item.py index b72ae41b..0952e9e4 100644 --- a/tests/spotify/api/test_spotify_api_item.py +++ b/tests/spotify/api/test_spotify_api_item.py @@ -1,11 +1,11 @@ from collections.abc import Collection from copy import deepcopy -from itertools import batched from random import sample, choice from typing import Any from urllib.parse import parse_qs import pytest +from itertools import batched # noinspection PyProtectedMember,PyUnresolvedReferences from requests_mock.request import _RequestObjectProxy as Request