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

View File

@ -5,6 +5,7 @@ from datetime import datetime, timedelta
import pylast import pylast
import pytz import pytz
from django.conf import settings from django.conf import settings
from django.utils import timezone
from music.utils import ( from music.utils import (
get_or_create_album, get_or_create_album,
get_or_create_artist, get_or_create_artist,
@ -71,8 +72,8 @@ class LastFM:
ten_seconds_eariler = timestamp - timedelta(seconds=15) ten_seconds_eariler = timestamp - timedelta(seconds=15)
ten_seconds_later = timestamp + timedelta(seconds=15) ten_seconds_later = timestamp + timedelta(seconds=15)
existing = Scrobble.objects.filter( existing = Scrobble.objects.filter(
created__gte=ten_seconds_eariler, timestamp__gte=ten_seconds_eariler,
created__lte=ten_seconds_later, timestamp__lte=ten_seconds_later,
track=track, track=track,
).first() ).first()
if existing: if existing:
@ -112,32 +113,42 @@ class LastFM:
def get_last_scrobbles(self, time_from=None, time_to=None): 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 """Given a user, Last.fm api key, and secret key, grab a list of scrobbled
tracks""" tracks"""
lfm_params = {}
scrobbles = [] scrobbles = []
if time_from: if time_from:
time_from = int(time_from.timestamp()) lfm_params["time_from"] = int(time_from.timestamp())
if time_to: 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: for scrobble in found_scrobbles:
run_time_ticks = scrobble.track.get_duration() try:
run_time = run_time_ticks / 1000 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( scrobbles.append(
{ {
"artist": scrobble.track.get_artist().name, "artist": artist,
"album": scrobble.album, "album": scrobble.album,
"title": scrobble.track.title, "title": scrobble.track.title,
"mbid": scrobble.track.get_mbid(), "mbid": scrobble.track.get_mbid(),
"run_time": int(run_time), "run_time": run_time,
"run_time_ticks": run_time_ticks, "run_time_ticks": run_time_ticks,
"timestamp": datetime.utcfromtimestamp( "timestamp": timestamp,
int(scrobble.timestamp)
).replace(tzinfo=pytz.utc),
} }
) )
return scrobbles 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}, extra={"result": top_result},
) )
return {} return {}
print(top_result) year = None
if top_result.get("date"):
year = parse(top_result["date"]).year
return { return {
"year": parse(top_result["date"]).year, "year": year,
"mb_id": top_result["id"], "mb_id": top_result["id"],
"mb_group_id": top_result["release-group"]["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 scrobbles.utils import convert_to_seconds, parse_mopidy_uri
from videos.models import Video from videos.models import Video
from sports.models import SportEvent 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__) logger = logging.getLogger(__name__)
@ -57,23 +62,23 @@ def mopidy_scrobble_podcast(
def mopidy_scrobble_track( def mopidy_scrobble_track(
data_dict: dict, user_id: Optional[int] data_dict: dict, user_id: Optional[int]
) -> Optional[Scrobble]: ) -> Optional[Scrobble]:
artist_dict = { artist = get_or_create_artist(
"name": data_dict.get("artist", None), data_dict.get("artist"),
"musicbrainz_id": data_dict.get("musicbrainz_artist_id", None), mbid=data_dict.get("musicbrainz_artist_id", None),
} )
album = get_or_create_album(
album_dict = { data_dict.get("album"),
"name": data_dict.get("album"), artist=artist,
"musicbrainz_id": data_dict.get("musicbrainz_album_id"), mbid=data_dict.get("musicbrainz_album_id"),
} )
track = get_or_create_track(
track_dict = { title=data_dict.get("name"),
"title": data_dict.get("name"), mbid=data_dict.get("musicbrainz_track_id"),
"run_time_ticks": data_dict.get("run_time_ticks"), artist=artist,
"run_time": data_dict.get("run_time"), album=album,
} 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) )
# Now we run off a scrobble # Now we run off a scrobble
mopidy_data = { mopidy_data = {
@ -136,38 +141,30 @@ def jellyfin_scrobble_track(
logger.error("No playback position tick from Jellyfin, aborting") logger.error("No playback position tick from Jellyfin, aborting")
return return
artist_dict = { artist = get_or_create_artist(
'name': data_dict.get(JELLYFIN_POST_KEYS["ARTIST_NAME"], None), data_dict.get(JELLYFIN_POST_KEYS["ARTIST_NAME"]),
'musicbrainz_id': data_dict.get( mbid=data_dict.get(JELLYFIN_POST_KEYS["ARTIST_MB_ID"]),
JELLYFIN_POST_KEYS["ARTIST_MB_ID"], None )
), 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 = { run_time_ticks = (
"name": data_dict.get(JELLYFIN_POST_KEYS["ALBUM_NAME"], None), data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME_TICKS"]) // 10000
"musicbrainz_id": data_dict.get(JELLYFIN_POST_KEYS['ALBUM_MB_ID']), )
} run_time = convert_to_seconds(
data_dict.get(JELLYFIN_POST_KEYS["RUN_TIME"])
# Convert ticks from Jellyfin from microseconds to nanoseconds )
# Ain't nobody got time for nanoseconds track = get_or_create_track(
track_dict = { title=data_dict.get("Name"),
"title": data_dict.get("Name", ""), mbid=data_dict.get(JELLYFIN_POST_KEYS["TRACK_MB_ID"]),
"run_time_ticks": data_dict.get( artist=artist,
JELLYFIN_POST_KEYS["RUN_TIME_TICKS"], None album=album,
) run_time_ticks=run_time_ticks,
// 10000, run_time=run_time,
"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()
scrobble_dict = build_scrobble_dict(data_dict, user_id) scrobble_dict = build_scrobble_dict(data_dict, user_id)