aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-12-21 13:22:03 -0500
committerBobby <[email protected]>2024-12-21 13:22:03 -0500
commit96f26bf37e72dd64fff10708fffe168a6ee10e18 (patch)
tree7465824b569b0e124eb4e095d3171da68ad90865
parentb453706835fcb5fe960375c7101074f3bb9c1c7a (diff)
downloadthatcomputerscientist-96f26bf37e72dd64fff10708fffe168a6ee10e18.tar.xz
thatcomputerscientist-96f26bf37e72dd64fff10708fffe168a6ee10e18.zip
proteccc stream
-rw-r--r--.gitmodules3
-rw-r--r--apps/anime/views.py153
-rw-r--r--middleware/i18nmiddleware.py8
-rw-r--r--services/stream/views.py48
m---------static/js/MathJax0
-rw-r--r--thatcomputerscientist/settings.py9
6 files changed, 120 insertions, 101 deletions
diff --git a/.gitmodules b/.gitmodules
index 09a0cde3..e69de29b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "static/js/MathJax"]
- path = static/js/MathJax
- url = https://github.com/mathjax/MathJax.git
diff --git a/apps/anime/views.py b/apps/anime/views.py
index 6b976391..c8a15b92 100644
--- a/apps/anime/views.py
+++ b/apps/anime/views.py
@@ -2,7 +2,9 @@ import os
from django.urls import reverse
import requests
from django.shortcuts import redirect, render
-
+from django.views.decorators.cache import cache_page
+from functools import wraps
+from django.core.cache import cache
from thatcomputerscientist.utils import i18npatterns
genres = [
@@ -37,30 +39,29 @@ sortings = [
]
ANIME_PROVIDER_MAP = {}
+CONSUMET_BASE_URL = os.getenv("CONSUMET_URL")
def get_anime(anime_id, dub=False):
- if anime_id in ANIME_PROVIDER_MAP:
- provider = ANIME_PROVIDER_MAP[anime_id]
- else:
- provider = "zoro"
-
- dub = "true" if dub else "false"
- base_url = f"{os.getenv('CONSUMET_URL')}/meta/anilist/info/{anime_id}"
- params = {"provider": provider, "dub": dub}
+ provider = ANIME_PROVIDER_MAP.get(anime_id, "zoro")
+ params = {"dub": "true"} if dub else {}
+ params.update({"provider": provider} if provider == "zoro" else {})
- response = requests.get(base_url, params=params)
+ response = requests.get(
+ f"{CONSUMET_BASE_URL}/meta/anilist/info/{anime_id}", params=params
+ )
data = response.json()
+
if (
- (not data.get("episodes") or len(data.get("episodes")) == 0)
+ not data.get("episodes")
and provider == "zoro"
and data.get("status") != "Not yet aired"
):
ANIME_PROVIDER_MAP[anime_id] = "gogoanime"
- return get_anime(anime_id)
- else:
- ANIME_PROVIDER_MAP[anime_id] = provider
- return data
+ return get_anime(anime_id, dub)
+
+ ANIME_PROVIDER_MAP[anime_id] = provider
+ return data
def sort_mapper(sort_by, order):
@@ -77,14 +78,7 @@ def sort_mapper(sort_by, order):
if sort_by not in sort_mappings or order not in ["asc", "desc"]:
return None
- sort_value = sort_mappings[sort_by]
- order_suffix = "" if order == "asc" else "_DESC"
-
- return f"{sort_value}{order_suffix}"
-
-
-def bracketed_string(string):
- return f'["{string}"]'
+ return f"{sort_mappings[sort_by]}{'_DESC' if order == 'desc' else ''}"
def anime_results(
@@ -97,37 +91,46 @@ def anime_results(
"finished",
"hiatus",
]
+ params = {
+ "page": page,
+ "perPage": per_page,
+ "type": "ANIME",
+ **({"query": query} if query else {}),
+ **({"sort": f'["{sort_mapper(sort, order)}"]'} if sort and order else {}),
+ **({"genres": f'["{genre}"]'} if genre else {}),
+ **({"status": status.upper()} if status in supported_status else {}),
+ }
- if status and status not in supported_status:
- status = ""
+ response = requests.get(
+ f"{CONSUMET_BASE_URL}/meta/anilist/advanced-search", params=params
+ )
+ return response.json()
- base_url = f"{os.getenv('CONSUMET_URL')}/meta/anilist/advanced-search"
- params = {"page": page, "perPage": per_page, "type": "ANIME"}
- if query:
- params["query"] = query
+def cache_anime_page(timeout=60 * 15):
+ def decorator(view_func):
+ @wraps(view_func)
+ def _wrapped_view(request, anime_id, e=None, *args, **kwargs):
+ cache_key = f"anime_page:{anime_id}:ep{e}:dub{request.COOKIES.get('anime_dub', False)}"
+ cached_response = cache.get(cache_key)
- if sort and order:
- sort_value = sort_mapper(sort, order)
- if sort_value:
- params["sort"] = bracketed_string(sort_value)
+ if cached_response:
+ return cached_response
- if genre:
- params["genres"] = bracketed_string(genre)
+ response = view_func(request, anime_id, e, *args, **kwargs)
+ if response.status_code == 200:
+ cache.set(cache_key, response, timeout)
+ return response
- if status:
- params["status"] = status.upper()
+ return _wrapped_view
- response = requests.get(base_url, params=params)
- return response.json()
+ return decorator
+@cache_page(60 * 15)
def home(request):
- META = {
- "title": "Anime: Home",
- }
LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE)
- request.meta.update(META)
+ request.meta.update({"title": "Anime: Home"})
context = {
"genres": genres,
@@ -139,72 +142,58 @@ def home(request):
sort="popularity", status="releasing", per_page=8
),
}
-
return render(request, f"{LANGUAGE_CODE}/anime/home.html", context)
def search(request):
- # Get search parameters
query = request.GET.get("q", "")
- genre = request.GET.get("genre", "")
- sort = request.GET.get("sort", "popularity")
- order = request.GET.get("order", "desc")
- page = int(request.GET.get("page", 1))
-
- META = {
- "title": f"Anime: Search",
- }
- if query:
- META["title"] = f"Anime: Search Results for {query}"
LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE)
- request.meta.update(META)
+ request.meta.update(
+ {"title": f"Anime: Search Results for {query}" if query else "Anime: Search"}
+ )
- # Get search results
search_results = anime_results(
- query=query, genre=genre, sort=sort, order=order, page=page, per_page=32
+ query=query,
+ genre=request.GET.get("genre", ""),
+ sort=request.GET.get("sort", "popularity"),
+ order=request.GET.get("order", "desc"),
+ page=int(request.GET.get("page", 1)),
+ per_page=32,
)
context = {
"genres": genres,
"sortings": sortings,
"search_results": search_results,
- "current_page": page,
+ "current_page": int(request.GET.get("page", 1)),
"total_pages": search_results.get("totalPages", 1),
"total_results": search_results.get("totalResults", 0),
}
-
return render(request, f"{LANGUAGE_CODE}/anime/search.html", context)
+@cache_anime_page(timeout=60 * 15)
def anime(request, anime_id, e=None):
- dub = request.COOKIES.get("anime_dub", False)
- anime_data = get_anime(anime_id, dub)
-
- if len(anime_data.get("episodes")) > 0:
- episode_numbers = [
- int(episode.get("number")) for episode in anime_data.get("episodes")
- ]
+ anime_data = get_anime(anime_id, request.COOKIES.get("anime_dub", False))
+ episode_numbers = [
+ int(episode.get("number")) for episode in anime_data.get("episodes", [])
+ ]
+ if episode_numbers:
if not e:
- e = episode_numbers[0]
return redirect(
- reverse("anime:anime", kwargs={"anime_id": anime_id, "e": e})
+ reverse(
+ "anime:anime",
+ kwargs={"anime_id": anime_id, "e": episode_numbers[0]},
+ )
)
-
- e = int(e)
- if e not in episode_numbers:
+ if int(e) not in episode_numbers:
return redirect(
reverse("anime:anime", kwargs={"anime_id": anime_id, "e": 1})
)
- META = {
- "title": f"Anime: {anime_data.get('title').get('romaji')}",
- }
LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE)
- request.meta.update(META)
-
- context = {
- "anime": anime_data,
- }
-
- return render(request, f"{LANGUAGE_CODE}/anime/anime.html", context)
+ request.meta.update(
+ {"title": f"Anime: {anime_data.get('title', {}).get('romaji')}"}
+ )
+ return render(request, f"{LANGUAGE_CODE}/anime/anime.html", {"anime": anime_data})
diff --git a/middleware/i18nmiddleware.py b/middleware/i18nmiddleware.py
index b0e7e077..8777491d 100644
--- a/middleware/i18nmiddleware.py
+++ b/middleware/i18nmiddleware.py
@@ -1,14 +1,12 @@
from django.utils.deprecation import MiddlewareMixin
+from django.utils.translation import activate
class I18NMiddleware(MiddlewareMixin):
def process_request(self, request):
- language = request.COOKIES.get("site_language")
- if language:
- request.LANGUAGE_CODE = language
- else:
- request.LANGUAGE_CODE = "en"
+ language = request.COOKIES.get("site_language", "en")
request.LANGUAGE_CODE = language
+ activate(language)
def process_response(self, request, response):
if not request.COOKIES.get("site_language"):
diff --git a/services/stream/views.py b/services/stream/views.py
index da1ff6dc..21e15dc1 100644
--- a/services/stream/views.py
+++ b/services/stream/views.py
@@ -1,10 +1,12 @@
# views.py
import os
import random
-from hashlib import md5
+from urllib.parse import urlparse
+
+from django.conf import settings
from services.stream.songs import MUSIC_FILES
import requests
-from django.http import HttpResponse, JsonResponse
+from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
CDN_URL = os.getenv("CDN_URL")
MUSIC_FILES_COUNT = len(MUSIC_FILES)
@@ -24,11 +26,37 @@ def random_song(request) -> JsonResponse:
def stream_song(request, song_id: int) -> HttpResponse:
- song = MUSIC_FILES[song_id - 1]
- stream_url = get_stream_url(song["songName"])
- response = requests.get(stream_url, stream=True)
-
- return HttpResponse(
- response.raw.read(),
- content_type=response.headers.get("Content-Type", "audio/mpeg"),
- )
+ 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")
+
+ try:
+ song = MUSIC_FILES[song_id - 1]
+ stream_url = get_stream_url(song["songName"])
+ response = requests.get(stream_url, stream=True)
+
+ if response.status_code != 200:
+ return HttpResponse(status=response.status_code)
+
+ return HttpResponse(
+ response.raw.read(),
+ content_type=response.headers.get("Content-Type", "audio/mpeg"),
+ headers={
+ "Content-Disposition": f"attachment; filename={song['songName']}.mp3",
+ "X-Frame-Options": "DENY",
+ "X-Content-Type-Options": "nosniff",
+ },
+ )
+ except (IndexError, KeyError):
+ return HttpResponse(status=404)
+ except Exception:
+ return HttpResponse(status=500)
diff --git a/static/js/MathJax b/static/js/MathJax
deleted file mode 160000
-Subproject 6273842a9746731b9ecca0de18ec9fd50a36df9
diff --git a/thatcomputerscientist/settings.py b/thatcomputerscientist/settings.py
index 97c05169..917a8109 100644
--- a/thatcomputerscientist/settings.py
+++ b/thatcomputerscientist/settings.py
@@ -44,13 +44,20 @@ SECRET_KEY = os.getenv("AUTHORIZATION_STRING")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True if os.getenv("ENVIRONMENT") == "development" else False
-ALLOWED_HOSTS = ["*"]
+ALLOWED_HOSTS = [
+ "shi.foo",
+ "www.shi.foo",
+ "thatcomputerscientist.com",
+ "www.thatcomputerscientist.com",
+] + (["localhost", "127.0.0.1"] if DEBUG else [])
+
CSRF_TRUSTED_ORIGINS = [
"https://*.thatcomputerscientist.com",
"http://*.thatcomputerscientist.com",
"https://*.shi.foo",
"http://localhost",
]
+
DOMAIN_NAME = "shi.foo"
SESSION_COOKIE_DOMAIN = (
os.getenv("DOMAIN") if os.getenv("ENVIRONMENT") == "development" else ".shi.foo"