quackscape/quackscape/tours/tasks.py
2024-03-11 15:56:03 +01:00

84 lines
2.8 KiB
Python

from django.conf import settings
from django.core.files.base import ContentFile
from django.apps import apps
from celery import shared_task
from PIL import Image
from io import BytesIO
import subprocess
import tempfile
import pathlib
import uuid
@shared_task
def create_image_resolutions(image: "OriginalImage"):
OriginalImage = apps.get_model("tours", "OriginalImage")
if isinstance(image, (str, uuid.UUID)):
image = OriginalImage.objects.get(id=image)
with Image.open(image.file) as img:
resolutions = settings.QUACKSCAPE_CONTENT_RESOLUTIONS
for width, height in resolutions:
if width > image.width:
continue
if not image.resolutions.filter(width=width, height=height).exists():
img_resized = img.resize((width, height))
img_resized = img_resized.convert("RGB")
new_image_path = f"{width}x{height}_{image.file.name}"
bio = BytesIO()
img_resized.save(bio, format="JPEG")
resolution = image.resolutions.create(
file=ContentFile(BytesIO.getvalue(bio), name=new_image_path),
width=width,
height=height,
)
@shared_task
def create_video_resolutions(video: "OriginalVideo"):
OriginalVideo = apps.get_model("tours", "OriginalVideo")
if isinstance(video, (str, uuid.UUID)):
video = OriginalVideo.objects.get(id=video)
resolutions = settings.QUACKSCAPE_CONTENT_RESOLUTIONS
ffmpeg_options = settings.FFMPEG_OPTIONS[settings.FFMPEG_DEFAULT_OPTION]
for width, height in resolutions:
if width > video.width:
continue
if not video.resolutions.filter(width=width, height=height).exists():
with tempfile.TemporaryDirectory() as tmpdir:
input_path = pathlib.Path(tmpdir) / video.file.name
with open(input_path, "wb") as f:
f.write(video.file.read())
output_path = (
pathlib.Path(tmpdir) / f"{width}x{height}_{video.file.name}"
)
cmd = f"ffmpeg {ffmpeg_options['global_options']} {ffmpeg_options['input_options']} -i {input_path} -s {width}x{height} {ffmpeg_options['output_options']} {output_path}".split()
try:
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as e:
print(f"Error processing video {video_path} to {resolution}: {e}")
with open(output_path, "rb") as f:
resolution = video.resolutions.create(
file=ContentFile(f.read(), name=output_path.name),
width=width,
height=height,
)
output_path.unlink()