114 lines
3.8 KiB
Python
114 lines
3.8 KiB
Python
import logging
|
|
import re
|
|
|
|
from django.db import IntegrityError, models, transaction
|
|
from music.constants import VARIOUS_ARTIST_DICT
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def clean_artist_name(name: str) -> str:
|
|
"""Remove featured names from artist string."""
|
|
if " feat. " in name.lower():
|
|
name = re.split("feat.", name, flags=re.IGNORECASE)[0].strip()
|
|
if " w. " in name.lower():
|
|
name = re.split("feat.", name, flags=re.IGNORECASE)[0].strip()
|
|
if " featuring " in name.lower():
|
|
name = re.split("featuring", name, flags=re.IGNORECASE)[0].strip()
|
|
# if " & " in name.lower() and "of the wand" not in name.lower():
|
|
# name = re.split("&", name, flags=re.IGNORECASE)[0].strip()
|
|
|
|
return name
|
|
|
|
|
|
def get_or_create_various_artists() -> "Artist":
|
|
from music.models import Artist
|
|
|
|
artist = Artist.objects.filter(name="Various Artists").first()
|
|
if not artist:
|
|
artist = Artist.objects.create(**VARIOUS_ARTIST_DICT)
|
|
logger.info("Created Various Artists placeholder")
|
|
return artist
|
|
|
|
|
|
def deduplicate_tracks(commit=False) -> int:
|
|
from music.models import Track
|
|
|
|
duplicates = (
|
|
Track.objects.values("artist", "title")
|
|
.annotate(dup_count=models.Count("id"))
|
|
.filter(dup_count__gt=1)
|
|
)
|
|
|
|
query = models.Q()
|
|
for dup in duplicates:
|
|
query |= models.Q(artist=dup["artist"], title=dup["title"])
|
|
|
|
duplicate_tracks = Track.objects.filter(query)
|
|
|
|
for b in duplicate_tracks:
|
|
tracks = Track.objects.filter(artist=b.artist, title=b.title)
|
|
first = tracks.first()
|
|
for other in tracks.exclude(id=first.id):
|
|
print("Moving scrobbles for", other.id, " to ", first.id)
|
|
if commit:
|
|
with transaction.atomic():
|
|
other.scrobble_set.update(track=first)
|
|
print("deleting ", other.id, " - ", other)
|
|
try:
|
|
other.delete()
|
|
except IntegrityError as e:
|
|
print(
|
|
"could not delete ",
|
|
other.id,
|
|
f": IntegrityError {e}",
|
|
)
|
|
return len(duplicate_tracks)
|
|
|
|
|
|
def condense_albums(commit: bool = False):
|
|
from music.models import Track
|
|
from scrobbles.models import Scrobble
|
|
|
|
processed_ids = []
|
|
for track in Track.objects.all():
|
|
albums_to_add = []
|
|
duplicates = (
|
|
Track.objects.filter(title=track.title, artist=track.artist)
|
|
.exclude(id=track.id)
|
|
.exclude(id__in=processed_ids)
|
|
)
|
|
|
|
if commit and track.album:
|
|
albums_to_add.append(track.album)
|
|
|
|
for dup_track in duplicates:
|
|
logger.info(f"Adding {dup_track.album} to {track} albums")
|
|
if commit and dup_track.album:
|
|
track.albums.add(dup_track.album)
|
|
|
|
# Find out if this track appears more than once
|
|
duplicates = Track.objects.filter(
|
|
title=track.title, artist=track.artist
|
|
)
|
|
if duplicates.count() > 1:
|
|
logger.info(f"Track appears more than once, condensing: {track}")
|
|
|
|
albums_to_add.extend([d.album for d in duplicates])
|
|
# Find all scrobbles
|
|
duplicate_ids = duplicates.values_list("id", flat=True)
|
|
scrobbles = Scrobble.objects.filter(track_id__in=duplicate_ids)
|
|
logger.info(
|
|
f"Found {scrobbles.count()} scrobbles to merge onto {track}"
|
|
)
|
|
if commit:
|
|
scrobbles.update(track=track)
|
|
track.albums.add(*list(set(albums_to_add)))
|
|
|
|
processed_ids.extend(duplicate_ids)
|
|
|
|
if commit:
|
|
Track.objects.filter(scrobble__isnull=True).delete()
|
|
|
|
return len(set(processed_ids))
|