Neon-AI commited on
Commit
c21e3cf
·
verified ·
1 Parent(s): ee72fb7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -40
app.py CHANGED
@@ -1,14 +1,12 @@
1
  from fastapi import FastAPI, HTTPException
2
- from playwright.sync_api import sync_playwright
3
- import os
4
  import requests
5
  from bs4 import BeautifulSoup
6
 
7
- app = FastAPI(title="Neon Anime Scraper")
8
 
9
  @app.get("/")
10
  def home():
11
- return {"status": "Neon Anime Scraper running!"}
12
 
13
  @app.get("/search")
14
  def search_anime(keyword: str):
@@ -74,10 +72,11 @@ def search_anime(keyword: str):
74
  @app.get("/metadata")
75
  def get_metadata(path: str):
76
  """
77
- Example call: /metadata?path=/naruto-677
 
78
  """
79
  try:
80
- full_url = f"https://hianime.to{path}"
81
  headers = {"User-Agent": "Mozilla/5.0"}
82
  resp = requests.get(full_url, headers=headers)
83
  if resp.status_code != 200:
@@ -85,54 +84,72 @@ def get_metadata(path: str):
85
 
86
  soup = BeautifulSoup(resp.text, "html.parser")
87
 
88
- # Title / Japanese / Synonyms
89
- title_elem = soup.select_one("h1.film-name") or soup.select_one("h2.film-name.dynamic-name")
90
- title = title_elem.text.strip() if title_elem else None
91
 
92
- japanese_elem = soup.find("span", string="Japanese:")
93
- japanese = japanese_elem.find_next_sibling("span").text.strip() if japanese_elem else None
 
94
 
95
- synonyms_elem = soup.find("span", string="Synonyms:")
96
- synonyms = synonyms_elem.find_next_sibling("span").text.strip() if synonyms_elem else None
 
 
 
 
 
97
 
98
- # Status, type, duration
99
- status_elem = soup.find("span", string="Status:")
100
- status = status_elem.find_next_sibling("span").text.strip() if status_elem else None
101
 
102
- type_elem = soup.select_one(".tick span.item")
103
- anime_type = type_elem.text.strip() if type_elem else None
 
 
 
 
 
 
104
 
105
- duration_elem = soup.find("span", string="Duration:")
106
- duration = duration_elem.find_next_sibling("span").text.strip() if duration_elem else None
107
 
108
- # Rating, quality, sub_count, dub_count, episodes
109
- tick_items = soup.select(".tick-item")
110
- rating = tick_items[0].text.strip() if len(tick_items) > 0 else None
111
- quality = tick_items[1].text.strip() if len(tick_items) > 1 else None
112
- sub_count = tick_items[2].text.strip() if len(tick_items) > 2 else None
113
- dub_count = tick_items[3].text.strip() if len(tick_items) > 3 else None
114
- episodes = tick_items[4].text.strip() if len(tick_items) > 4 else None
115
 
116
- # Genres
117
- genres = [g.text.strip() for g in soup.select(".item.item-list a[href^='/genre/']")]
 
 
 
118
 
119
- desc_elem = soup.select_one(".anisc-info .item-title:has(span.item-head:contains('Overview:')) .text")
120
- description = desc_elem.text.strip() if desc_elem else None
 
121
 
122
  return {
123
  "title": title,
124
- "japanese": japanese,
125
- "synonyms": synonyms,
126
- "status": status,
127
- "type": anime_type,
128
- "duration": duration,
129
  "rating": rating,
130
  "quality": quality,
131
- "sub_count": sub_count,
132
- "dub_count": dub_count,
133
- "episodes": episodes,
 
 
 
 
 
 
134
  "genres": genres,
135
- "description":description,
 
 
 
 
 
136
  }
137
 
138
  except Exception as e:
 
1
  from fastapi import FastAPI, HTTPException
 
 
2
  import requests
3
  from bs4 import BeautifulSoup
4
 
5
+ app = FastAPI(title="Neon Anime Api")
6
 
7
  @app.get("/")
8
  def home():
9
+ return {"status": "Neon Anime Api Alive"}
10
 
11
  @app.get("/search")
