2017-12-27 19:29:26 +00:00
|
|
|
from django.core.files.base import ContentFile
|
|
|
|
|
2018-03-06 19:27:28 +00:00
|
|
|
from dynamic_preferences.registries import global_preferences_registry
|
|
|
|
|
2017-12-26 20:12:37 +00:00
|
|
|
from funkwhale_api.taskapp import celery
|
|
|
|
from funkwhale_api.providers.acoustid import get_acoustid_client
|
2017-12-27 22:32:02 +00:00
|
|
|
from funkwhale_api.providers.audiofile.tasks import import_track_data_from_path
|
2017-12-26 20:12:37 +00:00
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
from . import models
|
|
|
|
from . import lyrics as lyrics_utils
|
|
|
|
|
|
|
|
|
|
|
|
@celery.app.task(name='acoustid.set_on_track_file')
|
|
|
|
@celery.require_instance(models.TrackFile, 'track_file')
|
|
|
|
def set_acoustid_on_track_file(track_file):
|
|
|
|
client = get_acoustid_client()
|
|
|
|
result = client.get_best_match(track_file.audio_file.path)
|
|
|
|
|
|
|
|
def update(id):
|
|
|
|
track_file.acoustid_track_id = id
|
|
|
|
track_file.save(update_fields=['acoustid_track_id'])
|
|
|
|
return id
|
|
|
|
if result:
|
|
|
|
return update(result['id'])
|
|
|
|
|
|
|
|
|
2018-04-07 09:29:40 +00:00
|
|
|
def import_track_from_remote(library_track):
|
|
|
|
metadata = library_track.metadata
|
|
|
|
try:
|
|
|
|
track_mbid = metadata['recording']['musicbrainz_id']
|
|
|
|
assert track_mbid # for null/empty values
|
|
|
|
except (KeyError, AssertionError):
|
|
|
|
pass
|
|
|
|
else:
|
2018-04-05 21:22:28 +00:00
|
|
|
return models.Track.get_or_create_from_api(mbid=track_mbid)
|
|
|
|
|
2018-04-07 09:29:40 +00:00
|
|
|
try:
|
|
|
|
album_mbid = metadata['release']['musicbrainz_id']
|
|
|
|
assert album_mbid # for null/empty values
|
|
|
|
except (KeyError, AssertionError):
|
|
|
|
pass
|
|
|
|
else:
|
2018-04-05 21:22:28 +00:00
|
|
|
album = models.Album.get_or_create_from_api(mbid=album_mbid)
|
|
|
|
return models.Track.get_or_create_from_title(
|
2018-04-07 09:29:40 +00:00
|
|
|
library_track.title, artist=album.artist, album=album)
|
2018-04-05 21:22:28 +00:00
|
|
|
|
2018-04-07 09:29:40 +00:00
|
|
|
try:
|
|
|
|
artist_mbid = metadata['artist']['musicbrainz_id']
|
|
|
|
assert artist_mbid # for null/empty values
|
|
|
|
except (KeyError, AssertionError):
|
|
|
|
pass
|
|
|
|
else:
|
2018-04-05 21:22:28 +00:00
|
|
|
artist = models.Artist.get_or_create_from_api(mbid=artist_mbid)
|
|
|
|
album = models.Album.get_or_create_from_title(
|
2018-04-07 09:29:40 +00:00
|
|
|
library_track.album_title, artist=artist)
|
2018-04-05 21:22:28 +00:00
|
|
|
return models.Track.get_or_create_from_title(
|
2018-04-07 09:29:40 +00:00
|
|
|
library_track.title, artist=artist, album=album)
|
2018-04-05 21:22:28 +00:00
|
|
|
|
|
|
|
# worst case scenario, we have absolutely no way to link to a
|
|
|
|
# musicbrainz resource, we rely on the name/titles
|
|
|
|
artist = models.Artist.get_or_create_from_name(
|
2018-04-07 09:29:40 +00:00
|
|
|
library_track.artist_name)
|
2018-04-05 21:22:28 +00:00
|
|
|
album = models.Album.get_or_create_from_title(
|
2018-04-07 09:29:40 +00:00
|
|
|
library_track.album_title, artist=artist)
|
2018-04-05 21:22:28 +00:00
|
|
|
return models.Track.get_or_create_from_title(
|
2018-04-07 09:29:40 +00:00
|
|
|
library_track.title, artist=artist, album=album)
|
2018-04-05 21:22:28 +00:00
|
|
|
|
|
|
|
|
2018-03-06 19:27:28 +00:00
|
|
|
def _do_import(import_job, replace, use_acoustid=True):
|
2017-12-27 19:29:26 +00:00
|
|
|
from_file = bool(import_job.audio_file)
|
|
|
|
mbid = import_job.mbid
|
|
|
|
acoustid_track_id = None
|
|
|
|
duration = None
|
|
|
|
track = None
|
2018-03-06 19:27:28 +00:00
|
|
|
manager = global_preferences_registry.manager()
|
|
|
|
use_acoustid = use_acoustid and manager['providers_acoustid__api_key']
|
|
|
|
if not mbid and use_acoustid and from_file:
|
2017-12-27 19:29:26 +00:00
|
|
|
# we try to deduce mbid from acoustid
|
|
|
|
client = get_acoustid_client()
|
|
|
|
match = client.get_best_match(import_job.audio_file.path)
|
2018-03-04 17:14:37 +00:00
|
|
|
if match:
|
|
|
|
duration = match['recordings'][0]['duration']
|
|
|
|
mbid = match['recordings'][0]['id']
|
|
|
|
acoustid_track_id = match['id']
|
2017-12-27 19:29:26 +00:00
|
|
|
if mbid:
|
|
|
|
track, _ = models.Track.get_or_create_from_api(mbid=mbid)
|
2018-04-05 21:22:28 +00:00
|
|
|
elif import_job.audio_file:
|
2017-12-27 19:29:26 +00:00
|
|
|
track = import_track_data_from_path(import_job.audio_file.path)
|
2018-04-07 09:29:40 +00:00
|
|
|
elif import_job.library_track:
|
|
|
|
track = import_track_from_remote(import_job.library_track)
|
2018-04-05 21:22:28 +00:00
|
|
|
else:
|
2018-04-07 09:29:40 +00:00
|
|
|
raise ValueError(
|
|
|
|
'Not enough data to process import, '
|
|
|
|
'add a mbid, an audio file or a library track')
|
2017-12-27 19:29:26 +00:00
|
|
|
|
|
|
|
track_file = None
|
|
|
|
if replace:
|
|
|
|
track_file = track.files.first()
|
|
|
|
elif track.files.count() > 0:
|
|
|
|
if import_job.audio_file:
|
|
|
|
import_job.audio_file.delete()
|
|
|
|
import_job.status = 'skipped'
|
|
|
|
import_job.save()
|
|
|
|
return
|
|
|
|
|
|
|
|
track_file = track_file or models.TrackFile(
|
|
|
|
track=track, source=import_job.source)
|
|
|
|
track_file.acoustid_track_id = acoustid_track_id
|
|
|
|
if from_file:
|
|
|
|
track_file.audio_file = ContentFile(import_job.audio_file.read())
|
|
|
|
track_file.audio_file.name = import_job.audio_file.name
|
|
|
|
track_file.duration = duration
|
2018-04-07 09:29:40 +00:00
|
|
|
elif import_job.library_track:
|
2018-04-07 13:34:35 +00:00
|
|
|
track_file.library_track = import_job.library_track
|
2018-04-07 09:29:40 +00:00
|
|
|
track_file.mimetype = import_job.library_track.audio_mimetype
|
|
|
|
if import_job.library_track.library.download_files:
|
2018-04-06 16:49:29 +00:00
|
|
|
raise NotImplementedError()
|
|
|
|
else:
|
|
|
|
# no downloading, we hotlink
|
|
|
|
pass
|
2017-12-27 19:29:26 +00:00
|
|
|
else:
|
|
|
|
track_file.download_file()
|
|
|
|
track_file.save()
|
|
|
|
import_job.status = 'finished'
|
|
|
|
import_job.track_file = track_file
|
|
|
|
if import_job.audio_file:
|
|
|
|
# it's imported on the track, we don't need it anymore
|
|
|
|
import_job.audio_file.delete()
|
|
|
|
import_job.save()
|
|
|
|
return track.pk
|
|
|
|
|
|
|
|
|
2017-12-26 20:12:37 +00:00
|
|
|
@celery.app.task(name='ImportJob.run', bind=True)
|
2018-02-27 16:43:50 +00:00
|
|
|
@celery.require_instance(
|
|
|
|
models.ImportJob.objects.filter(
|
|
|
|
status__in=['pending', 'errored']),
|
|
|
|
'import_job')
|
2018-03-06 19:27:28 +00:00
|
|
|
def import_job_run(self, import_job, replace=False, use_acoustid=True):
|
2017-12-27 19:29:26 +00:00
|
|
|
def mark_errored():
|
|
|
|
import_job.status = 'errored'
|
2018-03-06 19:27:28 +00:00
|
|
|
import_job.save(update_fields=['status'])
|
2017-12-26 20:12:37 +00:00
|
|
|
|
2017-12-27 19:29:26 +00:00
|
|
|
try:
|
2018-03-06 19:27:28 +00:00
|
|
|
return _do_import(import_job, replace, use_acoustid=use_acoustid)
|
2017-12-26 20:12:37 +00:00
|
|
|
except Exception as exc:
|
|
|
|
if not settings.DEBUG:
|
2017-12-27 19:29:26 +00:00
|
|
|
try:
|
|
|
|
self.retry(exc=exc, countdown=30, max_retries=3)
|
|
|
|
except:
|
|
|
|
mark_errored()
|
|
|
|
raise
|
|
|
|
mark_errored()
|
2017-12-26 20:12:37 +00:00
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
@celery.app.task(name='Lyrics.fetch_content')
|
|
|
|
@celery.require_instance(models.Lyrics, 'lyrics')
|
|
|
|
def fetch_content(lyrics):
|
|
|
|
html = lyrics_utils._get_html(lyrics.url)
|
|
|
|
content = lyrics_utils.extract_content(html)
|
|
|
|
cleaned_content = lyrics_utils.clean_content(content)
|
|
|
|
lyrics.content = cleaned_content
|
|
|
|
lyrics.save(update_fields=['content'])
|