Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pypdf
pymupdf
google-genai
requests
Pillow
62 changes: 62 additions & 0 deletions scripts/lib/cover.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Orijinal epub'dan kapak resmini çıkarıp eptran-web için küçültür.

web_ingest.push_book() bunu, çağıran taraf açıkça bir kapak vermediyse
kendisi kullanır — böylece convert.py ve backfill_ingest.py'de hiçbir
değişiklik gerekmeden hem yeni kitaplar hem eski kitaplar kapağıyla
birlikte gönderilir.
"""
import io
import os

import ebooklib
from ebooklib import epub

MAX_WIDTH = 400
FALLBACK_MAX_BYTES = 1_000_000


def load_cover(book_slug: str, originals_dir: str = "input/.originals"):
"""
input/.originals/<slug>.epub içinden kapak resmini bulur ve
(bytes, mime) döner. Bulunamazsa ya da hata olursa None.

Resim ~400px genişliğe küçültülüp JPEG'e çevrilir (site küçük bir grid
kartında gösteriyor, DB'ye gömülüyor: birkaç on KB yeter). Pillow yoksa
ham resim <=1MB ise olduğu gibi, değilse atlanır.

Fail-soft: kapak çıkarılamaması çeviri/PR/ingest akışını asla etkilemez.
"""
path = os.path.join(originals_dir, f"{book_slug}.epub")
if not os.path.exists(path):
return None

try:
book = epub.read_epub(path)

item = next(iter(book.get_items_of_type(ebooklib.ITEM_COVER)), None)
if item is None:
images = list(book.get_items_of_type(ebooklib.ITEM_IMAGE))
item = next((i for i in images if "cover" in i.get_name().lower()), None)
if item is None and images:
item = images[0]
if item is None:
return None

raw = item.get_content()
try:
from PIL import Image

img = Image.open(io.BytesIO(raw)).convert("RGB")
if img.width > MAX_WIDTH:
new_h = round(img.height * MAX_WIDTH / img.width)
img = img.resize((MAX_WIDTH, new_h), Image.LANCZOS)
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=82, optimize=True)
return buf.getvalue(), "image/jpeg"
except ImportError:
mime = getattr(item, "media_type", None) or "image/jpeg"
return (raw, mime) if len(raw) <= FALLBACK_MAX_BYTES else None
except Exception as e:
print(f" Uyarı: kapak çıkarılamadı: {e}")
return None
20 changes: 18 additions & 2 deletions scripts/lib/web_ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@

import requests

from lib.cover import load_cover

INGEST_TIMEOUT_SECONDS = 60


def push_book(book_slug: str, chapters: list, title: str,
author: str | None = None, description: str | None = None) -> None:
author: str | None = None, description: str | None = None,
cover: tuple | None = None) -> None:
"""
eptran-web'in /api/ingest'ine bir kitabın TÜM bölümlerini format=txt
olarak gönderir.

chapters: convert.py'nin load_txt_chapters()'ından dönen liste —
her eleman {"title": ..., "body": ...} içerir.
cover : opsiyonel (bytes, mime). Verilmezse input/.originals/<slug>.epub'dan
otomatik çıkarılır (lib/cover.py). eptran-web'de kapak olarak saklanır.

WEB_INGEST_URL : örn. https://eptran-web-virid.vercel.app/api/ingest
WEB_INGEST_SECRET: eptran-web'deki INGEST_SECRET ile AYNI değer
Expand Down Expand Up @@ -68,6 +73,16 @@ def push_book(book_slug: str, chapters: list, title: str,
fname = f"{i + 1:03d}_{book_slug}.txt"
files.append(("files[]", (fname, content.encode("utf-8"), "text/plain")))

# Çağıran açıkça bir kapak vermediyse orijinal epub'dan kendimiz çıkarırız
# (bkz. lib/cover.py) — convert.py ve backfill'in değişmesine gerek kalmaz.
if cover is None:
cover = load_cover(book_slug)

if cover:
cover_bytes, cover_mime = cover
ext = "png" if cover_mime == "image/png" else "jpg"
files.append(("cover", (f"cover.{ext}", cover_bytes, cover_mime)))

try:
resp = requests.post(
url, data=data, files=files,
Expand All @@ -91,4 +106,5 @@ def push_book(book_slug: str, chapters: list, title: str,

print(f" eptran-web'e gönderildi: novelId={result.get('novelId')}, "
f"yeni bölüm={result.get('chaptersCreated')}, "
f"güncellenen bölüm={result.get('chaptersUpdated')}")
f"güncellenen bölüm={result.get('chaptersUpdated')}, "
f"kapak={'evet' if result.get('coverSaved') else 'yok'}")