示例#1
0
    def create(self, validated_data):
        from . import views

        cover = validated_data.pop("cover", None)
        description = validated_data.get("description")
        artist = music_models.Artist.objects.create(
            attributed_to=validated_data["attributed_to"],
            name=validated_data["name"],
            content_category=validated_data["content_category"],
            attachment_cover=cover,
        )
        common_utils.attach_content(artist, "description", description)

        if validated_data.get("tags", []):
            tags_models.set_tags(artist, *validated_data["tags"])

        channel = models.Channel(
            artist=artist,
            attributed_to=validated_data["attributed_to"],
            metadata=validated_data["metadata"],
        )
        channel.actor = models.generate_actor(
            validated_data["username"], name=validated_data["name"],
        )

        channel.library = music_models.Library.objects.create(
            name=channel.actor.preferred_username,
            privacy_level="everyone",
            actor=validated_data["attributed_to"],
        )
        channel.save()
        channel = views.ChannelViewSet.queryset.get(pk=channel.pk)
        return channel
示例#2
0
def test_set_tags_honor_TAGS_MAX_BY_OBJ(factories, max, tags, expected,
                                        settings):
    settings.TAGS_MAX_BY_OBJ = max
    obj = factories["music.Artist"]()

    models.set_tags(obj, *tags)

    assert sorted(obj.tagged_items.values_list("tag__name",
                                               flat=True)) == expected
示例#3
0
 def create(self, validated_data):
     instance = models.Album.objects.create(
         attributed_to=self.context["user"].actor,
         artist=validated_data["artist"],
         release_date=validated_data.get("release_date"),
         title=validated_data["title"],
         attachment_cover=validated_data.get("cover"),
     )
     common_utils.attach_content(
         instance, "description", validated_data.get("description")
     )
     tag_models.set_tags(instance, *(validated_data.get("tags", []) or []))
     return instance
示例#4
0
def test_set_tags(factories, existing, given, expected):
    obj = factories["music.Artist"]()
    for tag in existing:
        factories["tags.TaggedItem"](content_object=obj, tag__name=tag)

    models.set_tags(obj, *given)

    tagged_items = models.TaggedItem.objects.all()

    assert tagged_items.count() == len(expected)
    for tag in expected:
        match = tagged_items.get(tag__name=tag)
        assert match.content_object == obj
示例#5
0
def update_track_metadata(audio_metadata, track):
    serializer = metadata.TrackMetadataSerializer(data=audio_metadata)
    serializer.is_valid(raise_exception=True)
    new_data = serializer.validated_data

    to_update = [
        ("track", track, lambda data: data),
        ("album", track.album, lambda data: data["album"]),
        ("artist", track.artist, lambda data: data["artists"][0]),
        (
            "album_artist",
            track.album.artist if track.album else None,
            lambda data: data["album"]["artists"][0],
        ),
    ]
    for id, obj, data_getter in to_update:
        if not obj:
            continue
        obj_updated_fields = []
        try:
            obj_data = data_getter(new_data)
        except IndexError:
            continue
        for field, config in UPDATE_CONFIG[id].items():
            getter = config.get(
                "getter", lambda data, field: data[config.get("field", field)])
            try:
                new_value = getter(obj_data, field)
            except KeyError:
                continue
            old_value = getattr(obj, field)
            if new_value == old_value:
                continue
            obj_updated_fields.append(field)
            setattr(obj, field, new_value)

        if obj_updated_fields:
            obj.save(update_fields=obj_updated_fields)

    tags_models.set_tags(track, *new_data.get("tags", []))

    if track.album and "album" in new_data and new_data["album"].get(
            "cover_data"):
        common_utils.attach_file(track.album, "attachment_cover",
                                 new_data["album"].get("cover_data"))
示例#6
0
    def update(self, obj, validated_data):
        if validated_data.get("tags") is not None:
            tags_models.set_tags(obj.artist, *validated_data["tags"])
        actor_update_fields = []
        artist_update_fields = []

        obj.metadata = validated_data["metadata"]
        obj.save(update_fields=["metadata"])

        if "description" in validated_data:
            common_utils.attach_content(
                obj.artist, "description", validated_data["description"]
            )

        if "name" in validated_data:
            actor_update_fields.append(("name", validated_data["name"]))
            artist_update_fields.append(("name", validated_data["name"]))

        if "content_category" in validated_data:
            artist_update_fields.append(
                ("content_category", validated_data["content_category"])
            )

        if "cover" in validated_data:
            artist_update_fields.append(("attachment_cover", validated_data["cover"]))

        if actor_update_fields:
            for field, value in actor_update_fields:
                setattr(obj.actor, field, value)
            obj.actor.save(update_fields=[f for f, _ in actor_update_fields])

        if artist_update_fields:
            for field, value in artist_update_fields:
                setattr(obj.artist, field, value)
            obj.artist.save(update_fields=[f for f, _ in artist_update_fields])

        return obj
