import os from urllib.parse import urlparse import factory from django.conf import settings from funkwhale_api.common import factories as common_factories from funkwhale_api.factories import NoUpdateOnCreate, registry from funkwhale_api.federation import factories as federation_factories from funkwhale_api.music import licenses from funkwhale_api.tags import factories as tags_factories from funkwhale_api.users import factories as users_factories SAMPLES_PATH = os.path.join( os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "tests", "music", ) def playable_factory(field): @factory.post_generation def inner(self, create, extracted, **kwargs): if not create: return if extracted: UploadFactory( library__privacy_level="everyone", import_status="finished", **{field: self} ) return inner def deduce_from_conf(field): @factory.lazy_attribute def inner(self): return licenses.LICENSES_BY_ID[self.code][field] return inner @registry.register class LicenseFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): code = "cc-by-4.0" url = deduce_from_conf("url") commercial = deduce_from_conf("commercial") redistribute = deduce_from_conf("redistribute") copyleft = deduce_from_conf("copyleft") attribution = deduce_from_conf("attribution") derivative = deduce_from_conf("derivative") class Meta: model = "music.License" django_get_or_create = ("code",) @registry.register class ArtistFactory( tags_factories.TaggableFactory, NoUpdateOnCreate, factory.django.DjangoModelFactory ): name = factory.Faker("name") mbid = factory.Faker("uuid4") fid = factory.Faker("federation_url") playable = playable_factory("track__album__artist_credit__artist") class Meta: model = "music.Artist" class Params: attributed = factory.Trait( attributed_to=factory.SubFactory(federation_factories.ActorFactory) ) local = factory.Trait(fid=factory.Faker("federation_url", local=True)) with_cover = factory.Trait( attachment_cover=factory.SubFactory(common_factories.AttachmentFactory) ) @registry.register class ArtistCreditFactory(factory.django.DjangoModelFactory): artist = factory.SubFactory(ArtistFactory) credit = factory.LazyAttribute(lambda obj: obj.artist.name) joinphrase = "" class Meta: model = "music.ArtistCredit" class Params: local = factory.Trait( artist=factory.SubFactory(ArtistFactory, local=True), ) @registry.register class AlbumFactory( tags_factories.TaggableFactory, NoUpdateOnCreate, factory.django.DjangoModelFactory ): title = factory.Faker("sentence", nb_words=3) mbid = factory.Faker("uuid4") release_date = factory.Faker("date_object") release_group_id = factory.Faker("uuid4") fid = factory.Faker("federation_url") playable = playable_factory("track__album") class Meta: model = "music.Album" class Params: attributed = factory.Trait( attributed_to=factory.SubFactory(federation_factories.ActorFactory) ) local = factory.Trait( fid=factory.Faker("federation_url", local=True), ) with_cover = factory.Trait( attachment_cover=factory.SubFactory(common_factories.AttachmentFactory) ) @factory.post_generation def artist_credit(self, create, extracted, **kwargs): if urlparse(self.fid).netloc == settings.FEDERATION_HOSTNAME: kwargs["artist__local"] = True if extracted: self.artist_credit.add(extracted) if create: self.artist_credit.add(ArtistCreditFactory(**kwargs)) @registry.register class TrackFactory( tags_factories.TaggableFactory, NoUpdateOnCreate, factory.django.DjangoModelFactory ): uuid = factory.Faker("uuid4") fid = factory.Faker("federation_url") title = factory.Faker("sentence", nb_words=3) mbid = factory.Faker("uuid4") album = factory.SubFactory(AlbumFactory) position = 1 playable = playable_factory("track") class Meta: model = "music.Track" class Params: attributed = factory.Trait( attributed_to=factory.SubFactory(federation_factories.ActorFactory) ) local = factory.Trait( fid=factory.Faker( "federation_url", local=True, prefix="/federation/music/tracks", obj_uuid=factory.SelfAttribute("..uuid"), ), album__local=True, ) with_cover = factory.Trait( attachment_cover=factory.SubFactory(common_factories.AttachmentFactory) ) @factory.post_generation def artist_credit(self, created, extracted, **kwargs): """ A bit intricated, because we want to be able to specify a different track artist with a fallback on album artist if nothing is specified. And handle cases where build or build_batch are used (so no db calls) """ # needed to get a primary key on the track and album objects. The primary key is needed for many_to_many if self.album: self.album.save() if not self.pk: self.save() if extracted: self.artist_credit.add(extracted) elif kwargs: if created: self.artist_credit.add(ArtistCreditFactory(**kwargs)) else: self.artist_credit.add(ArtistCreditFactory.build(**kwargs)) elif self.album: self.artist_credit.set(self.album.artist_credit.all()) if created: self.save() # The @factory.post_generation is not used because we must # not redefine the builtin `license` function. def _license_post_generation(self, created, extracted, **kwargs): if not created: return if extracted: self.license = LicenseFactory(code=extracted) self.save() license = factory.PostGeneration(_license_post_generation) @registry.register class UploadFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): fid = factory.Faker("federation_url") track = factory.SubFactory(TrackFactory) library = factory.SubFactory(federation_factories.MusicLibraryFactory) audio_file = factory.django.FileField( from_path=os.path.join(SAMPLES_PATH, "test.ogg") ) bitrate = None size = None duration = None mimetype = "audio/ogg" quality = 1 class Meta: model = "music.Upload" class Params: in_place = factory.Trait(audio_file=None, mimetype=None) playable = factory.Trait( import_status="finished", library__privacy_level="everyone" ) local = factory.Trait( fid=factory.Faker("federation_url", local=True), track__local=True, library__local=True, ) @factory.post_generation def channel(self, created, extracted, **kwargs): if not extracted: return from funkwhale_api.audio import factories as audio_factories audio_factories.ChannelFactory( library=self.library, artist=self.track.artist_credit.all()[0].artist, **kwargs ) @registry.register class UploadVersionFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): upload = factory.SubFactory(UploadFactory, bitrate=200000) bitrate = factory.SelfAttribute("upload.bitrate") mimetype = "audio/mpeg" audio_file = factory.django.FileField() size = 2000000 class Meta: model = "music.UploadVersion" class ImportBatchFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): submitted_by = factory.SubFactory(users_factories.UserFactory) class Meta: model = "music.ImportBatch" @registry.register class ImportJobFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): batch = factory.SubFactory(ImportBatchFactory) source = factory.Faker("url") mbid = factory.Faker("uuid4") replace_if_duplicate = False class Meta: model = "music.ImportJob"