aboutsummaryrefslogtreecommitdiff
path: root/services/stream
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-12-23 03:35:18 -0500
committerBobby <[email protected]>2024-12-23 03:35:18 -0500
commit4feba2452a151ed999d52d4a0d53b0b0584bf70e (patch)
treecd8474cd1287dac1839b5ceac24be987e25961cc /services/stream
parent2ab87058f41e07724757b944834da0a52de4b105 (diff)
downloadthatcomputerscientist-4feba2452a151ed999d52d4a0d53b0b0584bf70e.tar.xz
thatcomputerscientist-4feba2452a151ed999d52d4a0d53b0b0584bf70e.zip
anime streams are a thing baby
Diffstat (limited to 'services/stream')
-rw-r--r--services/stream/urls.py1
-rw-r--r--services/stream/views.py106
2 files changed, 105 insertions, 2 deletions
diff --git a/services/stream/urls.py b/services/stream/urls.py
index 4fc57ee5..aaedb926 100644
--- a/services/stream/urls.py
+++ b/services/stream/urls.py
@@ -6,4 +6,5 @@ app_name = "stream"
urlpatterns = [
path("random-song", views.random_song, name="random_song"),
path("song/<int:song_id>", views.stream_song, name="stream_song"),
+ path("anime/", views.anime_stream, name="anime_stream"),
]
diff --git a/services/stream/views.py b/services/stream/views.py
index 21e15dc1..a646d185 100644
--- a/services/stream/views.py
+++ b/services/stream/views.py
@@ -1,12 +1,18 @@
# views.py
import os
import random
-from urllib.parse import urlparse
+import re
+from urllib.parse import quote, urljoin, urlparse
from django.conf import settings
from services.stream.songs import MUSIC_FILES
import requests
-from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
+from django.http import (
+ HttpResponse,
+ HttpResponseForbidden,
+ JsonResponse,
+ StreamingHttpResponse,
+)
CDN_URL = os.getenv("CDN_URL")
MUSIC_FILES_COUNT = len(MUSIC_FILES)
@@ -60,3 +66,99 @@ def stream_song(request, song_id: int) -> HttpResponse:
return HttpResponse(status=404)
except Exception:
return HttpResponse(status=500)
+
+
+def anime_stream(request):
+ if not request.COOKIES.get("csrftoken"):
+ return HttpResponseForbidden("Invalid request")
+
+ referrer = request.META.get("HTTP_REFERER")
+ if not referrer:
+ return HttpResponseForbidden("Direct access not allowed")
+
+ parsed_uri = urlparse(referrer)
+ referrer_host = parsed_uri.netloc.split(":")[0]
+
+ if referrer_host not in settings.ALLOWED_HOSTS:
+ return HttpResponseForbidden("Access not allowed")
+
+ url = request.GET.get("url")
+
+ if not url:
+ return HttpResponse("No URL provided", status=400)
+
+ try:
+ # Make the request to the target server
+ response = requests.get(
+ url,
+ stream=True,
+ headers={
+ "User-Agent": request.headers.get("User-Agent", ""),
+ "Referer": request.headers.get("Referer", ""),
+ "Origin": request.headers.get("Origin", ""),
+ },
+ )
+
+ content_type = response.headers.get("content-type", "")
+
+ # Handle M3U8 playlists
+ if "m3u8" in content_type or url.endswith(".m3u8"):
+ content = response.text
+ base_url = url.rsplit("/", 1)[0] + "/"
+
+ # Modify the playlist URLs to go through our proxy
+ modified_content = []
+ for line in content.splitlines():
+ if line.startswith("#"):
+ modified_content.append(line)
+ elif line.strip(): # Handle content lines (URLs)
+ # Handle both absolute and relative URLs
+ if not line.startswith("http"):
+ line = urljoin(base_url, line)
+ proxy_url = f"/services/stream/anime?url={quote(line)}"
+ modified_content.append(proxy_url)
+ else:
+ modified_content.append(line)
+
+ return HttpResponse(
+ "\n".join(modified_content),
+ content_type="application/vnd.apple.mpegurl",
+ )
+
+ # Handle VTT files
+ elif url.endswith(".vtt"):
+ content = response.text
+ base_url = url.rsplit("/", 1)[0] + "/"
+
+ # Pattern to match both full URLs and relative paths with optional #xywh fragment
+ sprite_pattern = r'((?:https?://[^\s<>"]+?|[\w-]+\.(?:jpg|jpeg|png|webp))(?:#xywh=[\d,]+)?)'
+
+ def replace_url(match):
+ sprite_url = match.group(1)
+ # If it's not a full URL, join it with the base URL
+ if not sprite_url.startswith("http"):
+ sprite_url = urljoin(base_url, sprite_url)
+ return f"/watch/stream?url={quote(sprite_url)}"
+
+ # Replace all image URLs with proxied versions
+ modified_content = re.sub(sprite_pattern, replace_url, content)
+
+ return HttpResponse(modified_content, content_type="text/vtt")
+
+ # Handle images (thumbnails)
+ elif any(ext in url.lower() for ext in [".jpg", ".jpeg", ".png", ".webp"]):
+ return StreamingHttpResponse(
+ response.iter_content(chunk_size=8192),
+ content_type=response.headers.get("content-type"),
+ status=response.status_code,
+ )
+
+ # For video segments and other content, stream directly
+ return StreamingHttpResponse(
+ response.iter_content(chunk_size=8192),
+ content_type=response.headers.get("content-type"),
+ status=response.status_code,
+ )
+
+ except requests.RequestException as e:
+ return HttpResponse(f"Error proxying request: {str(e)}", status=500)