Merge pull request #77

* added timestamp to comicstatus.

* added timestamp to comicstatus.
This commit is contained in:
2022-09-19 12:18:46 +01:00
committed by GitHub
parent 01e73cc9b3
commit 2647a0e31e
20 changed files with 463 additions and 304 deletions

View File

@@ -3,9 +3,8 @@ import mimetypes
import uuid
import zipfile
from functools import reduce
from itertools import zip_longest
from pathlib import Path
from typing import Optional, List, Union, Tuple, Final
from typing import Optional, List, Union, Tuple, Final, IO
# noinspection PyPackageRequirements
import fitz
@@ -17,7 +16,6 @@ from django.contrib.auth.models import User
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_boost.models.fields import AutoOneToOneField
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
@@ -93,7 +91,7 @@ class Directory(models.Model):
self.parent.get_path_items(path_items)
return path_items
def get_path_objects(self, path_items=None) -> List["Directory"]:
def get_path_objects(self, path_items: Optional[List] = None) -> List["Directory"]:
if path_items is None:
path_items = []
path_items.append(self)
@@ -114,6 +112,7 @@ class ComicBook(models.Model):
options={'quality': 60},
null=True)
thumbnail_index = models.PositiveIntegerField(default=0)
page_count = models.IntegerField(default=0)
class Meta:
constraints = [
@@ -131,13 +130,17 @@ class ComicBook(models.Model):
def type(self) -> str:
return 'ComicBook'
@property
def total(self) -> int:
return self.page_count
def get_pdf(self) -> Path:
base_dir = settings.COMIC_BOOK_VOLUME
if self.directory:
return Path(base_dir, self.directory.get_path(), self.file_name)
return Path(base_dir, self.file_name)
def get_image(self, page: int) -> Union[Tuple[io.BytesIO, Image_type], Tuple[bool, bool]]:
def get_image(self, page: int) -> Union[Tuple[IO[bytes], str], Tuple[bool, bool]]:
base_dir = settings.COMIC_BOOK_VOLUME
if self.directory:
archive_path = Path(base_dir, self.directory.path, self.file_name)
@@ -151,14 +154,8 @@ class ComicBook(models.Model):
except zipfile.BadZipfile:
return False, False
page_obj = ComicPage.objects.get(Comic=self, index=page)
try:
out = (archive.open(page_obj.page_file_name), page_obj.content_type)
except rarfile.NoRarEntry:
self.verify_pages()
page_obj = ComicPage.objects.get(Comic=self, index=page)
out = (archive.open(page_obj.page_file_name), page_obj.content_type)
return out
file_name, file_mime = self.get_archive_files(archive)[page]
return archive.open(file_name), file_mime
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)
@@ -171,7 +168,7 @@ class ComicBook(models.Model):
img, content_type = self.get_image(page_index)
pil_data = Image.open(img)
else:
for page_number in range(ComicPage.objects.filter(Comic=self).count()):
for page_number in range(self.page_count):
try:
img, content_type = self.get_image(page_number)
pil_data = Image.open(img)
@@ -211,10 +208,6 @@ class ComicBook(models.Model):
img.seek(0)
return img, pil_data
@property
def page_count(self) -> int:
return ComicPage.objects.filter(Comic=self).count()
@staticmethod
def process_comic_book(comic_file_path: Path, directory: "Directory" = False) -> Union["ComicBook", Path]:
try:
@@ -234,14 +227,10 @@ class ComicBook(models.Model):
return comic_file_path
if archive_type == 'archive':
book.verify_pages()
book.page_count = len(book.get_archive_files(archive))
elif archive_type == 'pdf':
with atomic():
for page_index in range(archive.page_count):
page = ComicPage(
Comic=book, index=page_index, page_file_name=page_index + 1, content_type='application/pdf'
)
page.save()
book.page_count = archive.page_count
return book
@property
@@ -268,56 +257,20 @@ class ComicBook(models.Model):
pass
raise NotCompatibleArchive
def get_page_count(self) -> int:
archive, archive_type = self.get_archive()
if archive_type == 'archive':
return len(self.get_archive_files(archive))
elif archive_type == 'pdf':
return archive.page_count
@staticmethod
def get_archive_files(archive) -> List[Tuple[str, str]]:
def get_archive_files(archive: Union[zipfile.ZipFile, rarfile.RarFile]) -> 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]
if not x.endswith('/') and mimetypes.guess_type(x)[0] and not x.endswith('xml')
]
def verify_pages(self, pages: Optional["ComicPage"] = None) -> None:
if not pages:
pages = ComicPage.objects.filter(Comic=self)
archive, archive_type = self.get_archive()
if archive_type == 'pdf':
return
archive_files = self.get_archive_files(archive)
index = 0
for a_file, db_file in zip_longest(archive_files, pages):
if not a_file:
db_file.delete()
continue
if not db_file:
ComicPage(
Comic=self,
page_file_name=a_file[0],
index=index,
content_type=a_file[1]
).save()
index += 1
continue
changed = False
if a_file[0] != db_file.page_file_name:
db_file.page_file_name = a_file[0]
changed = True
if a_file[1] != db_file.content_type:
db_file.content_type = a_file[1]
changed = True
if changed:
db_file.save()
index += 1
class ComicPage(models.Model):
Comic = models.ForeignKey(ComicBook, on_delete=models.CASCADE)
index = models.IntegerField()
page_file_name = models.CharField(max_length=200, unique=False)
content_type = models.CharField(max_length=30)
class Meta:
ordering = ['index']
class ComicStatus(models.Model):
user = models.ForeignKey(User, unique=False, null=False, on_delete=models.CASCADE)
@@ -326,6 +279,7 @@ class ComicStatus(models.Model):
last_read_page = models.IntegerField(default=0)
unread = models.BooleanField(default=True)
finished = models.BooleanField(default=False)
updated = models.DateTimeField(auto_now=True)
class Meta:
constraints = [
@@ -342,9 +296,6 @@ class ComicStatus(models.Model):
)
# TODO: add support to reference items last being read
class UserMisc(models.Model):
user = AutoOneToOneField(User, on_delete=models.CASCADE, primary_key=True)