Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,30 +10,6 @@ app = FastAPI(title="Neon Anime Scraper")
|
|
| 10 |
def home():
|
| 11 |
return {"status": "Neon Anime Scraper running!"}
|
| 12 |
|
| 13 |
-
@app.get("/api/episode")
|
| 14 |
-
def get_episode(anime: str, episode: int, dub: str = "sub"):
|
| 15 |
-
if not anime or not episode:
|
| 16 |
-
raise HTTPException(status_code=400, detail="anime and episode required")
|
| 17 |
-
|
| 18 |
-
try:
|
| 19 |
-
with sync_playwright() as p:
|
| 20 |
-
browser = p.chromium.launch(headless=True)
|
| 21 |
-
page = browser.new_page()
|
| 22 |
-
url = f"https://hianime.tv/{anime}-episode-{episode}"
|
| 23 |
-
page.goto(url)
|
| 24 |
-
video_element = page.query_selector("video source")
|
| 25 |
-
stream_url = video_element.get_attribute("src") if video_element else None
|
| 26 |
-
browser.close()
|
| 27 |
-
|
| 28 |
-
if not stream_url:
|
| 29 |
-
raise HTTPException(status_code=404, detail="Stream URL not found")
|
| 30 |
-
|
| 31 |
-
return {"anime": anime, "episode": episode, "dub": dub, "streamUrl": stream_url}
|
| 32 |
-
|
| 33 |
-
except Exception as e:
|
| 34 |
-
raise HTTPException(status_code=500, detail=f"Failed to scrape episode: {str(e)}")
|
| 35 |
-
|
| 36 |
-
# ===== PATCH: /search endpoint =====
|
| 37 |
@app.get("/search")
|
| 38 |
def search_anime(keyword: str):
|
| 39 |
try:
|
|
@@ -44,13 +20,7 @@ def search_anime(keyword: str):
|
|
| 44 |
raise HTTPException(status_code=500, detail="Failed to fetch search page")
|
| 45 |
|
| 46 |
soup = BeautifulSoup(resp.text, "html.parser")
|
| 47 |
-
|
| 48 |
-
# Only grab the actual search results container
|
| 49 |
-
search_section = soup.select_one(".search-result") # <-- correct container class
|
| 50 |
-
if not search_section:
|
| 51 |
-
return {"keyword": keyword, "results": []}
|
| 52 |
-
|
| 53 |
-
items = search_section.select(".film-name") # only titles inside search results
|
| 54 |
|
| 55 |
results = []
|
| 56 |
for item in items:
|
|
@@ -59,7 +29,7 @@ def search_anime(keyword: str):
|
|
| 59 |
title = title_elem.text.strip() if title_elem else None
|
| 60 |
url = title_elem["href"] if title_elem else None
|
| 61 |
|
| 62 |
-
# thumbnail
|
| 63 |
thumb_elem = item.find_previous("img", class_="film-poster-img")
|
| 64 |
thumbnail = None
|
| 65 |
if thumb_elem:
|
|
@@ -72,9 +42,6 @@ def search_anime(keyword: str):
|
|
| 72 |
"thumbnail": thumbnail
|
| 73 |
})
|
| 74 |
|
| 75 |
-
# Optional: move exact matches to the top
|
| 76 |
-
results.sort(key=lambda r: 0 if r["title"].lower().startswith(keyword.lower()) else 1)
|
| 77 |
-
|
| 78 |
return {"keyword": keyword, "results": results}
|
| 79 |
|
| 80 |
except Exception as e:
|
|
|
|
| 10 |
def home():
|
| 11 |
return {"status": "Neon Anime Scraper running!"}
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
@app.get("/search")
|
| 14 |
def search_anime(keyword: str):
|
| 15 |
try:
|
|
|
|
| 20 |
raise HTTPException(status_code=500, detail="Failed to fetch search page")
|
| 21 |
|
| 22 |
soup = BeautifulSoup(resp.text, "html.parser")
|
| 23 |
+
items = soup.select(".film-name") # each item container
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
results = []
|
| 26 |
for item in items:
|
|
|
|
| 29 |
title = title_elem.text.strip() if title_elem else None
|
| 30 |
url = title_elem["href"] if title_elem else None
|
| 31 |
|
| 32 |
+
# thumbnail
|
| 33 |
thumb_elem = item.find_previous("img", class_="film-poster-img")
|
| 34 |
thumbnail = None
|
| 35 |
if thumb_elem:
|
|
|
|
| 42 |
"thumbnail": thumbnail
|
| 43 |
})
|
| 44 |
|
|
|
|
|
|
|
|
|
|
| 45 |
return {"keyword": keyword, "results": results}
|
| 46 |
|
| 47 |
except Exception as e:
|