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

Create app/enka_logic.py

Browse files
Files changed (1) hide show
  1. app/enka_logic.py +106 -0
app/enka_logic.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import requests
3
+ import time
4
+ from playwright.async_api import async_playwright
5
+
6
+ FREEIMAGE_API_KEY = "6d207e02198a847aa98d0a2a901485a5"
7
+ FREEIMAGE_URL = "https://freeimage.host/api/1/upload"
8
+
9
+ class EnkaApp:
10
+ def __init__(self):
11
+ self.playwright = None
12
+ self.browser = None
13
+
14
+ async def start(self):
15
+ self.playwright = await async_playwright().start()
16
+ self.browser = await self.playwright.chromium.launch(
17
+ headless=True,
18
+ args=['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu']
19
+ )
20
+ print("🚀 [System] Browser logic started.")
21
+
22
+ async def stop(self):
23
+ if self.browser: await self.browser.close()
24
+ if self.playwright: await self.playwright.stop()
25
+
26
+ async def get_context_page(self, fast_mode=False):
27
+ context = await self.browser.new_context(
28
+ viewport={'width': 1280, 'height': 800},
29
+ 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"
30
+ )
31
+ page = await context.new_page()
32
+ if fast_mode:
33
+ await page.route("**/*", lambda route: route.abort() if route.request.resource_type in ["media", "font"] else route.continue_())
34
+ return context, page
35
+
36
+ async def fetch_info(self, uid: str):
37
+ start_time = time.time()
38
+ context, page = await self.get_context_page(fast_mode=True)
39
+ try:
40
+ await page.goto(f"https://enka.network/u/{uid}/", wait_until="domcontentloaded", timeout=30000)
41
+ try:
42
+ await page.click('button[data-icon="cards"]', timeout=1500)
43
+ await page.wait_for_selector('.Loda .bg', timeout=1500)
44
+ except: pass
45
+
46
+ data = await page.evaluate("""() => {
47
+ const arText = document.querySelector('.ar')?.innerText || "";
48
+ const stats = Array.from(document.querySelectorAll('tr.stat')).map(tr => {
49
+ const style = tr.querySelector('td.icon')?.getAttribute('style') || "";
50
+ const iconMatch = style.match(/url\\(["']?(.*?)["']?\\)/);
51
+ return {
52
+ value: tr.querySelector('td:first-child')?.innerText.trim(),
53
+ label: tr.querySelector('td:last-child')?.innerText.trim(),
54
+ icon: iconMatch ? "https://enka.network" + iconMatch[1].replace(/\\\\/g, "") : null
55
+ };
56
+ });
57
+ const ncBg = document.querySelector('.Loda .bg')?.style.backgroundImage;
58
+ const ncMatch = ncBg ? ncBg.match(/url\\(["']?(.*?)["']?\\)/) : null;
59
+ const characters = Array.from(document.querySelectorAll('.CharacterList .avatar')).map(el => {
60
+ const style = el.querySelector('figure.chara')?.getAttribute('style') || "";
61
+ const path = style.match(/url\\((.*)\\)/)?.[1].replace(/["']/g, "");
62
+ return { name: path?.split('_').pop().split('.')[0], level: el.querySelector('.level')?.innerText, icon: "https://enka.network" + path };
63
+ }).filter(i => i.name);
64
+ return {
65
+ player: {
66
+ name: document.querySelector('.details h1')?.innerText,
67
+ signature: document.querySelector('.signature')?.innerText,
68
+ ar: arText.match(/AR\\s*(\\d+)/i)?.[1], wl: arText.match(/WL\\s*(\\d+)/i)?.[1],
69
+ avatar: "https://enka.network" + document.querySelector('.avatar-icon img')?.getAttribute('src'),
70
+ namecard: ncMatch ? "https://enka.network" + ncMatch[1] : null,
71
+ stats: stats
72
+ },
73
+ characters: characters
74
+ };
75
+ }""")
76
+ await context.close()
77
+ return {"execution_time": f"{round(time.time() - start_time, 2)}s", "uid": uid, **data}
78
+ except Exception as e:
79
+ await context.close()
80
+ return {"error": str(e)}
81
+
82
+ async def fetch_gen(self, uid: str, char: str = None):
83
+ start_time = time.time()
84
+ context, page = await self.get_context_page(fast_mode=False)
85
+ try:
86
+ await page.goto(f"https://enka.network/u/{uid}/", wait_until="domcontentloaded", timeout=30000)
87
+ if char:
88
+ target = char.strip().capitalize()
89
+ try:
90
+ await page.click(f"//div[contains(@class, 'avatar')]//figure[contains(@style, '{target}')]", timeout=3000)
91
+ await asyncio.sleep(0.4)
92
+ except: pass
93
+ await page.click('button[data-icon="image"]')
94
+ await page.wait_for_selector('.Loda img[src^="blob:"]', timeout=15000)
95
+ img_base64 = await page.evaluate("""async () => {
96
+ const img = document.querySelector('.Loda img');
97
+ const res = await fetch(img.src);
98
+ const blob = await res.blob();
99
+ return new Promise(r => { const rd = new FileReader(); rd.onloadend = () => r(rd.result.split(',')[1]); rd.readAsDataURL(blob); });
100
+ }""")
101
+ await context.close()
102
+ res = requests.post(FREEIMAGE_URL, data={"key": FREEIMAGE_API_KEY, "action": "upload", "source": img_base64, "format": "json"}, timeout=15)
103
+ return {"execution_time": f"{round(time.time() - start_time, 2)}s", "uid": uid, "card_url": res.json().get('image', {}).get('url')}
104
+ except Exception as e:
105
+ await context.close()
106
+ return {"error": str(e)}