示例#7
0
    def save(self, channel, existing_uploads=[], **track_defaults):
        validated_data = self.validated_data
        categories = validated_data.get("tags", {})
        expected_uuid = uuid.uuid3(
            uuid.NAMESPACE_URL, "rss://{}-{}".format(channel.pk, validated_data["id"])
        )
        existing_upload = get_cached_upload(existing_uploads, expected_uuid)
        if existing_upload:
            existing_track = existing_upload.track
        else:
            existing_track = (
                music_models.Track.objects.filter(
                    uuid=expected_uuid, artist__channel=channel
                )
                .select_related("description", "attachment_cover")
                .first()
            )
            if existing_track:
                existing_upload = existing_track.uploads.filter(
                    library=channel.library
                ).first()

        track_defaults = track_defaults
        track_defaults.update(
            {
                "disc_number": validated_data.get("itunes_season", 1) or 1,
                "position": validated_data.get("itunes_episode", 1) or 1,
                "title": validated_data["title"][
                    : music_models.MAX_LENGTHS["TRACK_TITLE"]
                ],
                "artist": channel.artist,
            }
        )
        if "rights" in validated_data:
            track_defaults["copyright"] = validated_data["rights"][
                : music_models.MAX_LENGTHS["COPYRIGHT"]
            ]

        if "published_parsed" in validated_data:
            track_defaults["creation_date"] = datetime.datetime.fromtimestamp(
                time.mktime(validated_data["published_parsed"])
            ).replace(tzinfo=pytz.utc)

        upload_defaults = {
            "source": validated_data["links"]["audio"]["source"],
            "size": validated_data["links"]["audio"]["size"],
            "mimetype": validated_data["links"]["audio"]["mimetype"],
            "duration": validated_data.get("itunes_duration") or None,
            "import_status": "finished",
            "library": channel.library,
        }
        if existing_track:
            track_kwargs = {"pk": existing_track.pk}
            upload_kwargs = {"track": existing_track}
        else:
            track_kwargs = {"pk": None}
            track_defaults["uuid"] = expected_uuid
            upload_kwargs = {"pk": None}

        if existing_upload and existing_upload.source != upload_defaults["source"]:
            # delete existing upload, the url to the audio file has changed
            existing_upload.delete()

        # create/update the track
        track, created = music_models.Track.objects.update_or_create(
            **track_kwargs, defaults=track_defaults,
        )
        # optimisation for reducing SQL queries, because we cannot use select_related with
        # update or create, so we restore the cache by hand
        if existing_track:
            for field in ["attachment_cover", "description"]:
                cached_id_value = getattr(existing_track, "{}_id".format(field))
                new_id_value = getattr(track, "{}_id".format(field))
                if new_id_value and cached_id_value == new_id_value:
                    setattr(track, field, getattr(existing_track, field))

        cover = validated_data.get("image")

        if cover:
            common_utils.attach_file(track, "attachment_cover", cover)
        tags = categories.get("tags", [])

        if tags:
            tags_models.set_tags(track, *tags)

        summary = validated_data.get("summary_detail")
        if summary:
            common_utils.attach_content(track, "description", summary)

        if created:
            upload_defaults["track"] = track

        # create/update the upload
        upload, created = music_models.Upload.objects.update_or_create(
            **upload_kwargs, defaults=upload_defaults
        )

        return upload
示例#8
0
    def save(self, rss_url):
        validated_data = self.validated_data
        # because there may be redirections from the original feed URL
        real_rss_url = validated_data.get("atom_link", rss_url) or rss_url
        service_actor = actors.get_service_actor()
        author = validated_data.get("author_detail", {})
        categories = validated_data.get("tags", {})
        metadata = {
            "explicit": validated_data.get("itunes_explicit", False),
            "copyright": validated_data.get("rights"),
            "owner_name": author.get("name"),
            "owner_email": author.get("email"),
            "itunes_category": categories.get("parent"),
            "itunes_subcategory": categories.get("child"),
            "language": validated_data.get("language"),
        }
        public_url = validated_data["link"]
        existing = (
            models.Channel.objects.external_rss()
            .filter(
                Q(rss_url=real_rss_url) | Q(rss_url=rss_url) | Q(actor__url=public_url)
            )
            .first()
        )
        channel_defaults = {
            "rss_url": real_rss_url,
            "metadata": metadata,
        }
        if existing:
            artist_kwargs = {"channel": existing}
            actor_kwargs = {"channel": existing}
            actor_defaults = {"url": public_url}
        else:
            artist_kwargs = {"pk": None}
            actor_kwargs = {"pk": None}
            preferred_username = "******".format(uuid.uuid4())
            actor_defaults = {
                "preferred_username": preferred_username,
                "type": "Application",
                "domain": service_actor.domain,
                "url": public_url,
                "fid": federation_utils.full_url(
                    reverse(
                        "federation:actors-detail",
                        kwargs={"preferred_username": preferred_username},
                    )
                ),
            }
            channel_defaults["attributed_to"] = service_actor

        actor_defaults["last_fetch_date"] = timezone.now()

        # create/update the artist profile
        artist, created = music_models.Artist.objects.update_or_create(
            **artist_kwargs,
            defaults={
                "attributed_to": service_actor,
                "name": validated_data["title"][
                    : music_models.MAX_LENGTHS["ARTIST_NAME"]
                ],
                "content_category": "podcast",
            },
        )

        cover = validated_data.get("image")

        if cover:
            common_utils.attach_file(artist, "attachment_cover", cover)
        tags = categories.get("tags", [])

        if tags:
            tags_models.set_tags(artist, *tags)

        summary = validated_data.get("summary_detail")
        if summary:
            common_utils.attach_content(artist, "description", summary)

        if created:
            channel_defaults["artist"] = artist

        # create/update the actor
        actor, created = federation_models.Actor.objects.update_or_create(
            **actor_kwargs, defaults=actor_defaults
        )
        if created:
            channel_defaults["actor"] = actor

        # create the library
        if not existing:
            channel_defaults["library"] = music_models.Library.objects.create(
                actor=service_actor,
                privacy_level=settings.PODCASTS_THIRD_PARTY_VISIBILITY,
                name=actor_defaults["preferred_username"],
            )

        # create/update the channel
        channel, created = models.Channel.objects.update_or_create(
            pk=existing.pk if existing else None, defaults=channel_defaults,
        )
        return channel
示例#9
0
 def update(self, instance, validated_data):
     tags = validated_data.pop("tags", NOOP)
     r = super().update(instance, validated_data)
     if tags != NOOP:
         tags_models.set_tags(instance, *tags)
     return r