File size: 2,675 Bytes
d043a72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import io
import os

from fastapi import FastAPI, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
import uvicorn

from config import logger, validate_web_env
from database import init_db
from scraper import (
    download_images_as_pdf_async,
    download_images_as_zip_async,
    fetch_chapter_images_api,
    get_genres_list,
    get_manga_chapters_api,
)


validate_web_env()
init_db()

app = FastAPI(title="Utoon Web API", version="1.0.0")
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/")
async def home():
    return {"status": "online"}


@app.get("/health")
async def health():
    return {"ok": True}


@app.get("/manga/chapters")
async def manga_chapters(url: str = Query(..., description="Utoon manga URL")):
    chapters = await get_manga_chapters_api(url)
    if not chapters:
        raise HTTPException(status_code=404, detail="No chapters found for this URL")
    return {"url": url, "count": len(chapters), "chapters": chapters}


@app.get("/genres")
async def genres():
    return {"genres": get_genres_list()}


@app.get("/chapter/download")
async def chapter_download(
    chapter_id: str = Query(..., description="Chapter ID"),
    manga_slug: str = Query("manga", description="Slug used in output filename"),
    chapter_slug: str = Query("chapter", description="Chapter slug used in output filename"),
    file_format: str = Query("pdf", pattern="^(pdf|zip)$"),
):
    images = await fetch_chapter_images_api(chapter_id)
    if not images:
        raise HTTPException(status_code=404, detail="Could not fetch chapter images")

    try:
        if file_format == "pdf":
            content = await download_images_as_pdf_async(images, manga_slug, chapter_id)
            filename = f"{manga_slug}_chapter-{chapter_slug}.pdf"
            media_type = "application/pdf"
        else:
            content = await download_images_as_zip_async(images, manga_slug, chapter_id)
            filename = f"{manga_slug}_chapter-{chapter_slug}.zip"
            media_type = "application/zip"
    except Exception as exc:
        logger.error("Failed to build %s for chapter %s: %s", file_format, chapter_id, exc)
        raise HTTPException(status_code=500, detail="Failed to generate chapter file") from exc

    return StreamingResponse(
        io.BytesIO(content),
        media_type=media_type,
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


if __name__ == "__main__":
    port = int(os.getenv("PORT", "7860"))
    uvicorn.run("app:app", host="0.0.0.0", port=port)