See #170: now record downloads count on tracks/uploads

This commit is contained in:
Eliot Berriot 2020-01-20 12:13:02 +01:00
parent 3674d1235d
commit b22b9c83b0
No known key found for this signature in database
GPG key ID: 6B501DFD73514E14
12 changed files with 161 additions and 18 deletions

View file

@ -6,9 +6,9 @@ from rest_framework import throttling as rest_throttling
from django.conf import settings
def get_ident(request):
if hasattr(request, "user") and request.user.is_authenticated:
return {"type": "authenticated", "id": request.user.pk}
def get_ident(user, request):
if user and user.is_authenticated:
return {"type": "authenticated", "id": user.pk}
ident = rest_throttling.BaseThrottle().get_ident(request)
return {"type": "anonymous", "id": ident}
@ -89,7 +89,7 @@ class FunkwhaleThrottle(rest_throttling.SimpleRateThrottle):
def allow_request(self, request, view):
self.request = request
self.ident = get_ident(request)
self.ident = get_ident(getattr(request, "user", None), request)
action = getattr(view, "action", "*")
view_scopes = getattr(view, "throttling_scopes", {})
if view_scopes is None:

View file

@ -135,7 +135,7 @@ class RateLimitView(views.APIView):
throttle_classes = []
def get(self, request, *args, **kwargs):
ident = throttling.get_ident(request)
ident = throttling.get_ident(getattr(request, "user", None), request)
data = {
"enabled": settings.THROTTLING_ENABLED,
"ident": ident,

View file

@ -0,0 +1,23 @@
# Generated by Django 2.2.9 on 2020-01-20 09:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('music', '0047_auto_20200116_1246'),
]
operations = [
migrations.AddField(
model_name='track',
name='downloads_count',
field=models.PositiveIntegerField(default=0),
),
migrations.AddField(
model_name='upload',
name='downloads_count',
field=models.PositiveIntegerField(default=0),
),
]

View file

@ -498,7 +498,7 @@ class Track(APIModelMixin):
on_delete=models.SET_NULL,
related_name="covered_track",
)
downloads_count = models.PositiveIntegerField(default=0)
federation_namespace = "tracks"
musicbrainz_model = "recording"
api = musicbrainz.api.recordings
@ -731,6 +731,7 @@ class Upload(models.Model):
from_activity = models.ForeignKey(
"federation.Activity", null=True, on_delete=models.SET_NULL, blank=True
)
downloads_count = models.PositiveIntegerField(default=0)
objects = UploadQuerySet.as_manager()

View file

@ -4,6 +4,11 @@ import magic
import mutagen
import pydub
from django.conf import settings
from django.core.cache import cache
from django.db.models import F
from funkwhale_api.common import throttling
from funkwhale_api.common.search import get_fts_query # noqa
from funkwhale_api.common.search import get_query # noqa
from funkwhale_api.common.search import normalize_query # noqa
@ -91,3 +96,25 @@ def transcode_file(input, output, input_format, output_format, **kwargs):
def transcode_audio(audio, output, output_format, **kwargs):
with output.open("wb"):
return audio.export(output, format=output_format, **kwargs)
def increment_downloads_count(upload, user, wsgi_request):
ident = throttling.get_ident(user=user, request=wsgi_request)
cache_key = "downloads_count:upload-{}:{}-{}".format(
upload.pk, ident["type"], ident["id"]
)
value = cache.get(cache_key)
if value:
# download already tracked
return
upload.downloads_count = F("downloads_count") + 1
upload.track.downloads_count = F("downloads_count") + 1
upload.save(update_fields=["downloads_count"])
upload.track.save(update_fields=["downloads_count"])
duration = max(upload.duration or 0, settings.MIN_DELAY_BETWEEN_DOWNLOADS_COUNT)
cache.set(cache_key, 1, duration)

View file

@ -432,6 +432,23 @@ def get_content_disposition(filename):
return "attachment; {}".format(filename)
def record_downloads(f):
def inner(*args, **kwargs):
user = kwargs.get("user")
wsgi_request = kwargs.pop("wsgi_request")
upload = kwargs.get("upload")
response = f(*args, **kwargs)
if response.status_code >= 200 and response.status_code < 400:
utils.increment_downloads_count(
upload=upload, user=user, wsgi_request=wsgi_request
)
return response
return inner
@record_downloads
def handle_serve(
upload, user, format=None, max_bitrate=None, proxy_media=True, download=True
):
@ -537,12 +554,13 @@ class ListenViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
if max_bitrate:
max_bitrate = max_bitrate * 1000
return handle_serve(
upload,
upload=upload,
user=request.user,
format=format,
max_bitrate=max_bitrate,
proxy_media=settings.PROXY_MEDIA,
download=download,
wsgi_request=request._request,
)

View file

@ -285,6 +285,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
# Subsonic clients don't expect 302 redirection unfortunately,
# So we have to proxy media files
proxy_media=True,
wsgi_request=request._request,
)
@action(detail=False, methods=["get", "post"], url_name="star", url_path="star")