Skip to content

Commit

Permalink
minor tweaks for v1 (#98)
Browse files Browse the repository at this point in the history
* fix musicbee xml path matching on load+save

* update todo comments
  • Loading branch information
geo-martino authored Jun 11, 2024
1 parent 22545ea commit 86acb28
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 24 deletions.
2 changes: 1 addition & 1 deletion musify/libraries/local/library/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ async def load(self) -> None:

def _log_errors(self, message: str = "Could not load") -> None:
"""Log paths which had some error while loading"""
errors = tuple(f"\33[91m{e}\33[0m" for e in self.errors)
errors = tuple(f"\33[91m{e}\33[0m" for e in sorted(self.errors))
if len(errors) > 0:
self.logger.warning(f"\33[97m{message}: \33[0m\n\t- {"\n\t- ".join(errors)} ")
self.logger.print()
Expand Down
37 changes: 18 additions & 19 deletions musify/libraries/local/library/musicbee.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def __init__(
)

def _get_track_from_xml_path(
self, track_xml: dict[str, Any], track_map: dict[Path, LocalTrack]
self, track_xml: dict[str, Any], track_map: dict[str, LocalTrack]
) -> LocalTrack | None:
if track_xml["Track Type"] != "File":
return
Expand All @@ -143,27 +143,34 @@ def _get_track_from_xml_path(
prefixes.update(self.path_mapper.stem_map.keys())

for prefix in prefixes:
track = track_map.get(Path(path.removeprefix(prefix)))
track = track_map.get(path.removeprefix(prefix).casefold())
if track is not None:
return track

self.errors.append(path)

async def load_tracks(self) -> None:
await super().load_tracks()
self.logger.debug(f"Enrich {self.name} tracks: START")

def _map_track_to_xml(self) -> dict[LocalTrack, dict[str, Any]]:
# need to remove library folders to allow match to be os agnostic
track_map = {
Path(str(track.path).removeprefix(str(folder))): track
str(track.path).removeprefix(str(folder)).casefold(): track
for folder in self.library_folders for track in self.tracks
}
track_xml_map: dict[LocalTrack, dict[str, Any]] = {}

for track_xml in self.library_xml["Tracks"].values():
track = self._get_track_from_xml_path(track_xml=track_xml, track_map=track_map)
if track is None:
continue

track_xml_map[track] = track_xml

return track_xml_map

async def load_tracks(self) -> None:
await super().load_tracks()
self.logger.debug(f"Enrich {self.name} tracks: START")

for track, track_xml in self._map_track_to_xml().items():
track.rating = int(track_xml.get("Rating")) if track_xml.get("Rating") is not None else None
track.date_added = track_xml.get("Date Added")
track.last_played = track_xml.get("Play Date UTC")
Expand All @@ -180,19 +187,11 @@ async def save(self, dry_run: bool = True, *_, **__) -> dict[str, Any]:
:return: Map representation of the saved XML file.
"""
self.logger.debug(f"Save {self.name} library file: START")
# need to remove library folders to allow match to be os agnostic
track_map = {
Path(str(track.path).removeprefix(str(folder))): track
for folder in self.library_folders for track in self.tracks
}
track_id_map: dict[LocalTrack, tuple[int, str]] = {}

for track_xml in self.library_xml["Tracks"].values():
track = self._get_track_from_xml_path(track_xml=track_xml, track_map=track_map)
if track is None:
continue

track_id_map[track] = (track_xml["Track ID"], track_xml["Persistent ID"])
track_id_map: dict[LocalTrack, tuple[int, str]] = {
track: (track_xml["Track ID"], track_xml["Persistent ID"])
for track, track_xml in self._map_track_to_xml().items()
}

self._log_errors("Could not find a loaded track for these paths from the MusicBee library file")

Expand Down
2 changes: 1 addition & 1 deletion musify/libraries/local/playlist/xautopf.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ def get_sorter(self) -> ItemSorter | None:

return ItemSorter(fields=fields, shuffle_mode=shuffle_mode, shuffle_weight=shuffle_weight)

# TODO: remove defined_sort workaround here - see self.defined_sort
# TODO: remove defined_sort workaround here, should use manual sort when no `fields` - see self.defined_sort
return ItemSorter(fields=fields or next(iter(self.defined_sort.values())))

def parse_sorter(self, sorter: ItemSorter | None = None) -> None:
Expand Down
6 changes: 3 additions & 3 deletions musify/libraries/local/track/track.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,9 @@ def as_dict(self):
return self._get_attributes() | attributes_extra

def __hash__(self):
# TODO: why doesn't this get inherited correctly from File superclass.
# If you remove this, tests will fail with error 'un-hashable type' for all subclasses of LocalTrack.
# LocalTrack should be inheriting __hash__ from File superclass
# If a class overrides __eq__, it must override __hash__ alongside it.
# https://stackoverflow.com/questions/74664008/python-typeerror-unhashable-type-when-inheriting-from-subclass-with-hash
# https://github.com/python/cpython/issues/46488
return super().__hash__()

def __eq__(self, item: MusifyItem):
Expand Down

0 comments on commit 86acb28

Please sign in to comment.