mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-05 23:28:26 +02:00
Implemented followers notification on import and autoimport
This commit is contained in:
parent
adcbe8852d
commit
f31874edf5
10 changed files with 253 additions and 5 deletions
|
@ -12,6 +12,9 @@ from rest_framework.exceptions import PermissionDenied
|
|||
from dynamic_preferences.registries import global_preferences_registry
|
||||
|
||||
from funkwhale_api.common import session
|
||||
from funkwhale_api.common import utils as funkwhale_utils
|
||||
from funkwhale_api.music import models as music_models
|
||||
from funkwhale_api.music import tasks as music_tasks
|
||||
|
||||
from . import activity
|
||||
from . import keys
|
||||
|
@ -243,7 +246,7 @@ class LibraryActor(SystemActor):
|
|||
data=i, context={'library': remote_library})
|
||||
for i in items
|
||||
]
|
||||
|
||||
now = timezone.now()
|
||||
valid_serializers = []
|
||||
for s in item_serializers:
|
||||
if s.is_valid():
|
||||
|
@ -252,8 +255,30 @@ class LibraryActor(SystemActor):
|
|||
logger.debug(
|
||||
'Skipping invalid item %s, %s', s.initial_data, s.errors)
|
||||
|
||||
lts = []
|
||||
for s in valid_serializers:
|
||||
s.save()
|
||||
lts.append(s.save())
|
||||
|
||||
if remote_library.autoimport:
|
||||
batch = music_models.ImportBatch.objects.create(
|
||||
source='federation',
|
||||
)
|
||||
for lt in lts:
|
||||
if lt.creation_date < now:
|
||||
# track was already in the library, we do not trigger
|
||||
# an import
|
||||
continue
|
||||
job = music_models.ImportJob.objects.create(
|
||||
batch=batch,
|
||||
library_track=lt,
|
||||
mbid=lt.mbid,
|
||||
source=lt.url,
|
||||
)
|
||||
funkwhale_utils.on_commit(
|
||||
music_tasks.import_job_run.delay,
|
||||
import_job_id=job.pk,
|
||||
use_acoustid=False,
|
||||
)
|
||||
|
||||
|
||||
class TestActor(SystemActor):
|
||||
|
|
|
@ -97,6 +97,11 @@ class Actor(models.Model):
|
|||
if self.is_system:
|
||||
return actors.SYSTEM_ACTORS[self.preferred_username]
|
||||
|
||||
def get_approved_followers(self):
|
||||
follows = self.received_follows.filter(approved=True)
|
||||
return self.followers.filter(
|
||||
pk__in=follows.values_list('actor', flat=True))
|
||||
|
||||
|
||||
class Follow(models.Model):
|
||||
ap_type = 'Follow'
|
||||
|
|
|
@ -493,7 +493,7 @@ class ActorWebfingerSerializer(serializers.Serializer):
|
|||
|
||||
class ActivitySerializer(serializers.Serializer):
|
||||
actor = serializers.URLField()
|
||||
id = serializers.URLField()
|
||||
id = serializers.URLField(required=False)
|
||||
type = serializers.ChoiceField(
|
||||
choices=[(c, c) for c in activity.ACTIVITY_TYPES])
|
||||
object = serializers.JSONField()
|
||||
|
@ -525,6 +525,14 @@ class ActivitySerializer(serializers.Serializer):
|
|||
)
|
||||
return value
|
||||
|
||||
def to_representation(self, conf):
|
||||
d = {}
|
||||
d.update(conf)
|
||||
|
||||
if self.context.get('include_ap_context', True):
|
||||
d['@context'] = AP_CONTEXT
|
||||
return d
|
||||
|
||||
|
||||
class ObjectSerializer(serializers.Serializer):
|
||||
id = serializers.URLField()
|
||||
|
|
|
@ -81,6 +81,9 @@ class ImportBatchFactory(factory.django.DjangoModelFactory):
|
|||
submitted_by=None,
|
||||
source='federation',
|
||||
)
|
||||
finished = factory.Trait(
|
||||
status='finished',
|
||||
)
|
||||
|
||||
|
||||
@registry.register
|
||||
|
@ -98,6 +101,10 @@ class ImportJobFactory(factory.django.DjangoModelFactory):
|
|||
library_track=factory.SubFactory(LibraryTrackFactory),
|
||||
batch=factory.SubFactory(ImportBatchFactory, federation=True),
|
||||
)
|
||||
finished = factory.Trait(
|
||||
status='finished',
|
||||
track_file=factory.SubFactory(TrackFileFactory),
|
||||
)
|
||||
|
||||
|
||||
@registry.register(name='music.FileImportJob')
|
||||
|
|
|
@ -505,8 +505,17 @@ class ImportBatch(models.Model):
|
|||
return str(self.pk)
|
||||
|
||||
def update_status(self):
|
||||
old_status = self.status
|
||||
self.status = utils.compute_status(self.jobs.all())
|
||||
self.save(update_fields=['status'])
|
||||
if self.status != old_status and self.status == 'finished':
|
||||
from . import tasks
|
||||
tasks.import_batch_notify_followers.delay(import_batch_id=self.pk)
|
||||
|
||||
def get_federation_url(self):
|
||||
return federation_utils.full_url(
|
||||
'/federation/music/import/batch/{}'.format(self.uuid)
|
||||
)
|
||||
|
||||
|
||||
class ImportJob(models.Model):
|
||||
|
|
|
@ -2,6 +2,10 @@ from django.core.files.base import ContentFile
|
|||
|
||||
from dynamic_preferences.registries import global_preferences_registry
|
||||
|
||||
from funkwhale_api.federation import activity
|
||||
from funkwhale_api.federation import actors
|
||||
from funkwhale_api.federation import models as federation_models
|
||||
from funkwhale_api.federation import serializers as federation_serializers
|
||||
from funkwhale_api.taskapp import celery
|
||||
from funkwhale_api.providers.acoustid import get_acoustid_client
|
||||
from funkwhale_api.providers.audiofile.tasks import import_track_data_from_path
|
||||
|
@ -128,6 +132,7 @@ def _do_import(import_job, replace, use_acoustid=True):
|
|||
# it's imported on the track, we don't need it anymore
|
||||
import_job.audio_file.delete()
|
||||
import_job.save()
|
||||
|
||||
return track.pk
|
||||
|
||||
|
||||
|
@ -162,3 +167,44 @@ def fetch_content(lyrics):
|
|||
cleaned_content = lyrics_utils.clean_content(content)
|
||||
lyrics.content = cleaned_content
|
||||
lyrics.save(update_fields=['content'])
|
||||
|
||||
|
||||
@celery.app.task(name='music.import_batch_notify_followers')
|
||||
@celery.require_instance(
|
||||
models.ImportBatch.objects.filter(status='finished'), 'import_batch')
|
||||
def import_batch_notify_followers(import_batch):
|
||||
if not settings.FEDERATION_ENABLED:
|
||||
return
|
||||
|
||||
if import_batch.source == 'federation':
|
||||
return
|
||||
|
||||
library_actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
|
||||
followers = library_actor.get_approved_followers()
|
||||
jobs = import_batch.jobs.filter(
|
||||
status='finished',
|
||||
library_track__isnull=True,
|
||||
track_file__isnull=False,
|
||||
).select_related(
|
||||
'track_file__track__artist',
|
||||
'track_file__track__album__artist',
|
||||
)
|
||||
track_files = [job.track_file for job in jobs]
|
||||
collection = federation_serializers.CollectionSerializer({
|
||||
'actor': library_actor,
|
||||
'id': import_batch.get_federation_url(),
|
||||
'items': track_files,
|
||||
'item_serializer': federation_serializers.AudioSerializer
|
||||
}).data
|
||||
for f in followers:
|
||||
create = federation_serializers.ActivitySerializer(
|
||||
{
|
||||
'type': 'Create',
|
||||
'id': collection['id'],
|
||||
'object': collection,
|
||||
'actor': library_actor.url,
|
||||
'to': [f.url],
|
||||
}
|
||||
).data
|
||||
|
||||
activity.deliver(create, on_behalf_of=library_actor, to=[f.url])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue