File size: 5,995 Bytes
3ef1dcc bfa341f 3ec3597 bfa341f 7ef1acd 764130c 3ec3597 96d06a6 697c68e 3ec3597 3ef1dcc 764130c 3ef1dcc bfa341f 96d06a6 212e935 3ef1dcc 8b99b89 96d06a6 8b99b89 4c9bee0 96d06a6 3ef1dcc 96d06a6 fce806c 96d06a6 212e935 96d06a6 212e935 96d06a6 212e935 96d06a6 71dd405 96d06a6 71dd405 96d06a6 bfa341f 8b99b89 bfa341f 96d06a6 bfa341f 8b99b89 96d06a6 bfa341f 8b99b89 96d06a6 7ef1acd fce806c 96d06a6 7ef1acd 96d06a6 7ef1acd 96d06a6 7ef1acd 96d06a6 7ef1acd bfa341f 3ec3597 5c25007 96d06a6 5c25007 73c1ed7 3ec3597 3ef1dcc 2b8e58c 96d06a6 bbeae6c f8d2244 764130c f8d2244 96d06a6 f8d2244 5dcf7d0 3ef1dcc f8d2244 3371607 697c68e 021cf6c 3ec3597 | 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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | import mangadex as md
from fastapi import FastAPI, Query, HTTPException
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from reportlab.pdfgen import canvas
import tempfile
import os
from PIL import Image as PILImage
import httpx
import pikepdf
from pathlib import Path
app = FastAPI()
# Serve static files from the "static" directory
app.mount("/static", StaticFiles(directory="static"), name="static")
# Ensure the "static" directory exists
Path("static").mkdir(exist_ok=True)
auth = md.auth.Auth()
@app.get("/mangadex")
async def fetch_and_upload_pdf(
chapter_id: str = Query(..., description="Comma-separated MangaDex chapter IDs to fetch images for"),
as_pdf: bool = Query(True, description="Set to False to return image URLs without creating a PDF"),
page: str = Query(None, description="Specific page(s) to fetch, e.g., '1' or '1-5'")
):
"""
Fetch images from specified chapters and optionally combine them into a single PDF.
"""
try:
chapter_ids = chapter_id.split(",")
all_images = []
# Fetch images for each chapter
chapter = md.series.Chapter(auth=auth)
for chapter_id in chapter_ids:
chapter_data = chapter.get_chapter_by_id(chapter_id=chapter_id)
images = chapter_data.fetch_chapter_images()
if not images:
raise HTTPException(status_code=404, detail=f"No images found for chapter ID {chapter_id}.")
all_images.extend(images)
# Filter images by page if applicable
if page:
pages = []
try:
if '-' in page:
start, end = map(int, page.split('-'))
pages = list(range(start, end + 1))
else:
pages = [int(page)]
except ValueError:
raise HTTPException(status_code=400, detail="Invalid page query format.")
all_images = [all_images[i - 1] for i in pages if 1 <= i <= len(all_images)]
if not all_images:
raise HTTPException(status_code=404, detail="No images found for the selected pages.")
# Return image URLs if not converting to PDF
if not as_pdf:
return JSONResponse(content={"image_urls": all_images})
# Generate PDF from images
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_pdf:
pdf_path = temp_pdf.name
c = canvas.Canvas(pdf_path)
async with httpx.AsyncClient() as client:
for image_url in all_images:
response = await client.get(image_url)
response.raise_for_status()
# Save image to temporary file
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_image:
temp_image.write(response.content)
temp_image_path = temp_image.name
# Process image
img = PILImage.open(temp_image_path)
img = img.convert("RGB")
# Save a converted image (JPEG format)
converted_image_path = temp_image_path + "_converted.jpg"
img.save(converted_image_path, "JPEG")
# Get image dimensions
width, height = img.size
# Add image to PDF
c.setPageSize((width, height))
c.drawImage(converted_image_path, 0, 0, width, height)
c.showPage()
# Clean up temporary files
os.remove(temp_image_path)
os.remove(converted_image_path)
c.save()
# Compress the PDF
compressed_pdf_path = f"static/{chapter_id}_compressed.pdf"
with pikepdf.open(pdf_path) as pdf:
pdf.save(compressed_pdf_path)
# Clean up temporary PDF file
os.remove(pdf_path)
# Return the URL to the compressed PDF
return JSONResponse(content={"file_url": f"/static/{chapter_id}_compressed.pdf"})
except Exception as e:
return JSONResponse(content={"error": f"Failed to process the chapters: {str(e)}"}, status_code=500)
@app.get("/name")
async def fetch_manga_details(
title: str = Query(..., description="Manga title to search for")
):
"""
Fetch manga details by title from MangaDex.
"""
try:
manga = md.series.Manga(auth=auth)
manga_list = manga.get_manga_list(title=title)
if not manga_list:
return JSONResponse(
content={"error": f"No manga found with the title '{title}'"},
status_code=404
)
manga_details = []
for m in manga_list:
manga_details.append({
"id": m.manga_id,
"title": m.title.get("en", "No English Title"),
"alt_titles": m.altTitles,
"description": m.description.get("en", "No English Description"),
"status": m.status,
"content_rating": m.contentRating,
"last_volume": m.lastVolume,
"last_chapter": m.lastChapter,
"year": m.year,
"original_language": m.originalLanguage,
"created_at": str(m.createdAt) if m.createdAt else None,
"uploaded_at": str(getattr(m, "uploadedAt", None))
})
return JSONResponse(content={"manga_list": manga_details})
except Exception as e:
return JSONResponse(
content={"error": f"Failed to fetch manga details: {str(e)}"},
status_code=500
)
@app.get("/")
def root():
"""
Basic root endpoint.
"""
return {"message": "يعني ايه"}
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, workers=4) |