Fix lastfm importing

This commit is contained in:
2023-02-15 01:33:12 -05:00
parent 817ad3f67f
commit 20528b576b
4 changed files with 90 additions and 73 deletions

View File

@ -11,15 +11,21 @@ logger = logging.getLogger(__name__)
from music.models import Artist, Album, Track
def get_or_create_artist(name: str) -> Artist:
artist, artist_created = Artist.objects.get_or_create(name=name)
if artist_created:
def get_or_create_artist(name: str, mbid: str = None) -> Artist:
if mbid:
artist, artist_created = Artist.objects.get_or_create(
name=name, musicbrainz_id=mbid
)
else:
artist, artist_created = Artist.objects.get_or_create(name=name)
if not mbid:
artist.musicbrainz_id = lookup_artist_id_from_mb(artist.name)
artist.save(update_fields=["musicbrainz_id"])
return artist
def get_or_create_album(name: str, artist: Artist) -> Album:
def get_or_create_album(name: str, artist: Artist, mbid: str = None) -> Album:
album = None
album_created = False
albums = Album.objects.filter(name__iexact=name)
@ -31,11 +37,11 @@ def get_or_create_album(name: str, artist: Artist) -> Album:
album = potential_album
if not album:
album_created = True
album = Album.objects.create(name=name)
album = Album.objects.create(name=name, musicbrainz_id=mbid)
album.save()
album.artists.add(artist)
if album_created:
if album_created or not mbid:
album_dict = lookup_album_dict_from_mb(
album.name, artist_name=artist.name
)

View File

@ -5,6 +5,7 @@ from datetime import datetime, timedelta
import pylast
import pytz
from django.conf import settings
from django.utils import timezone
from music.utils import (
get_or_create_album,
get_or_create_artist,
@ -71,8 +72,8 @@ class LastFM:
ten_seconds_eariler = timestamp - timedelta(seconds=15)
ten_seconds_later = timestamp + timedelta(seconds=15)
existing = Scrobble.objects.filter(
created__gte=ten_seconds_eariler,
created__lte=ten_seconds_later,
timestamp__gte=ten_seconds_eariler,
timestamp__lte=ten_seconds_later,
track=track,
).first()
if existing:
@ -112,32 +113,42 @@ class LastFM:
def get_last_scrobbles(self, time_from=None, time_to=None):
"""Given a user, Last.fm api key, and secret key, grab a list of scrobbled
tracks"""
lfm_params = {}
scrobbles = []
if time_from:
time_from = int(time_from.timestamp())
lfm_params["time_from"] = int(time_from.timestamp())
if time_to:
time_to = int(time_to.timestamp())
lfm_params["time_to"] = int(time_to.timestamp())
# if not time_from and not time_to:
lfm_params['limit'] = None
found_scrobbles = self.user.get_recent_tracks(**lfm_params)
if not time_from and not time_to:
found_scrobbles = self.user.get_recent_tracks(limit=None)
else:
found_scrobbles = self.user.get_recent_tracks(
time_from=time_from, time_to=time_to
)
for scrobble in found_scrobbles:
run_time_ticks = scrobble.track.get_duration()
run_time = run_time_ticks / 1000
try:
run_time_ticks = scrobble.track.get_duration()
run_time = int(run_time_ticks / 1000)
except pylast.MalformedResponseError:
run_time_ticks = None
run_time = None
logger.warn(f"Track {scrobble.track} has no duration")
timestamp = datetime.utcfromtimestamp(
int(scrobble.timestamp)
).replace(tzinfo=pytz.utc)
artist = scrobble.track.get_artist().name
logger.debug(f"{artist},{scrobble.track.title},{timestamp}")
scrobbles.append(
{
"artist": scrobble.track.get_artist().name,
"artist": artist,
"album": scrobble.album,
"title": scrobble.track.title,
"mbid": scrobble.track.get_mbid(),
"run_time": int(run_time),
"run_time": run_time,
"run_time_ticks": run_time_ticks,
"timestamp": datetime.utcfromtimestamp(
int(scrobble.timestamp)
).replace(tzinfo=pytz.utc),
"timestamp": timestamp,
}
)
return scrobbles

View File

@ -62,9 +62,12 @@ def lookup_album_dict_from_mb(release_name: str, artist_name: str) -> dict:
extra={"result": top_result},
)
return {}
print(top_result)
year = None
if top_result.get("date"):
year = parse(top_result["date"]).year
return {
"year": parse(top_result["date"]).year,
"year": year,
"mb_id": top_result["id"],
"mb_group_id": top_result["release-group"]["id"],
}

