Source code for thabloid.models

import os
import shutil
import subprocess
from itertools import zip_longest

from PIL import Image
from django.conf import settings
from django.core.validators import MinValueValidator, FileExtensionValidator
from django.db import models
from django.urls import reverse
from django.utils.text import slugify

from utils.threading import PopenAndCall


[docs]def thabloid_filename(instance, filename): ext = os.path.splitext(filename)[1] return os.path.join("public/thabloids/", slugify(instance) + ext)
[docs]class Thabloid(models.Model): year = models.IntegerField( verbose_name="academic year", validators=[MinValueValidator(1990)] ) issue = models.IntegerField() file = models.FileField( upload_to=thabloid_filename, validators=[FileExtensionValidator(["txt", "pdf", "jpg", "jpeg", "png"])], ) class Meta: unique_together = ( "year", "issue", ) ordering = ("-year", "-issue") def __str__(self): return "Thabloid {}-{}, #{}".format(self.year, self.year + 1, self.issue)
[docs] def page_url(self, page=None, second_page=None): if page is None: page = "%03d.png" elif second_page is None: page = "{:03}.png".format(page) else: page = "{:03}-{:03}.png".format(page, second_page) dst, ext = os.path.splitext(self.file.name) return os.path.join(os.path.dirname(dst), "pages", os.path.basename(dst), page)
@property def cover(self): return self.page_url(1)
[docs] def pagesets(self, count): if count < 1: return [] pageiter = iter(range(2, count)) return [(1, None)] + list(zip_longest(pageiter, pageiter))
@property def pages(self): pages = os.listdir( os.path.join(settings.MEDIA_ROOT, os.path.dirname(self.page_url())) ) count = len(pages) * 2 - 1 return map(lambda p: self.page_url(p[0], p[1]), self.pagesets(count))
[docs] def get_absolute_url(self): return reverse( "thabloid:pages", kwargs={"year": self.year, "issue": self.issue} )
[docs] def post_extract(self): pages = os.listdir( os.path.join(settings.MEDIA_ROOT, os.path.dirname(self.page_url())) ) pages = [self.page_url(i + 1) for i in range(len(pages))] pages = sorted(pages) pages = pages[1:-1] count = int(len(pages) / 2) dirname = os.path.join(settings.MEDIA_ROOT, os.path.dirname(self.page_url())) for i in range(0, count): i = i * 2 spread_left = os.path.join(settings.MEDIA_ROOT, pages[i]) spread_right = os.path.join(settings.MEDIA_ROOT, pages[i + 1]) result = Image.new("RGB", (2100, 1485)) img_left = Image.open(spread_left) result.paste(img_left, (0, 0, 1050, 1485)) img_right = Image.open(spread_right) result.paste(img_right, (1050, 0, 2100, 1485)) filename = ( os.path.splitext(os.path.basename(spread_left))[0] + "-" + os.path.splitext(os.path.basename(spread_right))[0] + ".png" ) result.save(os.path.join(dirname, filename), "PNG") os.remove(spread_left) os.remove(spread_right)
[docs] def extract_thabloid_pages(self, wait): dst = os.path.join(settings.MEDIA_ROOT, self.page_url()) name = thabloid_filename(self, self.file.name) src = os.path.join(settings.MEDIA_ROOT, name) try: # Remove potential remainders shutil.rmtree(os.path.dirname(dst)) except FileNotFoundError: pass os.makedirs(os.path.dirname(dst), exist_ok=True) # TODO reconsider if this resolution / quality is sufficient thread = PopenAndCall( self.post_extract, [ "gs", "-o", dst, # '-g2100x2970', '-dPDFFitPage', "-g1050x1485", "-dPDFFitPage", "-dTextAlphaBits=4", "-sDEVICE=png16m", "-f", src, ], stdout=subprocess.DEVNULL, ) if wait: thread.join()
[docs] def save(self, *args, wait=False, **kwargs): new_file = False if self.pk is None: new_file = True else: old = Thabloid.objects.get(pk=self.pk) old_dir = os.path.join(settings.MEDIA_ROOT, old.page_url()) old_dir = os.path.dirname(old_dir) if self.file != old.file: new_file = True elif self.year != old.year or self.issue != old.issue: self.file.name = thabloid_filename(self, self.file.name) new_dir = os.path.join(settings.MEDIA_ROOT, self.page_url()) new_dir = os.path.dirname(new_dir) try: shutil.rmtree(new_dir) except FileNotFoundError: pass os.rename(old_dir, new_dir) os.rename( os.path.join(settings.MEDIA_ROOT, old.file.name), os.path.join(settings.MEDIA_ROOT, self.file.name), ) if new_file: filename = thabloid_filename(self, self.file.name) src = os.path.join(settings.MEDIA_ROOT, filename) # Removes the .pdf file if it already exists try: os.remove(src) except FileNotFoundError: pass super().save(*args, **kwargs) if new_file: self.extract_thabloid_pages(wait)