mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-01-29 06:10:51 +00:00
* feat: add ePub thumbnail support Co-Authored-By: Jorge Rui Da Silva Barrios <29062316+jorgerui@users.noreply.github.com> * tests: compare epub cover against png snapshot Co-Authored-By: yed <yedpodtrzitko@users.noreply.github.com> * test: optimize epub test file --------- Co-authored-by: Jorge Rui Da Silva Barrios <29062316+jorgerui@users.noreply.github.com> Co-authored-by: yed <yedpodtrzitko@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
3d7629bc73
commit
d3c3e634b9
@@ -23,6 +23,7 @@ class MediaType(str, Enum):
|
||||
DATABASE: str = "database"
|
||||
DISK_IMAGE: str = "disk_image"
|
||||
DOCUMENT: str = "document"
|
||||
EBOOK: str = "ebook"
|
||||
FONT: str = "font"
|
||||
IMAGE_ANIMATED: str = "image_animated"
|
||||
IMAGE_RAW: str = "image_raw"
|
||||
@@ -160,6 +161,25 @@ class MediaCategories:
|
||||
".wpd",
|
||||
".wps",
|
||||
}
|
||||
_EBOOK_SET: set[str] = {
|
||||
".epub",
|
||||
# ".azw",
|
||||
# ".azw3",
|
||||
# ".cb7",
|
||||
# ".cba",
|
||||
# ".cbr",
|
||||
# ".cbt",
|
||||
# ".cbz",
|
||||
# ".djvu",
|
||||
# ".fb2",
|
||||
# ".ibook",
|
||||
# ".inf",
|
||||
# ".kfx",
|
||||
# ".lit",
|
||||
# ".mobi",
|
||||
# ".pdb"
|
||||
# ".prc",
|
||||
}
|
||||
_FONT_SET: set[str] = {
|
||||
".fon",
|
||||
".otf",
|
||||
@@ -347,6 +367,11 @@ class MediaCategories:
|
||||
extensions=_DOCUMENT_SET,
|
||||
is_iana=False,
|
||||
)
|
||||
EBOOK_TYPES: MediaCategory = MediaCategory(
|
||||
media_type=MediaType.EBOOK,
|
||||
extensions=_EBOOK_SET,
|
||||
is_iana=False,
|
||||
)
|
||||
FONT_TYPES: MediaCategory = MediaCategory(
|
||||
media_type=MediaType.FONT,
|
||||
extensions=_FONT_SET,
|
||||
@@ -448,6 +473,7 @@ class MediaCategories:
|
||||
DATABASE_TYPES,
|
||||
DISK_IMAGE_TYPES,
|
||||
DOCUMENT_TYPES,
|
||||
EBOOK_TYPES,
|
||||
FONT_TYPES,
|
||||
IMAGE_ANIMATED_TYPES,
|
||||
IMAGE_RAW_TYPES,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import math
|
||||
import struct
|
||||
import zipfile
|
||||
from copy import deepcopy
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
@@ -616,6 +617,29 @@ class ThumbRenderer(QObject):
|
||||
logger.error("Couldn't render thumbnail", filepath=filepath, error=e)
|
||||
return im
|
||||
|
||||
def _epub_cover(self, filepath: Path) -> Image.Image:
|
||||
"""Extracts and returns the first image found in the ePub file at the given filepath.
|
||||
|
||||
Args:
|
||||
filepath (Path): The path to the ePub file.
|
||||
|
||||
Returns:
|
||||
Image: The first image found in the ePub file, or None by default.
|
||||
"""
|
||||
im: Image.Image = None
|
||||
try:
|
||||
with zipfile.ZipFile(filepath, "r") as zip_file:
|
||||
for file_name in zip_file.namelist():
|
||||
if file_name.lower().endswith(
|
||||
(".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg")
|
||||
):
|
||||
image_data = zip_file.read(file_name)
|
||||
im = Image.open(BytesIO(image_data))
|
||||
except Exception as e:
|
||||
logger.error("Couldn't render thumbnail", filepath=filepath, error=e)
|
||||
|
||||
return im
|
||||
|
||||
def _font_short_thumb(self, filepath: Path, size: int) -> Image.Image:
|
||||
"""Render a small font preview ("Aa") thumbnail from a font file.
|
||||
|
||||
@@ -1045,6 +1069,11 @@ class ThumbRenderer(QObject):
|
||||
image = self._audio_waveform_thumb(_filepath, ext, adj_size, pixel_ratio)
|
||||
if image is not None:
|
||||
image = self._apply_overlay_color(image, UiColor.GREEN)
|
||||
# Ebooks =======================================================
|
||||
elif MediaCategories.is_ext_in_category(
|
||||
ext, MediaCategories.EBOOK_TYPES, mime_fallback=True
|
||||
):
|
||||
image = self._epub_cover(_filepath)
|
||||
# Blender ======================================================
|
||||
elif MediaCategories.is_ext_in_category(
|
||||
ext, MediaCategories.BLENDER_TYPES, mime_fallback=True
|
||||
@@ -1060,7 +1089,6 @@ class ThumbRenderer(QObject):
|
||||
ext, MediaCategories.SOURCE_ENGINE_TYPES, mime_fallback=True
|
||||
):
|
||||
image = self._source_engine(_filepath)
|
||||
|
||||
# No Rendered Thumbnail ========================================
|
||||
if not _filepath.exists():
|
||||
raise FileNotFoundError
|
||||
|
||||
BIN
tagstudio/tests/fixtures/sample.epub
vendored
Normal file
BIN
tagstudio/tests/fixtures/sample.epub
vendored
Normal file
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -10,6 +10,18 @@ from src.qt.widgets.thumb_renderer import ThumbRenderer
|
||||
from syrupy.extensions.image import PNGImageSnapshotExtension
|
||||
|
||||
|
||||
def test_epub_preview(cwd, snapshot):
|
||||
file_path: Path = cwd / "fixtures" / "sample.epub"
|
||||
tr = ThumbRenderer()
|
||||
img: Image.Image = tr._epub_cover(file_path)
|
||||
|
||||
img_bytes = io.BytesIO()
|
||||
img.save(img_bytes, format="PNG")
|
||||
img_bytes.seek(0)
|
||||
|
||||
assert img_bytes.read() == snapshot(extension_class=PNGImageSnapshotExtension)
|
||||
|
||||
|
||||
def test_pdf_preview(cwd, snapshot):
|
||||
file_path: Path = cwd / "fixtures" / "sample.pdf"
|
||||
renderer = ThumbRenderer()
|
||||
@@ -18,6 +30,7 @@ def test_pdf_preview(cwd, snapshot):
|
||||
img_bytes = io.BytesIO()
|
||||
img.save(img_bytes, format="PNG")
|
||||
img_bytes.seek(0)
|
||||
|
||||
assert img_bytes.read() == snapshot(extension_class=PNGImageSnapshotExtension)
|
||||
|
||||
|
||||
@@ -29,4 +42,5 @@ def test_svg_preview(cwd, snapshot):
|
||||
img_bytes = io.BytesIO()
|
||||
img.save(img_bytes, format="PNG")
|
||||
img_bytes.seek(0)
|
||||
|
||||
assert img_bytes.read() == snapshot(extension_class=PNGImageSnapshotExtension)
|
||||
|
||||
Reference in New Issue
Block a user