View File

@ -10,6 +10,11 @@ from scrobbles.models import Scrobble
from scrobbles.utils import convert_to_seconds, parse_mopidy_uri
from videos.models import Video
from sports.models import SportEvent
from vrobbler.apps.music.utils import (
get_or_create_album,
get_or_create_artist,
get_or_create_track,
)
logger = logging.getLogger(__name__)
@ -57,23 +62,23 @@ def mopidy_scrobble_podcast(
def mopidy_scrobble_track(
data_dict: dict, user_id: Optional[int]
) -> Optional[Scrobble]:
artist_dict = {
"name": data_dict.get("artist", None),
"musicbrainz_id": data_dict.get("musicbrainz_artist_id", None),
}
album_dict = {
"name": data_dict.get("album"),
"musicbrainz_id": data_dict.get("musicbrainz_album_id"),
}
track_dict = {
"title": data_dict.get("name"),
"run_time_ticks": data_dict.get("run_time_ticks"),
"run_time": data_dict.get("run_time"),
}
track = Track.find_or_create(artist_dict, album_dict, track_dict)
artist = get_or_create_artist(
data_dict.get("artist"),
mbid=data_dict.get("musicbrainz_artist_id", None),
)
album = get_or_create_album(
data_dict.get("album"),
artist=artist,
mbid=data_dict.get("musicbrainz_album_id"),
)
track = get_or_create_track(
title=data_dict.get("name"),
mbid=data_dict.get("musicbrainz_track_id"),
artist=artist,
album=album,
run_time_ticks=data_dict.get("run_time_ticks"),
run_time=data_dict.get("run_time"),
)
# Now we run off a scrobble
mopidy_data = {
@ -136,38 +141,30 @@ def jellyfin_scrobble_track(
logger.error("No playback position tick from Jellyfin, aborting")
return
artist_dict = {
'name': data_dict.get(JELLYFIN_POST_KEYS["ARTIST_NAME"], None),
'musicbrainz_id': data_dict.get(
JELLYFIN_POST_KEYS["ARTIST_MB_ID"], None
),
}
artist = get_or_create_artist(
data_dict.get(JELLYFIN_POST_KEYS["ARTIST_NAME"]),
mbid=data_dict.get(JELLYFIN_POST_KEYS["ARTIST_MB_ID"]),
)
album = get_or_create_album(
data_dict.get(JELLYFIN_POST_KEYS["ALBUM_NAME"]),
artist=artist,
mbid=data_dict.get(JELLYFIN_POST_KEYS['ALBUM_MB_ID']),
)
album_dict = {
"name": data_dict.get(JELLYFIN_POST_KEYS["ALBUM_NAME"], None),
"musicbrainz_id": data_dict.get(JELLYFIN_POST_KEYS['ALBUM_MB_ID']),
}
# Convert ticks from Jellyfin from microseconds to nanoseconds
# Ain't nobody got time for nanoseconds
track_dict = {
"title": data_dict.get("Name", ""),
"run_time_ticks": data_dict.get(
JELLYFIN_POST_KEYS["RUN_TIME_TICKS"], None
)
// 10000,
"run_time": convert_to_seconds(
data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME"], None)
),
}
track = Track.find_or_create(artist_dict, album_dict, track_dict)
# Prefer Mopidy MD IDs to Jellyfin, so skip if we already have one
if not track.musicbrainz_id:
track.musicbrainz_id = data_dict.get(
JELLYFIN_POST_KEYS["TRACK_MB_ID"], None
)
track.save()
run_time_ticks = (
data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME_TICKS"]) // 10000
)
run_time = convert_to_seconds(
data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME"])
)
track = get_or_create_track(
title=data_dict.get("Name"),
mbid=data_dict.get(JELLYFIN_POST_KEYS["TRACK_MB_ID"]),
artist=artist,
album=album,
run_time_ticks=run_time_ticks,
run_time=run_time,
)
scrobble_dict = build_scrobble_dict(data_dict, user_id)