V1 cleanup (#73)

* removed obsolete code

* removed obsolete code

* removed obsolete code and added type annotations

* removed obsolete code and added type annotations

* version bump

Co-authored-by: Peter Dwyer <peter.dwyer@clanwilliamhealth.com>
This commit is contained in:
2022-08-26 13:11:29 +01:00
committed by GitHub
parent 1aeda89b74
commit 40b79c2f5d
42 changed files with 79 additions and 2720 deletions

View File

@@ -3,21 +3,21 @@ import mimetypes
import uuid
import zipfile
from functools import reduce
from itertools import zip_longest, chain
from itertools import zip_longest
from pathlib import Path
from typing import Optional, List, Union, Tuple
from typing import Optional, List, Union, Tuple, Final
# noinspection PyPackageRequirements
import fitz
import rarfile
from PIL import Image, UnidentifiedImageError
from PIL.Image import Image as Image_type
from django.conf import settings
from django.contrib.auth.models import User, AbstractUser
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db import models
from django.db.models import UniqueConstraint
from django.db.transaction import atomic
from django.templatetags.static import static
from django.utils.http import urlsafe_base64_encode
from django_boost.models.fields import AutoOneToOneField
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
@@ -57,34 +57,14 @@ class Directory(models.Model):
return "Directory: {0}; {1}".format(self.name, self.parent)
@property
def title(self):
def title(self) -> str:
return self.name
@property
def type(self):
def type(self) -> str:
return 'Directory'
def mark_read(self, user):
books = ComicBook.objects.filter(directory=self)
for book in books:
book.mark_read(user)
def mark_unread(self, user):
books = ComicBook.objects.filter(directory=self)
for book in books:
book.mark_unread(user)
def get_thumbnail_url(self):
if self.thumbnail:
return self.thumbnail.url
else:
self.generate_thumbnail()
if self.thumbnail:
return self.thumbnail.url
else:
return static('img/placeholder.png')
def generate_thumbnail(self):
def generate_thumbnail(self) -> None:
book: ComicBook = ComicBook.objects.filter(directory=self).order_by('file_name').first()
if not book:
return
@@ -105,7 +85,7 @@ class Directory(models.Model):
else:
return Path(path_items[0])
def get_path_items(self, p: Optional[List] = None) -> List[str]:
def get_path_items(self, p: Optional[List] = None) -> List[Path]:
if p is None:
p = []
p.append(self.name)
@@ -113,7 +93,7 @@ class Directory(models.Model):
self.parent.get_path_items(p)
return p
def get_path_objects(self, p=None):
def get_path_objects(self, p=None) -> List["Directory"]:
if p is None:
p = []
p.append(self)
@@ -121,14 +101,6 @@ class Directory(models.Model):
self.parent.get_path_objects(p)
return p
@property
def url_safe_selector(self):
return urlsafe_base64_encode(self.selector.bytes)
def set_classification(self, form_data):
self.classification = form_data['classification']
self.save()
class ComicBook(models.Model):
file_name = models.TextField()
@@ -148,36 +120,17 @@ class ComicBook(models.Model):
UniqueConstraint(fields=['directory', 'file_name'], name='one_comic_name_per_directory')
]
def __str__(self):
def __str__(self) -> str:
return self.file_name
@property
def title(self):
def title(self) -> str:
return self.file_name
@property
def type(self):
def type(self) -> str:
return 'ComicBook'
def mark_read(self, user: User):
status, _ = ComicStatus.objects.get_or_create(comic=self, user=user)
status.mark_read()
def mark_unread(self, user: User):
status, _ = ComicStatus.objects.get_or_create(comic=self, user=user)
status.mark_unread()
def mark_previous(self, user):
books = ComicBook.objects.filter(directory=self.directory).order_by('file_name')
for book in books:
if book == self:
break
book.mark_read(user)
@property
def url_safe_selector(self):
return urlsafe_base64_encode(self.selector.bytes)
def get_pdf(self) -> Path:
base_dir = settings.COMIC_BOOK_VOLUME
if self.directory:
@@ -185,7 +138,7 @@ class ComicBook(models.Model):
else:
return Path(base_dir, self.file_name)
def get_image(self, page: int):
def get_image(self, page: int) -> Union[Tuple[io.BytesIO, Image_type], Tuple[bool, bool]]:
base_dir = settings.COMIC_BOOK_VOLUME
if self.directory:
archive_path = Path(base_dir, self.directory.path, self.file_name)
@@ -196,7 +149,7 @@ class ComicBook(models.Model):
except rarfile.NotRarFile:
archive = zipfile.ZipFile(archive_path)
except zipfile.BadZipfile:
return False
return False, False
page_obj = ComicPage.objects.get(Comic=self, index=page)
try:
@@ -207,39 +160,34 @@ class ComicBook(models.Model):
out = (archive.open(page_obj.page_file_name), page_obj.content_type)
return out
def get_thumbnail_url(self):
if self.thumbnail:
return self.thumbnail.url
else:
self.generate_thumbnail()
return self.thumbnail.url
def generate_thumbnail_pdf(self, page_index: int = 0) -> Tuple[io.BytesIO, Image_type, str]:
img, pil_data = self._get_pdf_image(page_index if page_index else 0)
return img, pil_data, 'Image/JPEG'
def generate_thumbnail(self, page_index: int = None):
def generate_thumbnail_archive(self, page_index: int = 0) -> Union[Tuple[io.BytesIO, Image_type, str],
Tuple[bool, bool, bool]]:
img, content_type, pil_data = False, False, False
if page_index:
img, content_type = self.get_image(page_index)
pil_data = Image.open(img)
else:
for x in range(ComicPage.objects.filter(Comic=self).count()):
try:
img, content_type = self.get_image(x)
pil_data = Image.open(img)
break
except UnidentifiedImageError:
continue
return img, pil_data, content_type
def generate_thumbnail(self, page_index: int = None) -> None:
if Path(self.file_name).suffix.lower() == '.pdf':
if page_index:
img, pil_data = self._get_pdf_image(page_index)
else:
img, pil_data = self._get_pdf_image(0)
content_type = 'Image/JPEG'
img, pil_data, content_type = self.generate_thumbnail_pdf(page_index if page_index else 0)
else:
if page_index:
img, content_type = self.get_image(page_index)
pil_data = Image.open(img)
else:
for x in range(ComicPage.objects.filter(Comic=self).count()):
try:
img, content_type = self.get_image(x)
pil_data = Image.open(img)
break
except UnidentifiedImageError:
continue
try:
img
content_type
pil_data
except NameError:
return
img, pil_data, content_type = self.generate_thumbnail_archive(page_index)
if not img:
return
self.thumbnail = InMemoryUploadedFile(
img,
None,
@@ -250,133 +198,25 @@ class ComicBook(models.Model):
)
self.save()
def _get_pdf_image(self, page_index: int):
# noinspection PyTypeChecker
def _get_pdf_image(self, page_index: int) -> Tuple[io.BytesIO, Image_type]:
# noinspection PyUnresolvedReferences
doc = fitz.open(self.get_pdf())
page = doc[page_index]
pix = page.get_pixmap()
mode = "RGBA" if pix.alpha else "RGB"
pil_data = Image.frombytes(mode, [pix.width, pix.height], pix.samples)
mode: Final = "RGBA" if pix.alpha else "RGB"
# noinspection PyTypeChecker
pil_data = Image.frombytes(mode, (pix.width, pix.height), pix.samples)
img = io.BytesIO()
pil_data.save(img, format="JPEG")
img.seek(0)
return img, pil_data
def is_last_page(self, page):
if (self.page_count - 1) == page:
return True
return False
@property
def page_count(self):
def page_count(self) -> int:
return ComicPage.objects.filter(Comic=self).count()
def nav(self, user):
next_path, next_type = self.nav_get_next_comic(user)
prev_path, prev_type = self.nav_get_prev_comic(user)
return {
"next_path": next_path,
"next_type": next_type,
"prev_path": prev_path,
"prev_type": prev_type,
"cur_path": urlsafe_base64_encode(self.selector.bytes)
}
def nav_get_prev_comic(self, user) -> str:
base_dir = settings.COMIC_BOOK_VOLUME
if self.directory:
folder = Path(base_dir, self.directory.path)
else:
folder = base_dir
dir_list = ComicBook.get_ordered_dir_list(folder)
comic_index = dir_list.index(self.file_name)
if comic_index == 0:
if self.directory:
comic_path = urlsafe_base64_encode(self.directory.selector.bytes), type(self.directory).__name__
else:
comic_path = "", None
else:
prev_comic = dir_list[comic_index - 1]
if Path(folder, prev_comic).is_dir():
if self.directory:
comic_path = urlsafe_base64_encode(self.directory.selector.bytes), type(self.directory).__name__
else:
comic_path = "", None
else:
try:
if self.directory:
book = ComicBook.objects.get(file_name=prev_comic, directory=self.directory)
else:
book = ComicBook.objects.get(file_name=prev_comic, directory__isnull=True)
except ComicBook.DoesNotExist:
if self.directory:
book = ComicBook.process_comic_book(Path(prev_comic), self.directory)
else:
book = ComicBook.process_comic_book(Path(prev_comic))
cs, _ = ComicStatus.objects.get_or_create(comic=book, user=user)
comic_path = urlsafe_base64_encode(book.selector.bytes), type(book).__name__
return comic_path
def nav_get_next_comic(self, user):
base_dir = settings.COMIC_BOOK_VOLUME
if self.directory:
folder = Path(base_dir, self.directory.path)
else:
folder = base_dir
dir_list = ComicBook.get_ordered_dir_list(folder)
comic_index = dir_list.index(self.file_name)
try:
next_comic = dir_list[comic_index + 1]
try:
if self.directory:
book = ComicBook.objects.get(file_name=next_comic, directory=self.directory)
else:
book = ComicBook.objects.get(file_name=next_comic, directory__isnull=True)
except ComicBook.DoesNotExist:
if self.directory:
book = ComicBook.process_comic_book(Path(next_comic), self.directory)
else:
book = ComicBook.process_comic_book(Path(next_comic))
except ComicBook.MultipleObjectsReturned:
if self.directory:
books = ComicBook.objects.filter(file_name=next_comic, directory=self.directory).order_by('id')
else:
books = ComicBook.objects.get(file_name=next_comic, directory__isnull=True).order_by('id')
book = books.first()
books = books.exclude(id=book.id)
books.delete()
if type(book) is str:
raise IndexError
comic_path = urlsafe_base64_encode(book.selector.bytes), type(book).__name__
except IndexError:
if self.directory:
comic_path = urlsafe_base64_encode(self.directory.selector.bytes), type(self.directory).__name__
else:
comic_path = "", None
return comic_path
class DirFile:
def __init__(self):
self.name = ""
self.isdir = False
self.icon = ""
self.iscb = False
self.location = ""
self.label = ""
self.cur_page = 0
def __str__(self):
return self.name
@staticmethod
def process_comic_book(comic_file_path: Path, directory: "Directory" = False) -> Union["ComicBook", Path]:
"""
:type comic_file_path: str
:type directory: Directory
"""
try:
book = ComicBook.objects.get(file_name=comic_file_path.name, version=0)
book.directory = directory
@@ -404,19 +244,8 @@ class ComicBook(models.Model):
page.save()
return book
@staticmethod
def get_ordered_dir_list(folder: Path) -> List[str]:
directories = []
files = []
for item in folder.glob('*'):
if item.is_dir():
directories.append(item)
else:
files.append(item)
return [x.name for x in chain(sorted(directories), sorted(files))]
@property
def get_archive_path(self):
def get_archive_path(self) -> Path:
if self.directory:
return Path(settings.COMIC_BOOK_VOLUME, self.directory.get_path(), self.file_name)
else:
@@ -441,13 +270,13 @@ class ComicBook(models.Model):
raise NotCompatibleArchive
@staticmethod
def get_archive_files(archive):
def get_archive_files(archive) -> List[Tuple[str, str]]:
return [
(x, mimetypes.guess_type(x)[0]) for x in sorted(archive.namelist())
if not x.endswith('/') and mimetypes.guess_type(x)[0]
]
def verify_pages(self, pages: Optional["ComicPage"] = None):
def verify_pages(self, pages: Optional["ComicPage"] = None) -> None:
if not pages:
pages = ComicPage.objects.filter(Comic=self)
@@ -493,7 +322,8 @@ class ComicPage(models.Model):
class ComicStatus(models.Model):
user = models.ForeignKey(User, unique=False, null=False, on_delete=models.CASCADE)
comic = models.ForeignKey(ComicBook, unique=False, blank=False, null=False, on_delete=models.CASCADE, to_field="selector")
comic = models.ForeignKey(ComicBook, unique=False, blank=False, null=False, on_delete=models.CASCADE,
to_field="selector")
last_read_page = models.IntegerField(default=0)
unread = models.BooleanField(default=True)
finished = models.BooleanField(default=False)
@@ -503,23 +333,10 @@ class ComicStatus(models.Model):
UniqueConstraint(fields=['user', 'comic'], name='one_per_user_per_comic')
]
def mark_read(self):
page_count = ComicPage.objects.filter(Comic=self.comic).count()
self.unread = False
self.finished = True
self.last_read_page = page_count - 1
self.save()
def mark_unread(self):
self.unread = True
self.finished = False
self.last_read_page = 0
self.save()
def __str__(self):
def __str__(self) -> str:
return self.__repr__()
def __repr__(self):
def __repr__(self) -> str:
return (
f"<ComicStatus:{self.user.username}:{self.comic.file_name}:{self.last_read_page}:"
f"{self.unread}:{self.finished}"