import hashlib import json import logging import mimetypes import os import re import shutil import subprocess from pathlib import Path import imagehash from django.conf import settings from django.core import signing from django.http import FileResponse, Http404, HttpResponse from django.utils.text import get_valid_filename from PIL import Image from .models import MediaItem, MediaLocation logger = logging.getLogger(__name__) HASH_FIELDS = ("ahash", "dhash", "phash", "whash") IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".apng", ".webp"} ALLOWED_EXTENSIONS = { ".jpg", ".jpeg", ".png", ".gif", ".apng", ".webp", ".mp4", ".webm", } VIDEO_EXTENSIONS = {".mp4", ".webm"} UPLOAD_FILE_SALT = "j621.upload-file" MEDIA_FILE_SALT = "j621.media-file" CHUNK_SIZE = 1024 * 1024 RANGE_RE = re.compile(r"bytes=(\d*)-(\d*)$") def compute_md5(path): digest = hashlib.md5() with open(path, "rb") as handle: for chunk in iter(lambda: handle.read(CHUNK_SIZE), b""): digest.update(chunk) return digest.hexdigest() def index_file(path, folder): """Index one file into MediaItem/MediaLocation. Returns (item, created_item, location, created_location). """ path = Path(path) folder = Path(folder) stat = path.stat() md5 = compute_md5(path) item, created_item = MediaItem.objects.get_or_create( md5=md5, defaults={"size": stat.st_size} ) if not created_item and item.size != stat.st_size: item.size = stat.st_size item.save(update_fields=["size", "updated_at"]) location, created_location = MediaLocation.objects.update_or_create( item=item, path=str(path), defaults={ "rel_path": str(path.relative_to(folder)), "mtime": stat.st_mtime, }, ) return item, created_item, location, created_location def signed_media_url(item, user, action="raw"): """Media URL that /