summaryrefslogtreecommitdiffstats
path: root/mediaproxy
diff options
context:
space:
mode:
authorAndrew Godwin2022-12-10 12:16:08 -0700
committerAndrew Godwin2022-12-10 12:16:08 -0700
commit3595af7bd239f3843aff3ae06df8932cff23173d (patch)
tree84b8a0432fb89f253808be11275e2f78fc57bf42 /mediaproxy
parent9a978786d4eac0139b5606e22c605450adbe7a12 (diff)
downloadtakahe-3595af7bd239f3843aff3ae06df8932cff23173d.tar.gz
takahe-3595af7bd239f3843aff3ae06df8932cff23173d.tar.bz2
takahe-3595af7bd239f3843aff3ae06df8932cff23173d.zip
Media proxy, caching and tuning docs
Fixes #67
Diffstat (limited to 'mediaproxy')
-rw-r--r--mediaproxy/__init__.py0
-rw-r--r--mediaproxy/apps.py6
-rw-r--r--mediaproxy/views.py101
3 files changed, 107 insertions, 0 deletions
diff --git a/mediaproxy/__init__.py b/mediaproxy/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mediaproxy/__init__.py
diff --git a/mediaproxy/apps.py b/mediaproxy/apps.py
new file mode 100644
index 0000000..6b87719
--- /dev/null
+++ b/mediaproxy/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class MediaproxyConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "mediaproxy"
diff --git a/mediaproxy/views.py b/mediaproxy/views.py
new file mode 100644
index 0000000..e799e8b
--- /dev/null
+++ b/mediaproxy/views.py
@@ -0,0 +1,101 @@
+import httpx
+from django.conf import settings
+from django.core.cache import caches
+from django.http import Http404, HttpResponse
+from django.shortcuts import get_object_or_404
+from django.views.generic import View
+
+from activities.models import PostAttachment
+from users.models import Identity
+
+
+class BaseCacheView(View):
+ """
+ Base class for caching remote content.
+ """
+
+ cache_name = "media"
+ item_timeout: int | None = None
+
+ def get(self, request, **kwargs):
+ self.kwargs = kwargs
+ remote_url = self.get_remote_url()
+ cache = caches[self.cache_name]
+ cache_key = "proxy_" + remote_url
+ # See if it's already cached
+ cached_content = cache.get(cache_key)
+ if not cached_content:
+ # OK, fetch and cache it
+ try:
+ remote_response = httpx.get(
+ remote_url,
+ headers={"User-Agent": settings.TAKAHE_USER_AGENT},
+ follow_redirects=True,
+ timeout=settings.SETUP.REMOTE_TIMEOUT,
+ )
+ except (httpx.ConnectError, httpx.RequestError):
+ return HttpResponse(status=502)
+ if remote_response.status_code >= 400:
+ return HttpResponse(status=502)
+ # We got it - shove it into the cache
+ cached_content = {
+ "content": remote_response.content,
+ "mimetype": remote_response.headers.get(
+ "Content-Type", "application/octet-stream"
+ ),
+ }
+ cache.set(cache_key, cached_content, timeout=self.item_timeout)
+ return HttpResponse(
+ cached_content["content"],
+ headers={
+ "Content-Type": cached_content["mimetype"],
+ },
+ )
+
+ def get_remote_url(self):
+ raise NotImplementedError()
+
+
+class IdentityIconCacheView(BaseCacheView):
+ """
+ Caches identity icons (avatars)
+ """
+
+ cache_name = "avatars"
+ item_timeout = 86400 * 7 # One week
+
+ def get_remote_url(self):
+ self.identity = get_object_or_404(Identity, pk=self.kwargs["identity_id"])
+ if self.identity.local or not self.identity.image_uri:
+ raise Http404()
+ return self.identity.icon_uri
+
+
+class IdentityImageCacheView(BaseCacheView):
+ """
+ Caches identity profile header images
+ """
+
+ item_timeout = 86400 * 7 # One week
+
+ def get_remote_url(self):
+ self.identity = get_object_or_404(Identity, pk=self.kwargs["identity_id"])
+ if self.identity.local or not self.identity.image_uri:
+ raise Http404()
+ return self.identity.image_uri
+
+
+class PostAttachmentCacheView(BaseCacheView):
+ """
+ Caches post media (images only, videos should always be offloaded to remote)
+ """
+
+ item_timeout = 86400 * 7 # One week
+
+ def get_remote_url(self):
+ self.post_attachment = get_object_or_404(
+ PostAttachment, pk=self.kwargs["attachment_id"]
+ )
+ if not self.post_attachment.is_image():
+ raise Http404()
+ return self.post_attachment.remote_url