Hana Celeste commited on
Commit
d9c02b8
·
verified ·
1 Parent(s): 21a329f

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +14 -123
main.py CHANGED
@@ -1,134 +1,25 @@
1
- import asyncio
2
- import requests
3
- import time
4
  from fastapi import FastAPI
5
- from playwright.async_api import async_playwright
 
6
 
7
- app = FastAPI()
8
 
9
- IMGBB_API_KEY = "093dee93ec19418d26cc76f40e053725"
 
 
 
 
10
 
11
- async def get_page(uid: str, fast_mode=False):
12
- p = await async_playwright().start()
13
- browser = await p.chromium.launch(headless=True, args=[
14
- '--no-sandbox',
15
- '--disable-setuid-sandbox',
16
- '--disable-dev-shm-usage',
17
- '--disable-gpu'
18
- ])
19
- context = await browser.new_context(
20
- viewport={'width': 1280, 'height': 800},
21
- user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
22
- )
23
- page = await context.new_page()
24
-
25
- # CHẶN RÁC ĐỂ TĂNG TỐC
26
- async def block_waste(route):
27
- bad_types = ["media", "font", "other"]
28
- if fast_mode: bad_types.extend(["image", "stylesheet"])
29
- if any(x in route.request.url for x in ["google", "analytics", "doubleclick"]):
30
- await route.abort()
31
- else:
32
- await route.continue_()
33
-
34
- await page.route("**/*", block_waste)
35
- await page.goto(f"https://enka.network/u/{uid}/", wait_until="domcontentloaded", timeout=60000)
36
- return browser, page
37
 
38
  @app.get("/info")
39
- async def info(uid: str):
40
- start_time = time.time()
41
- browser, page = await get_page(uid, fast_mode=True)
42
- try:
43
- # CLICK NAMECARD (Dùng try/except thay cho .catch)
44
- try:
45
- await page.click('button[data-icon="cards"]', timeout=3000)
46
- await page.wait_for_selector('.Loda .bg', timeout=3000)
47
- except:
48
- pass # Bỏ qua nếu không có namecard hoặc quá chậm
49
-
50
- data = await page.evaluate("""
51
- () => {
52
- const arText = document.querySelector('.ar')?.innerText || "";
53
- const stats = Array.from(document.querySelectorAll('tr.stat')).map(tr => {
54
- const style = tr.querySelector('td.icon')?.getAttribute('style') || "";
55
- const iconMatch = style.match(/url\\(["']?(.*?)["']?\\)/);
56
- return {
57
- value: tr.querySelector('td:first-child')?.innerText.trim(),
58
- label: tr.querySelector('td:last-child')?.innerText.trim(),
59
- icon: iconMatch ? "https://enka.network" + iconMatch[1].replace(/\\\\/g, "") : null
60
- };
61
- });
62
-
63
- const ncBg = document.querySelector('.Loda .bg')?.style.backgroundImage;
64
- const ncMatch = ncBg ? ncBg.match(/url\\(["']?(.*?)["']?\\)/) : null;
65
-
66
- const characters = Array.from(document.querySelectorAll('.CharacterList .avatar')).map(el => {
67
- const style = el.querySelector('figure.chara')?.getAttribute('style') || "";
68
- const path = style.match(/url\\((.*)\\)/)?.[1].replace(/["']/g, "");
69
- return {
70
- name: path?.split('_').pop().split('.')[0],
71
- level: el.querySelector('.level')?.innerText,
72
- icon: "https://enka.network" + path
73
- };
74
- }).filter(i => i.name);
75
-
76
- return {
77
- player: {
78
- name: document.querySelector('.details h1')?.innerText,
79
- signature: document.querySelector('.signature')?.innerText,
80
- ar: arText.match(/AR\\s*(\\d+)/i)?.[1],
81
- wl: arText.match(/WL\\s*(\\d+)/i)?.[1],
82
- avatar: "https://enka.network" + document.querySelector('.avatar-icon img')?.getAttribute('src'),
83
- namecard: ncMatch ? "https://enka.network" + ncMatch[1] : null,
84
- stats: stats
85
- },
86
- characters: characters
87
- };
88
- }
89
- """)
90
-
91
- await browser.close()
92
- return {"execution_time": f"{round(time.time() - start_time, 2)}s", "uid": uid, **data}
93
- except Exception as e:
94
- if 'browser' in locals(): await browser.close()
95
- return {"error": str(e)}
96
 
97
  @app.get("/gen")
98
- async def generate(uid: str, char: str = None):
99
- start_time = time.time()
100
- browser, page = await get_page(uid, fast_mode=False)
101
- try:
102
- if char:
103
- target = char.strip().capitalize()
104
- try:
105
- await page.click(f"//figure[contains(@style, '{target}')]", timeout=5000)
106
- await asyncio.sleep(0.8)
107
- except: pass
108
-
109
- await page.click('button[data-icon="image"]')
110
- await page.wait_for_selector('.Loda img[src^="blob:"]', timeout=15000)
111
-
112
- img_base64 = await page.evaluate("""
113
- async () => {
114
- const img = document.querySelector('.Loda img');
115
- const res = await fetch(img.src);
116
- const blob = await res.blob();
117
- return new Promise(r => {
118
- const rd = new FileReader();
119
- rd.onloadend = () => r(rd.result.split(',')[1]);
120
- rd.readAsDataURL(blob);
121
- });
122
- }
123
- """)
124
-
125
- await browser.close()
126
- res = requests.post("https://api.imgbb.com/1/upload", data={"key": IMGBB_API_KEY, "image": img_base64}, timeout=20)
127
- return {"execution_time": f"{round(time.time() - start_time, 2)}s", "uid": uid, "card_url": res.json().get('data', {}).get('url')}
128
- except Exception as e:
129
- if 'browser' in locals(): await browser.close()
130
- return {"error": str(e)}
131
 
132
  @app.get("/")
133
  def home():
134
- return {"status": "Enka API Fixed & Running"}
 
 
 
 
1
  from fastapi import FastAPI
2
+ from contextlib import asynccontextmanager
3
+ from app.enka_logic import EnkaApp
4
 
5
+ enka = EnkaApp()
6
 
7
+ @asynccontextmanager
8
+ async def lifespan(app: FastAPI):
9
+ await enka.start()
10
+ yield
11
+ await enka.stop()
12
 
13
+ app = FastAPI(lifespan=lifespan)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  @app.get("/info")
16
+ async def get_info(uid: str):
17
+ return await enka.fetch_info(uid)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  @app.get("/gen")
20
+ async def get_gen(uid: str, char: str = None):
21
+ return await enka.fetch_gen(uid, char)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  @app.get("/")
24
  def home():
25
+ return {"status": "Modular API is Live", "logic": "Loaded from ./app/enka_logic.py"}