162 lines
5.5 KiB
Python
162 lines
5.5 KiB
Python
from django.shortcuts import redirect
|
|
from django.urls import reverse
|
|
from django.views.generic import TemplateView
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.db.models import Q, Count, OuterRef
|
|
from django.db.models.functions import Coalesce
|
|
from django.http import HttpResponse, Http404, StreamingHttpResponse
|
|
|
|
import aiofiles
|
|
from rest_framework.viewsets import GenericViewSet
|
|
from rest_framework import mixins
|
|
from rest_framework.response import Response
|
|
from rest_framework.decorators import action
|
|
|
|
from app.utils import StreamingZipFileResponse
|
|
from user.models import User
|
|
from .models import Torrent, File, SharedUser
|
|
from .serializers import TorrentSerializer, FileSerializer
|
|
from .utils import torrent_proceed, torrent_share
|
|
|
|
|
|
class HomeView(LoginRequiredMixin, TemplateView):
|
|
template_name = "torrent/home.html"
|
|
|
|
|
|
async def download_file(request, file_id):
|
|
user = await request.auser()
|
|
qs = File.objects.filter(
|
|
Q(torrent__user=user)
|
|
| Q(torrent__shared_users=user)
|
|
| Q(torrent__user__friends=user)
|
|
| Q(torrent__shared_users__friends=user),
|
|
torrent__transmission_data__progress__gte=100,
|
|
pk=file_id
|
|
)
|
|
|
|
try:
|
|
file = await qs.aget()
|
|
except File.DoesNotExist:
|
|
raise Http404()
|
|
else:
|
|
if request.GET.get("dl_hotfix", "0") == "1":
|
|
async def read_file():
|
|
async with aiofiles.open(file.abs_pathname, "rb") as f:
|
|
while chunk := await f.read(128 * 1024):
|
|
yield chunk
|
|
response = StreamingHttpResponse(read_file())
|
|
response["Content-Length"] = file.size
|
|
response["Content-Type"] = "application/octet-stream"
|
|
response["Content-Disposition"] = file.disposition
|
|
return response
|
|
else:
|
|
response = HttpResponse()
|
|
response["X-Accel-Redirect"] = file.accel_redirect
|
|
response["Content-Type"] = file.mime_types
|
|
response["Content-Disposition"] = file.disposition
|
|
return response
|
|
|
|
|
|
async def download_torrent(request, torrent_id):
|
|
# py version
|
|
user = await request.auser()
|
|
qs = Torrent.objects.filter(
|
|
Q(user=user)
|
|
| Q(shared_users=user)
|
|
| Q(user__friends=user)
|
|
| Q(shared_users__friends=user),
|
|
transmission_data__progress__gte=100,
|
|
pk=torrent_id
|
|
).annotate(count_files=Count("files"))
|
|
|
|
torrent = await qs.aget()
|
|
|
|
if torrent.count_files == 1:
|
|
file = await torrent.files.afirst()
|
|
return redirect(reverse("torrent:download_file", kwargs={
|
|
"file_id": file.pk
|
|
}))
|
|
|
|
response = StreamingZipFileResponse(
|
|
filename="test.zip",
|
|
file_list=[
|
|
(file.abs_pathname, file.rel_name)
|
|
async for file in torrent.files.all()
|
|
],
|
|
is_async=True
|
|
)
|
|
return response
|
|
|
|
|
|
class TorrentViewSet(mixins.CreateModelMixin,
|
|
mixins.RetrieveModelMixin,
|
|
mixins.DestroyModelMixin,
|
|
mixins.ListModelMixin,
|
|
GenericViewSet):
|
|
queryset = Torrent.objects.all().annotate(count_files=Count("files"))
|
|
serializer_class = TorrentSerializer
|
|
|
|
def get_queryset(self):
|
|
qs = super().get_queryset()
|
|
|
|
qs.filter(
|
|
Q(user=self.request.user)
|
|
| Q(shared_users=self.request.user)
|
|
| Q(user__friends=self.request.user)
|
|
| Q(shared_users__friends=self.request.user)
|
|
)
|
|
|
|
# Récupération des torrents de l'utilisateur et de ceux partagé à celui-ci (ordonné par ordre de partage ou par date d'ajout du torrent)
|
|
user_id = self.request.query_params.get("user", None)
|
|
if user_id:
|
|
qs = qs.filter(Q(user_id=user_id) | Q(shared_users=user_id))
|
|
else:
|
|
user_id = self.request.user.id
|
|
|
|
sub = SharedUser.objects.filter(torrent_id=OuterRef("pk"), user_id=user_id).values("date_created")
|
|
qs = qs.annotate(last_date=Coalesce(sub, "date_created")).order_by("-last_date")
|
|
|
|
search = self.request.query_params.get("search", None)
|
|
if search:
|
|
qs = qs.filter(name__icontains=search)
|
|
|
|
return qs
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
file = request.data["file"]
|
|
r = torrent_proceed(self.request.user, file)
|
|
if r["torrent"]:
|
|
r["torrent"] = self.get_serializer_class()(r["torrent"]).data
|
|
return Response(r)
|
|
|
|
def perform_destroy(self, instance):
|
|
instance: Torrent
|
|
if instance.user == self.request.user:
|
|
return super().perform_destroy(instance)
|
|
else:
|
|
if instance.shared_users.filter(id=self.request.user.id).exists():
|
|
instance.shared_users.remove(self.request.user)
|
|
|
|
@action(methods=["post"], detail=True)
|
|
def share(self, request, pk):
|
|
user_id = self.request.data.get("user_id")
|
|
torrent = self.get_object()
|
|
is_share_success = torrent_share(torrent=torrent, current_user=self.request.user, target_user_id=user_id)
|
|
return Response({"success": is_share_success})
|
|
|
|
@action(methods=["get"], detail=False)
|
|
def user_stats(self, request):
|
|
Torrent.objects.filter(user=self.request.user).aggregate(total_size=Sum("size"))
|
|
|
|
|
|
class FileViewSet(mixins.RetrieveModelMixin,
|
|
mixins.ListModelMixin,
|
|
GenericViewSet):
|
|
queryset = File.objects.all()
|
|
serializer_class = FileSerializer
|
|
filterset_fields = ["torrent"]
|
|
|
|
def get_queryset(self):
|
|
qs = super().get_queryset()
|
|
return qs
|