Files
oxpanel25/app/torrent/views.py
2025-04-18 17:33:48 +02:00

192 lines
6.4 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, Sum
from django.db.models.functions import Coalesce
from django.http import HttpResponse, Http404, StreamingHttpResponse
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins
from rest_framework.response import Response
from rest_framework.decorators import action
import anyio
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"
def pping(request):
return HttpResponse(str(dict(request.session)))
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
).distinct()
try:
file = await qs.aget()
except File.DoesNotExist:
raise Http404()
else:
if int(request.GET.get("dl_hotfix", 0)) == 1:
async def read_file():
async with await anyio.open_file(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 flux_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
).distinct()
try:
file = await qs.aget()
except File.DoesNotExist:
raise Http404()
else:
response = HttpResponse()
response["X-Accel-Redirect"] = file.accel_redirect
response["X-Accel-Buffering"] = "no"
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")).distinct()
torrent = await qs.aget()
if await torrent.alen_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"]
file_mode = request.data.get("file_mode", "file_object")
r = torrent_proceed(self.request.user, file, file_mode)
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