発散解像度 -divergence resolution-

Signed-off-by: Shin'ya Minazuki <shinyoukai@laidback.moe>
This commit is contained in:
Shin'ya Minazuki 2026-01-25 21:15:56 +01:00
commit 01bb65f8da
457 changed files with 929 additions and 602 deletions

View file

View file

@ -0,0 +1,16 @@
from funkwhale_api.activity import record
from funkwhale_api.common import channels
from . import serializers
record.registry.register_serializer(serializers.ListeningActivitySerializer)
@record.registry.register_consumer("history.Listening")
def broadcast_listening_to_instance_activity(data, obj):
if obj.user.privacy_level not in ["instance", "everyone"]:
return
channels.group_send(
"instance_activity", {"type": "event.send", "text": "", "data": data}
)

View file

@ -0,0 +1,10 @@
from funkwhale_api.common import admin
from . import models
@admin.register(models.Listening)
class ListeningAdmin(admin.ModelAdmin):
list_display = ["track", "creation_date", "user", "session_key"]
search_fields = ["track__name", "user__username"]
list_select_related = ["user", "track"]

View file

@ -0,0 +1,14 @@
import factory
from funkwhale_api.factories import NoUpdateOnCreate, registry
from funkwhale_api.music import factories
from funkwhale_api.users.factories import UserFactory
@registry.register
class ListeningFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
user = factory.SubFactory(UserFactory)
track = factory.SubFactory(factories.TrackFactory)
class Meta:
model = "history.Listening"

View file

@ -0,0 +1,19 @@
import django_filters
from funkwhale_api.common import filters as common_filters
from funkwhale_api.moderation import filters as moderation_filters
from . import models
class ListeningFilter(moderation_filters.HiddenContentFilterSet):
username = django_filters.CharFilter("user__username")
domain = django_filters.CharFilter("user__actor__domain_id")
scope = common_filters.ActorScopeFilter(actor_field="user__actor", distinct=True)
class Meta:
model = models.Listening
hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG[
"LISTENING"
]
fields = []

View file

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
("music", "0008_auto_20160529_1456"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Listening",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
primary_key=True,
serialize=False,
auto_created=True,
),
),
(
"end_date",
models.DateTimeField(
null=True, blank=True, default=django.utils.timezone.now
),
),
(
"session_key",
models.CharField(null=True, blank=True, max_length=100),
),
(
"track",
models.ForeignKey(
related_name="listenings",
to="music.Track",
on_delete=models.CASCADE,
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
related_name="listenings",
to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
),
),
],
options={"ordering": ("-end_date",)},
)
]

View file

@ -0,0 +1,17 @@
# Generated by Django 2.0.3 on 2018-03-25 14:33
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [("history", "0001_initial")]
operations = [
migrations.AlterModelOptions(
name="listening", options={"ordering": ("-creation_date",)}
),
migrations.RenameField(
model_name="listening", old_name="end_date", new_name="creation_date"
),
]

View file

@ -0,0 +1,25 @@
from django.db import models
from django.utils import timezone
from funkwhale_api.music.models import Track
class Listening(models.Model):
creation_date = models.DateTimeField(default=timezone.now, null=True, blank=True)
track = models.ForeignKey(
Track, related_name="listenings", on_delete=models.CASCADE
)
user = models.ForeignKey(
"users.User",
related_name="listenings",
null=True,
blank=True,
on_delete=models.CASCADE,
)
session_key = models.CharField(max_length=100, null=True, blank=True)
class Meta:
ordering = ("-creation_date",)
def get_activity_url(self):
return f"{self.user.get_activity_url()}/listenings/tracks/{self.pk}"

View file

@ -0,0 +1,58 @@
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from funkwhale_api.activity import serializers as activity_serializers
from funkwhale_api.federation import serializers as federation_serializers
from funkwhale_api.music.serializers import TrackActivitySerializer, TrackSerializer
from funkwhale_api.users.serializers import UserActivitySerializer, UserBasicSerializer
from . import models
class ListeningActivitySerializer(activity_serializers.ModelSerializer):
type = serializers.SerializerMethodField()
object = TrackActivitySerializer(source="track")
actor = UserActivitySerializer(source="user")
published = serializers.DateTimeField(source="creation_date")
class Meta:
model = models.Listening
fields = ["id", "local_id", "object", "type", "actor", "published"]
def get_actor(self, obj):
return UserActivitySerializer(obj.user).data
def get_type(self, obj):
return "Listen"
class ListeningSerializer(serializers.ModelSerializer):
track = TrackSerializer(read_only=True)
user = UserBasicSerializer(read_only=True)
actor = serializers.SerializerMethodField()
class Meta:
model = models.Listening
fields = ("id", "user", "track", "creation_date", "actor")
def create(self, validated_data):
validated_data["user"] = self.context["user"]
return super().create(validated_data)
@extend_schema_field(federation_serializers.APIActorSerializer)
def get_actor(self, obj):
actor = obj.user.actor
if actor:
return federation_serializers.APIActorSerializer(actor).data
class ListeningWriteSerializer(serializers.ModelSerializer):
class Meta:
model = models.Listening
fields = ("id", "user", "track", "creation_date")
def create(self, validated_data):
validated_data["user"] = self.context["user"]
return super().create(validated_data)

View file

@ -0,0 +1,8 @@
from funkwhale_api.common import routers
from . import views
router = routers.OptionalSlashRouter()
router.register(r"listenings", views.ListeningViewSet, "listenings")
urlpatterns = router.urls

View file

@ -0,0 +1,64 @@
from django.db.models import Prefetch
from rest_framework import mixins, viewsets
from config import plugins
from funkwhale_api.activity import record
from funkwhale_api.common import fields, permissions
from funkwhale_api.music import utils as music_utils
from funkwhale_api.music.models import Track
from funkwhale_api.users.oauth import permissions as oauth_permissions
from . import filters, models, serializers
class ListeningViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet,
):
serializer_class = serializers.ListeningSerializer
queryset = models.Listening.objects.all().select_related(
"user__actor__attachment_icon"
)
permission_classes = [
oauth_permissions.ScopePermission,
permissions.OwnerPermission,
]
required_scope = "listenings"
anonymous_policy = "setting"
owner_checks = ["write"]
filterset_class = filters.ListeningFilter
def get_serializer_class(self):
if self.request.method.lower() in ["head", "get", "options"]:
return serializers.ListeningSerializer
return serializers.ListeningWriteSerializer
def perform_create(self, serializer):
r = super().perform_create(serializer)
plugins.trigger_hook(
plugins.LISTENING_CREATED,
listening=serializer.instance,
confs=plugins.get_confs(self.request.user),
)
record.send(serializer.instance)
return r
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.filter(
fields.privacy_level_query(self.request.user, "user__privacy_level")
)
tracks = Track.objects.with_playable_uploads(
music_utils.get_actor_from_request(self.request)
).select_related(
"artist", "album__artist", "attributed_to", "artist__attachment_cover"
)
return queryset.prefetch_related(Prefetch("track", queryset=tracks))
def get_serializer_context(self):
context = super().get_serializer_context()
context["user"] = self.request.user
return context