library and toc navigation
Python CI / test (push) Successful in 4m30s

This commit is contained in:
2025-11-08 12:20:23 +01:00
parent 60426432a0
commit 284a6e3393
13 changed files with 2365 additions and 219 deletions
+77 -3
View File
@@ -7,6 +7,9 @@ from typing import List, Dict, Optional
from dreader import create_ebook_reader
import base64
from io import BytesIO
from PIL import Image
import ebooklib
from ebooklib import epub
def scan_book_directory(directory: Path) -> List[Dict[str, str]]:
@@ -53,9 +56,9 @@ def extract_book_metadata(epub_path: Path, include_cover: bool = True) -> Option
'author': reader.book_author or 'Unknown Author',
}
# Extract cover image if requested
# Extract cover image if requested - use direct EPUB extraction
if include_cover:
cover_data = extract_cover_as_base64(reader)
cover_data = extract_cover_from_epub(epub_path)
metadata['cover_data'] = cover_data
return metadata
@@ -75,6 +78,9 @@ def extract_cover_as_base64(reader, max_width: int = 300, max_height: int = 450)
"""
Extract cover image from reader and return as base64 encoded string.
This function is kept for backward compatibility but now uses extract_cover_from_epub
internally if the reader has an epub_path attribute.
Args:
reader: EbookReader instance with loaded book
max_width: Maximum width for cover image
@@ -84,7 +90,11 @@ def extract_cover_as_base64(reader, max_width: int = 300, max_height: int = 450)
Base64 encoded PNG image string or None
"""
try:
# Get first page as cover
# If the reader has an epub path, try to extract actual cover
if hasattr(reader, '_epub_path') and reader._epub_path:
return extract_cover_from_epub(reader._epub_path, max_width, max_height)
# Fallback to first page as cover
cover_image = reader.get_current_page()
# Resize if needed
@@ -104,6 +114,70 @@ def extract_cover_as_base64(reader, max_width: int = 300, max_height: int = 450)
return None
def extract_cover_from_epub(epub_path: Path, max_width: int = 300, max_height: int = 450) -> Optional[str]:
"""
Extract the actual cover image from an EPUB file.
Args:
epub_path: Path to EPUB file
max_width: Maximum width for cover image
max_height: Maximum height for cover image
Returns:
Base64 encoded PNG image string or None
"""
try:
# Read the EPUB
book = epub.read_epub(str(epub_path))
# Look for cover image
cover_image = None
# First, try to find item marked as cover
for item in book.get_items():
if item.get_type() == ebooklib.ITEM_COVER:
cover_image = Image.open(BytesIO(item.get_content()))
break
# If not found, look for files with 'cover' in the name
if not cover_image:
for item in book.get_items():
if item.get_type() == ebooklib.ITEM_IMAGE:
name = item.get_name().lower()
if 'cover' in name:
cover_image = Image.open(BytesIO(item.get_content()))
break
# If still not found, get the first image
if not cover_image:
for item in book.get_items():
if item.get_type() == ebooklib.ITEM_IMAGE:
try:
cover_image = Image.open(BytesIO(item.get_content()))
break
except:
continue
if not cover_image:
return None
# Resize if needed (maintain aspect ratio)
if cover_image.width > max_width or cover_image.height > max_height:
cover_image.thumbnail((max_width, max_height), Image.Resampling.LANCZOS)
# Convert to base64
buffer = BytesIO()
cover_image.save(buffer, format='PNG')
img_bytes = buffer.getvalue()
img_base64 = base64.b64encode(img_bytes).decode('utf-8')
return img_base64
except Exception as e:
print(f"Error extracting cover from EPUB {epub_path}: {e}")
return None
def get_chapter_list(reader) -> List[Dict]:
"""
Get formatted chapter list from reader.