This repository has been archived on 2023-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
python-blog/src/attachments/models.py

130 lines
4 KiB
Python
Raw Normal View History

2021-12-31 12:08:03 +01:00
from __future__ import annotations
import json
2020-08-26 19:04:48 +02:00
import tempfile
from pathlib import Path
2021-12-31 12:08:03 +01:00
from typing import Any
2020-08-26 19:04:48 +02:00
import requests
from django.conf import settings
2020-08-26 19:04:48 +02:00
from django.core.files import File
2022-09-23 21:47:19 +02:00
from django.core.handlers.wsgi import WSGIRequest
2020-08-26 19:04:48 +02:00
from django.db import models
from django.db.models.fields.files import FieldFile
2022-10-01 09:16:26 +02:00
from django.urls import reverse
2020-08-26 19:04:48 +02:00
from PIL import Image
from articles.utils import build_full_absolute_url
class AbsoluteUrlFieldFile(FieldFile):
2022-09-23 21:47:19 +02:00
def get_full_absolute_url(self, request: WSGIRequest) -> str:
return build_full_absolute_url(request, self.url)
class AbsoluteUrlFileField(models.FileField):
attr_class = AbsoluteUrlFieldFile
2020-08-26 19:04:48 +02:00
2020-11-28 20:09:37 +01:00
class AttachmentManager(models.Manager):
2021-12-31 12:08:03 +01:00
def get_open_graph_image(self) -> Attachment | None:
2020-11-28 20:09:37 +01:00
return self.filter(open_graph_image=True).first()
2020-08-26 19:04:48 +02:00
class Attachment(models.Model):
description = models.CharField(max_length=500)
original_file = AbsoluteUrlFileField()
processed_file = AbsoluteUrlFileField(blank=True, null=True)
open_graph_image = models.BooleanField(blank=True, default=False)
2020-11-28 20:09:37 +01:00
objects = AttachmentManager()
2020-08-26 19:04:48 +02:00
2020-08-28 22:24:28 +02:00
class Meta:
ordering = ["description"]
2021-12-31 12:08:03 +01:00
def __str__(self) -> str:
2020-08-27 22:09:18 +02:00
return f"{self.description} ({self.original_file.name})"
2021-12-31 12:08:03 +01:00
def reprocess(self) -> None:
2023-01-30 20:58:18 +01:00
self.processed_file = None # type: ignore[assignment]
self.save()
2022-10-01 09:16:26 +02:00
@property
def original_file_url(self) -> str:
return reverse("attachments:original", kwargs={"pk": self.pk})
@property
def processed_file_url(self) -> str | None:
if self.processed_file:
return reverse("attachments:processed", kwargs={"pk": self.pk})
return None
2021-12-31 12:08:03 +01:00
def save(self, *args: Any, **kwargs: Any) -> None:
super().save(*args, **kwargs)
2020-08-26 19:04:48 +02:00
if self.processed_file:
2023-01-30 20:58:18 +01:00
return None
2020-08-26 19:04:48 +02:00
try:
2020-12-03 22:30:11 +01:00
Image.open(self.original_file.path)
except OSError:
2023-01-30 20:58:18 +01:00
return None
# Submit job to shortpixel
base_data = {
"key": settings.SHORTPIXEL_API_KEY,
"plugin_version": "gabno",
"wait": 20,
}
post_data = {
"lossy": 1,
"resize": 3,
"resize_width": settings.SHORTPIXEL_RESIZE_WIDTH,
"resize_height": settings.SHORTPIXEL_RESIZE_HEIGHT,
2020-08-29 09:55:31 +02:00
"keep_exif": 1,
"file_paths": json.dumps(
[f"{self.original_file.name}:{self.original_file.path}"]
),
}
data = {**base_data, **post_data}
url = "https://api.shortpixel.com/v2/post-reducer.php"
2023-01-30 20:58:18 +01:00
with Path(self.original_file.path).open("rb") as original_file:
response = requests.post(
2023-01-30 20:58:18 +01:00
url=url,
data=data,
files={self.original_file.name: original_file},
timeout=10,
)
res = response.json()
res_data = res[0]
# Loop until it's done
post_data = {
"key": settings.SHORTPIXEL_API_KEY,
"plugin_version": "gabno",
"wait": 20,
"file_urls": json.dumps([res_data["OriginalURL"]]),
}
check_data = {**base_data, **post_data}
while res_data["Status"]["Code"] == "1":
2023-01-30 20:58:18 +01:00
response = requests.post(url=url, data=check_data, timeout=10)
res_data = response.json()[0]
# Download image
current_path = Path(self.original_file.path)
2020-08-26 19:04:48 +02:00
temp_dir = Path(tempfile.mkdtemp())
temp_path = temp_dir / (current_path.stem + "-processed" + current_path.suffix)
2023-01-30 20:58:18 +01:00
img = requests.get(res_data["LossyURL"], stream=True, timeout=10)
with Path(temp_path).open("wb") as temp_file:
for chunk in img:
temp_file.write(chunk)
# Link it to our model
2023-01-30 20:58:18 +01:00
with Path(temp_path).open("rb") as output_file:
2020-08-26 19:04:48 +02:00
f = File(output_file)
self.processed_file.save(temp_path.name, f, save=False)
2020-08-26 19:04:48 +02:00
temp_path.unlink()
temp_dir.rmdir()
return super().save(*args, **kwargs)