12
  def search_anime(keyword: str):
 
72
  @app.get("/metadata")
73
  def get_metadata(path: str):
74
  """
75
+ Fetch full anime metadata from AniWave.
76
+ Example: /metadata?path=/anime-watch/naruto
77
  """
78
  try:
79
+ full_url = f"https://www.aniwave.se{path}"
80
  headers = {"User-Agent": "Mozilla/5.0"}
81
  resp = requests.get(full_url, headers=headers)
82
  if resp.status_code != 200:
 
84
 
85
  soup = BeautifulSoup(resp.text, "html.parser")
86
 
87
+ # Thumbnail
88
+ thumb_elem = soup.select_one("img[itemprop='image']")
89
+ thumbnail = thumb_elem["src"] if thumb_elem else None
90
 
91
+ # Title
92
+ title_elem = soup.select_one(".names.font-italic.mb-2")
93
+ title = title_elem.text.strip() if title_elem else None
94
 
95
+ # Rating / Quality / Sub / Dub
96
+ rating_elem = soup.select_one(".meta.icons .rating")
97
+ rating = rating_elem.text.strip() if rating_elem else None
98
+ quality_elem = soup.select_one(".meta.icons .quality")
99
+ quality = quality_elem.text.strip() if quality_elem else None
100
+ has_sub = bool(soup.select_one(".meta.icons .sub"))
101
+ has_dub = bool(soup.select_one(".meta.icons .dub"))
102
 
103
+ # Description
104
+ desc_elem = soup.select_one(".synopsis .content")
105
+ description = desc_elem.text.strip() if desc_elem else None
106
 
107
+ # Type, Source, Premiered, Date aired, Broadcast, Status
108
+ bmeta = soup.select_one(".bmeta .meta")
109
+ anime_type = bmeta.select_one("div:contains('Type:') span a").text.strip() if bmeta else None
110
+ source = bmeta.select_one("div:contains('Source:') span").text.strip() if bmeta else None
111
+ premiered = bmeta.select_one("div:contains('Premiered:') span a").text.strip() if bmeta else None
112
+ date_aired = bmeta.select_one("div:contains('Date aired:') span").text.strip() if bmeta else None
113
+ broadcast = bmeta.select_one("div:contains('Broadcast:')").text.replace("Broadcast:", "").strip() if bmeta else None
114
+ status = bmeta.select_one("div:contains('Status:') a").text.strip() if bmeta else None
115
 
116
+ # Genres
117
+ genres = [g.text.strip() for g in bmeta.select("div:contains('Genres:') a")] if bmeta else []
118
 
119
+ # MAL rating
120
+ mal_elem = bmeta.select_one("div:contains('MAL:') span")
121
+ mal_rating = mal_elem.text.strip() if mal_elem else None
 
 
 
 
122
 
123
+ # Duration / Episodes
124
+ duration_elem = bmeta.select_one("div:contains('Duration:')")
125
+ duration = duration_elem.text.replace("Duration:", "").strip() if duration_elem else None
126
+ episodes_elem = bmeta.select_one("div:contains('Episodes:') span")
127
+ total_episodes = episodes_elem.text.strip() if episodes_elem else None
128
 
129
+ # Studios / Producers
130
+ studios = [s.text.strip() for s in bmeta.select("div:contains('Studios:') a span")]
131
+ producers = [p.text.strip() for p in bmeta.select("div:contains('Producers:') a span")]
132
 
133
  return {
134
  "title": title,
 
 
 
 
 
135
  "rating": rating,
136
  "quality": quality,
137
+ "has_sub": has_sub,
138
+ "has_dub": has_dub,
139
+ "description": description,
140
+ "type": anime_type,
141
+ "source": source,
142
+ "premiered": premiered,
143
+ "date_aired": date_aired,
144
+ "broadcast": broadcast,
145
+ "status": status,
146
  "genres": genres,
147
+ "mal_rating": mal_rating,
148
+ "duration": duration,
149
+ "total_episodes": total_episodes,
150
+ "studios": studios,
151
+ "producers": producers,
152
+ "thumbnail": thumbnail,
153
  }
154
 
155
  except Exception as e: