Files
oxpanel25/app/torrent/views.py
2025-03-18 18:24:14 +01:00

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