diff --git a/api/funkwhale_api/audio/serializers.py b/api/funkwhale_api/audio/serializers.py index 2f6b76442fac207a3707deb42623192a008f80bc..2e412c3e98ef89fafb158eceb084d0b5410fb395 100644 --- a/api/funkwhale_api/audio/serializers.py +++ b/api/funkwhale_api/audio/serializers.py @@ -239,6 +239,7 @@ class ChannelSerializer(serializers.ModelSerializer): actor = serializers.SerializerMethodField() attributed_to = federation_serializers.APIActorSerializer() rss_url = serializers.CharField(source="get_rss_url") + url = serializers.SerializerMethodField() class Meta: model = models.Channel @@ -250,6 +251,7 @@ class ChannelSerializer(serializers.ModelSerializer): "creation_date", "metadata", "rss_url", + "url", ] def get_artist(self, obj): @@ -269,6 +271,9 @@ class ChannelSerializer(serializers.ModelSerializer): return None return federation_serializers.APIActorSerializer(obj.actor).data + def get_url(self, obj): + return obj.actor.url + class SubscriptionSerializer(serializers.Serializer): approved = serializers.BooleanField(read_only=True) diff --git a/api/tests/audio/test_serializers.py b/api/tests/audio/test_serializers.py index add1068885b06414e93b9eb21a70914442fb9ab3..1b647389a3cedbf602d5df8ef636022ec3891d12 100644 --- a/api/tests/audio/test_serializers.py +++ b/api/tests/audio/test_serializers.py @@ -227,6 +227,7 @@ def test_channel_serializer_representation(factories, to_api_date): ).data, "metadata": {}, "rss_url": channel.get_rss_url(), + "url": channel.actor.url, } expected["artist"]["description"] = common_serializers.ContentSerializer( content @@ -249,6 +250,7 @@ def test_channel_serializer_external_representation(factories, to_api_date): ).data, "metadata": {}, "rss_url": channel.get_rss_url(), + "url": channel.actor.url, } expected["artist"]["description"] = common_serializers.ContentSerializer( content diff --git a/front/src/views/channels/DetailBase.vue b/front/src/views/channels/DetailBase.vue index ca086d5f95a7ba1ae10cd247ddbffc95db0564ce..9250cc588b9e83f7e81fbda2556644b9753da55f 100644 --- a/front/src/views/channels/DetailBase.vue +++ b/front/src/views/channels/DetailBase.vue @@ -128,6 +128,12 @@ <div class="sub header ellipsis" v-if="object.actor ":title="object.actor.full_username"> {{ object.actor.full_username }} </div> + <div v-else class="sub header ellipsis"> + <a :href="object.url || object.rss_url" rel="noopener noreferrer" target="_blank"> + <i class="external link icon"></i> + <translate :translate-params="{domain: externalDomain}" translate-context="Content/Channel/Paragraph">Mirrored from %{ domain }</translate> + </a> + </div> </div> </h1> <div class="header-buttons"> @@ -298,6 +304,12 @@ export default { } }, computed: { + externalDomain () { + let parser = document.createElement('a') + parser.href = this.object.url || this.object.rss_url + return parser.hostname + }, + isOwner () { return this.$store.state.auth.authenticated && this.object.attributed_to.full_username === this.$store.state.auth.fullUsername },