|
|
|
@ -5,6 +5,11 @@ import mimetypes |
|
|
|
import re |
|
|
|
from urllib.parse import urlparse |
|
|
|
|
|
|
|
from django.core.files.storage import default_storage |
|
|
|
from django.core.files.base import ContentFile |
|
|
|
|
|
|
|
from pathlib import Path |
|
|
|
from django.utils.text import get_valid_filename |
|
|
|
from django.conf import settings |
|
|
|
from django.core.files import File |
|
|
|
from django.http import HttpRequest |
|
|
|
@ -198,6 +203,26 @@ def sizeof_fmt(num, suffix="B"): |
|
|
|
num /= 1024.0 |
|
|
|
return f"{num:.1f} Yi{suffix}" |
|
|
|
|
|
|
|
def file_location_media(path: str): |
|
|
|
""" |
|
|
|
Resolve a media URL/relative path to absolute filesystem path under MEDIA_ROOT. |
|
|
|
""" |
|
|
|
from django.conf import settings |
|
|
|
|
|
|
|
media_url = (getattr(settings, "MEDIA_URL", "/media/") or "/media/").rstrip("/") |
|
|
|
media_root = settings.MEDIA_ROOT |
|
|
|
|
|
|
|
if path.startswith("http"): |
|
|
|
path = exclude_host_from_url(path) |
|
|
|
|
|
|
|
if path.startswith(media_url + "/"): |
|
|
|
path = path[len(media_url):] |
|
|
|
|
|
|
|
if path.startswith("/"): |
|
|
|
path = path[1:] |
|
|
|
|
|
|
|
return os.path.join(media_root, path) |
|
|
|
|
|
|
|
|
|
|
|
def file_location(path): |
|
|
|
from django.conf import settings |
|
|
|
@ -253,14 +278,16 @@ class FileFieldSerializer(serializers.CharField): |
|
|
|
# value not changed and here we simply return old file path |
|
|
|
return self.get_rpath(data) |
|
|
|
|
|
|
|
if data.startswith('http'): |
|
|
|
data = self.get_rpath(data) |
|
|
|
# if data.startswith('http'): |
|
|
|
# data = self.get_rpath(data) |
|
|
|
|
|
|
|
fpath = file_location(data) |
|
|
|
fpath = file_location_media(data) |
|
|
|
if not os.path.exists(fpath): |
|
|
|
raise serializers.ValidationError(f"File: '{fpath}' Does not exist") |
|
|
|
|
|
|
|
return File(open(fpath, 'rb'), os.path.basename(data)) |
|
|
|
rel = os.path.basename(data) |
|
|
|
return File(open(fpath, "rb"), rel) |
|
|
|
# return File(open(fpath, 'rb'), os.path.basename(data)) |
|
|
|
|
|
|
|
|
|
|
|
class UploadChatMediaSerializer(serializers.Serializer): |
|
|
|
@ -277,62 +304,137 @@ class UploadChatMediaSerializer(serializers.Serializer): |
|
|
|
data['file'] = instance['file'] |
|
|
|
return data |
|
|
|
|
|
|
|
# def store_file(self, file): |
|
|
|
# from django.conf import settings |
|
|
|
# from utils.image_utils import ( |
|
|
|
# create_thumbnail, |
|
|
|
# is_image_file, |
|
|
|
# is_video_file, |
|
|
|
# extract_video_thumbnail |
|
|
|
# ) |
|
|
|
# media_path = settings.MEDIA_ROOT |
|
|
|
|
|
|
|
# os.makedirs(f'{media_path}/chat/uploads', exist_ok=True) |
|
|
|
# fpath = f"/chat/uploads/{secrets.token_urlsafe(4)}-{file.name}" |
|
|
|
# full_path = media_path + fpath |
|
|
|
# if hasattr(file, 'read'): |
|
|
|
# default_storage.save(str(full_path), ContentFile(file.read())) |
|
|
|
# else: |
|
|
|
# default_storage.save(str(full_path), file) |
|
|
|
# os.chmod(full_path, 0o644) |
|
|
|
|
|
|
|
# result = { |
|
|
|
# 'file': fpath, |
|
|
|
# 'url': absolute_url(self.context['request'], f"/media{fpath}"), |
|
|
|
# 'name': file.name, |
|
|
|
# 'size': sizeof_fmt(file.size), |
|
|
|
# 'mime_type': guess_file_type(fpath) |
|
|
|
# } |
|
|
|
|
|
|
|
# # Generate thumbnail if file is an image (low quality for preview) |
|
|
|
# if is_image_file(full_path): |
|
|
|
# try: |
|
|
|
# thumbnail_path = create_thumbnail(full_path, size=(200, 200), quality=60) |
|
|
|
# thumbnail_relative = thumbnail_path.replace(media_path, '') |
|
|
|
# result['thumbnail_url'] = absolute_url( |
|
|
|
# self.context['request'], |
|
|
|
# f"/media{thumbnail_relative}" |
|
|
|
# ) |
|
|
|
# except Exception as e: |
|
|
|
# print(f"Failed to generate image thumbnail: {e}") |
|
|
|
# result['thumbnail_url'] = None |
|
|
|
# # Generate thumbnail if file is a video (low quality for preview) |
|
|
|
# elif is_video_file(full_path): |
|
|
|
# try: |
|
|
|
# thumbnail_path = extract_video_thumbnail( |
|
|
|
# full_path, |
|
|
|
# time_offset='00:00:01', |
|
|
|
# size=(200, 200), |
|
|
|
# quality=60 |
|
|
|
# ) |
|
|
|
# thumbnail_relative = thumbnail_path.replace(media_path, '') |
|
|
|
# result['thumbnail_url'] = absolute_url( |
|
|
|
# self.context['request'], |
|
|
|
# f"/media{thumbnail_relative}" |
|
|
|
# ) |
|
|
|
# except Exception as e: |
|
|
|
# print(f"Failed to generate video thumbnail: {e}") |
|
|
|
# result['thumbnail_url'] = None |
|
|
|
# else: |
|
|
|
# result['thumbnail_url'] = None |
|
|
|
|
|
|
|
# return result |
|
|
|
def store_file(self, file): |
|
|
|
from django.conf import settings |
|
|
|
from utils.image_utils import ( |
|
|
|
create_thumbnail, |
|
|
|
is_image_file, |
|
|
|
is_video_file, |
|
|
|
extract_video_thumbnail |
|
|
|
extract_video_thumbnail, |
|
|
|
) |
|
|
|
media_path = settings.MEDIA_ROOT |
|
|
|
|
|
|
|
os.makedirs(f'{media_path}/chat/uploads', exist_ok=True) |
|
|
|
fpath = f"/chat/uploads/{secrets.token_urlsafe(4)}-{file.name}" |
|
|
|
full_path = media_path + fpath |
|
|
|
shutil.move(file.temporary_file_path(), full_path) |
|
|
|
os.chmod(full_path, 0o644) |
|
|
|
media_root = Path(settings.MEDIA_ROOT) # Path object |
|
|
|
chat_dir = media_root / "chat" / "uploads" |
|
|
|
chat_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
safe_name = get_valid_filename(os.path.basename(file.name)) |
|
|
|
rel_path = Path("chat") / "uploads" / f"{secrets.token_urlsafe(4)}-{safe_name}" |
|
|
|
full_path = media_root / rel_path # Path object |
|
|
|
|
|
|
|
# Save via default_storage (path must be relative to MEDIA_ROOT) |
|
|
|
if hasattr(file, "read"): |
|
|
|
default_storage.save(str(rel_path), ContentFile(file.read())) |
|
|
|
else: |
|
|
|
default_storage.save(str(rel_path), file) |
|
|
|
|
|
|
|
# Optional: chmod only if local filesystem and OS supports it |
|
|
|
try: |
|
|
|
os.chmod(full_path, 0o644) |
|
|
|
except PermissionError: |
|
|
|
pass |
|
|
|
|
|
|
|
result = { |
|
|
|
'file': fpath, |
|
|
|
'url': absolute_url(self.context['request'], f"/media{fpath}"), |
|
|
|
'name': file.name, |
|
|
|
'size': sizeof_fmt(file.size), |
|
|
|
'mime_type': guess_file_type(fpath) |
|
|
|
"file": f"/{rel_path.as_posix()}", |
|
|
|
"url": absolute_url( |
|
|
|
self.context["request"], |
|
|
|
f"{settings.MEDIA_URL.rstrip('/')}/{rel_path.as_posix()}", |
|
|
|
), |
|
|
|
"name": safe_name, |
|
|
|
"size": sizeof_fmt(file.size), |
|
|
|
"mime_type": guess_file_type(rel_path.name), |
|
|
|
} |
|
|
|
|
|
|
|
# Generate thumbnail if file is an image (low quality for preview) |
|
|
|
if is_image_file(full_path): |
|
|
|
# For images |
|
|
|
if is_image_file(str(full_path)): |
|
|
|
try: |
|
|
|
thumbnail_path = create_thumbnail(full_path, size=(200, 200), quality=60) |
|
|
|
thumbnail_relative = thumbnail_path.replace(media_path, '') |
|
|
|
result['thumbnail_url'] = absolute_url( |
|
|
|
self.context['request'], |
|
|
|
f"/media{thumbnail_relative}" |
|
|
|
thumbnail_path = create_thumbnail(str(full_path), size=(200, 200), quality=60) |
|
|
|
thumb_rel = str(thumbnail_path).replace(str(media_root), "").lstrip("\\/") |
|
|
|
result["thumbnail_url"] = absolute_url( |
|
|
|
self.context["request"], |
|
|
|
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}", |
|
|
|
) |
|
|
|
except Exception as e: |
|
|
|
print(f"Failed to generate image thumbnail: {e}") |
|
|
|
result['thumbnail_url'] = None |
|
|
|
# Generate thumbnail if file is a video (low quality for preview) |
|
|
|
elif is_video_file(full_path): |
|
|
|
result["thumbnail_url"] = None |
|
|
|
# For videos |
|
|
|
elif is_video_file(str(full_path)): |
|
|
|
try: |
|
|
|
thumbnail_path = extract_video_thumbnail( |
|
|
|
full_path, |
|
|
|
time_offset='00:00:01', |
|
|
|
str(full_path), |
|
|
|
time_offset="00:00:01", |
|
|
|
size=(200, 200), |
|
|
|
quality=60 |
|
|
|
quality=60, |
|
|
|
) |
|
|
|
thumbnail_relative = thumbnail_path.replace(media_path, '') |
|
|
|
result['thumbnail_url'] = absolute_url( |
|
|
|
self.context['request'], |
|
|
|
f"/media{thumbnail_relative}" |
|
|
|
thumb_rel = str(thumbnail_path).replace(str(media_root), "").lstrip("\\/") |
|
|
|
result["thumbnail_url"] = absolute_url( |
|
|
|
self.context["request"], |
|
|
|
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}", |
|
|
|
) |
|
|
|
except Exception as e: |
|
|
|
print(f"Failed to generate video thumbnail: {e}") |
|
|
|
result['thumbnail_url'] = None |
|
|
|
result["thumbnail_url"] = None |
|
|
|
else: |
|
|
|
result['thumbnail_url'] = None |
|
|
|
|
|
|
|
result["thumbnail_url"] = None |
|
|
|
return result |
|
|
|
|
|
|
|
def validate(self, attrs): |
|
|
|
@ -359,55 +461,67 @@ class UploadTmpSerializer(serializers.Serializer): |
|
|
|
create_thumbnail, |
|
|
|
is_image_file, |
|
|
|
is_video_file, |
|
|
|
extract_video_thumbnail |
|
|
|
extract_video_thumbnail, |
|
|
|
) |
|
|
|
static_path = settings.STATIC_ROOT |
|
|
|
|
|
|
|
os.makedirs(f'{static_path}/tmp', exist_ok=True) |
|
|
|
fpath = f"/tmp/{secrets.token_urlsafe(4)}-{file.name}" |
|
|
|
full_path = static_path + fpath |
|
|
|
shutil.move(file.temporary_file_path(), full_path) |
|
|
|
os.chmod(full_path, 0o644) |
|
|
|
media_root = Path(settings.MEDIA_ROOT) |
|
|
|
tmp_dir = media_root / "tmp" |
|
|
|
tmp_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
safe_name = get_valid_filename(os.path.basename(file.name)) |
|
|
|
rel_path = Path("tmp") / f"{secrets.token_urlsafe(4)}-{safe_name}" |
|
|
|
|
|
|
|
# Save the file using Django storage (safe on Windows) |
|
|
|
# If the file is an InMemoryFile or TemporaryUploadedFile, read its content |
|
|
|
if hasattr(file, 'read'): |
|
|
|
default_storage.save(str(rel_path), ContentFile(file.read())) |
|
|
|
else: |
|
|
|
default_storage.save(str(rel_path), file) |
|
|
|
|
|
|
|
full_path = str(media_root / rel_path) |
|
|
|
|
|
|
|
result = { |
|
|
|
'file': fpath, |
|
|
|
'url': absolute_url(self.context['request'], f"/static{fpath}"), |
|
|
|
'name': file.name, |
|
|
|
'size': sizeof_fmt(file.size), |
|
|
|
'mime_type': guess_file_type(fpath) |
|
|
|
"file": f"/{rel_path.as_posix()}", |
|
|
|
"url": absolute_url( |
|
|
|
self.context["request"], |
|
|
|
f"{settings.MEDIA_URL.rstrip('/')}/{rel_path.as_posix()}", |
|
|
|
), |
|
|
|
"name": safe_name, |
|
|
|
"size": sizeof_fmt(file.size), |
|
|
|
"mime_type": guess_file_type(rel_path.name), |
|
|
|
} |
|
|
|
|
|
|
|
# Generate thumbnail if file is an image (low quality for preview) |
|
|
|
# Generate thumbnail if image |
|
|
|
if is_image_file(full_path): |
|
|
|
try: |
|
|
|
thumbnail_path = create_thumbnail(full_path, size=(200, 200), quality=60) |
|
|
|
thumbnail_relative = thumbnail_path.replace(static_path, '') |
|
|
|
result['thumbnail_url'] = absolute_url( |
|
|
|
self.context['request'], |
|
|
|
f"/static{thumbnail_relative}" |
|
|
|
thumb_path = create_thumbnail(full_path, size=(200, 200), quality=60) |
|
|
|
thumb_rel = thumb_path.replace(str(media_root), "").lstrip("\\/") |
|
|
|
result["thumbnail_url"] = absolute_url( |
|
|
|
self.context["request"], |
|
|
|
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}", |
|
|
|
) |
|
|
|
except Exception as e: |
|
|
|
print(f"Failed to generate image thumbnail: {e}") |
|
|
|
result['thumbnail_url'] = None |
|
|
|
# Generate thumbnail if file is a video (low quality for preview) |
|
|
|
print("Failed to generate image thumbnail:", e) |
|
|
|
result["thumbnail_url"] = None |
|
|
|
# Generate thumbnail if video |
|
|
|
elif is_video_file(full_path): |
|
|
|
try: |
|
|
|
thumbnail_path = extract_video_thumbnail( |
|
|
|
thumb_path = extract_video_thumbnail( |
|
|
|
full_path, |
|
|
|
time_offset='00:00:01', |
|
|
|
time_offset="00:00:01", |
|
|
|
size=(200, 200), |
|
|
|
quality=60 |
|
|
|
quality=60, |
|
|
|
) |
|
|
|
thumbnail_relative = thumbnail_path.replace(static_path, '') |
|
|
|
result['thumbnail_url'] = absolute_url( |
|
|
|
self.context['request'], |
|
|
|
f"/static{thumbnail_relative}" |
|
|
|
thumb_rel = thumb_path.replace(str(media_root), "").lstrip("\\/") |
|
|
|
result["thumbnail_url"] = absolute_url( |
|
|
|
self.context["request"], |
|
|
|
f"{settings.MEDIA_URL.rstrip('/')}/{thumb_rel.replace(os.sep, '/')}", |
|
|
|
) |
|
|
|
except Exception as e: |
|
|
|
print(f"Failed to generate video thumbnail: {e}") |
|
|
|
result['thumbnail_url'] = None |
|
|
|
print("Failed to generate video thumbnail:", e) |
|
|
|
result["thumbnail_url"] = None |
|
|
|
else: |
|
|
|
result['thumbnail_url'] = None |
|
|
|
result["thumbnail_url"] = None |
|
|
|
|
|
|
|
return result |
|
|
|
|
|
|
|
|