1+ """Render sado-reference page and capture full-page screenshot."""
2+ import asyncio
3+ from pathlib import Path
4+ from playwright .async_api import async_playwright
5+
6+ URL = "https://syedos.arif-fazil.com/sado-reference/"
7+ OUT_DIR = Path ("/root/AAA/artifacts/aletta-ocean" )
8+ OUT_DIR .mkdir (parents = True , exist_ok = True )
9+ SCREENSHOT_PATH = OUT_DIR / "live-preview.png"
10+
11+ async def main ():
12+ async with async_playwright () as p :
13+ browser = await p .chromium .launch (headless = True )
14+ context = await browser .new_context (
15+ viewport = {"width" : 1440 , "height" : 900 },
16+ device_scale_factor = 2 ,
17+ )
18+ page = await context .new_page ()
19+
20+ console_msgs = []
21+ page .on ("console" , lambda msg : console_msgs .append (f"[{ msg .type } ] { msg .text } " ))
22+ failed_requests = []
23+ page .on ("requestfailed" , lambda req : failed_requests .append (f"{ req .url } - { req .failure } " ))
24+
25+ print (f"Navigating to { URL } ..." )
26+ response = await page .goto (URL , wait_until = "networkidle" , timeout = 30000 )
27+ print (f"Status: { response .status if response else 'no response' } " )
28+
29+ # Wait 5s for fonts as specified
30+ await page .wait_for_timeout (5000 )
31+
32+ # Verify presence of expected elements
33+ title_visible = await page .locator ("text=ALETTA OCEAN" ).count ()
34+ vs_count = await page .locator ("text=vs" ).count ()
35+ respect_section = await page .locator ("text=Why Abang Sado Respect Dia" ).count ()
36+
37+ # Image checks
38+ imgs = page .locator ("img" )
39+ img_count = await imgs .count ()
40+ img_details = []
41+ for i in range (img_count ):
42+ img = imgs .nth (i )
43+ src = await img .get_attribute ("src" )
44+ alt = await img .get_attribute ("alt" )
45+ natural_w = await img .evaluate ("el => el.naturalWidth" )
46+ natural_h = await img .evaluate ("el => el.naturalHeight" )
47+ complete = await img .evaluate ("el => el.complete" )
48+ img_details .append ({
49+ "src" : src , "alt" : alt ,
50+ "naturalWidth" : natural_w , "naturalHeight" : natural_h ,
51+ "loaded" : complete ,
52+ })
53+
54+ # Layout probe — get bounding boxes of portraits and vs circle
55+ layout = await page .evaluate ("""() => {
56+ const result = {};
57+ // Try to find portrait containers by alt or class
58+ const allImgs = Array.from(document.querySelectorAll('img'));
59+ result.imgCount = allImgs.length;
60+ result.imgs = allImgs.map(i => ({
61+ src: i.src,
62+ alt: i.alt,
63+ rect: i.getBoundingClientRect().toJSON(),
64+ }));
65+ // Look for 'vs' element
66+ const allEls = Array.from(document.querySelectorAll('*'));
67+ const vsEls = allEls.filter(e => e.textContent.trim() === 'vs' && e.children.length === 0);
68+ result.vsElements = vsEls.map(v => ({
69+ text: v.textContent,
70+ tag: v.tagName,
71+ rect: v.getBoundingClientRect().toJSON(),
72+ classes: v.className,
73+ }));
74+ // Get page dimensions
75+ result.pageHeight = document.documentElement.scrollHeight;
76+ result.pageWidth = document.documentElement.scrollWidth;
77+ result.viewportHeight = window.innerHeight;
78+ result.viewportWidth = window.innerWidth;
79+ result.title = document.title;
80+ return result;
81+ }""" )
82+
83+ print ("\n === LAYOUT PROPOSURE ===" )
84+ print (f"Page title: { layout ['title' ]} " )
85+ print (f"Page dimensions: { layout ['pageWidth' ]} x{ layout ['pageHeight' ]} (viewport { layout ['viewportWidth' ]} x{ layout ['viewportHeight' ]} )" )
86+ print (f"Image count: { layout ['imgCount' ]} " )
87+ for i , img in enumerate (layout ['imgs' ]):
88+ print (f" img[{ i } ]: src={ img ['src' ][- 60 :] if img ['src' ] else 'NONE' } alt={ img ['alt' ]} rect=({ img ['rect' ]['width' ]:.0f} x{ img ['rect' ]['height' ]:.0f} @ { img ['rect' ]['x' ]:.0f} ,{ img ['rect' ]['y' ]:.0f} )" )
89+ print (f"vs elements: { len (layout ['vsElements' ])} " )
90+ for v in layout ['vsElements' ]:
91+ print (f" '{ v ['text' ]} ' <{ v ['tag' ]} > class={ v ['classes' ]} rect=({ v ['rect' ]['width' ]:.0f} x{ v ['rect' ]['height' ]:.0f} @ { v ['rect' ]['x' ]:.0f} ,{ v ['rect' ]['y' ]:.0f} )" )
92+
93+ print ("\n === TEXT PROPOSURE ===" )
94+ print (f"'ALETTA OCEAN' matches: { title_visible } " )
95+ print (f"'vs' matches: { vs_count } " )
96+ print (f"'Why Abang Sado Respect Dia' matches: { respect_section } " )
97+
98+ print ("\n === IMAGES ===" )
99+ for img in img_details :
100+ print (f" src={ img ['src' ][- 60 :] if img ['src' ] else 'NONE' } alt={ img ['alt' ]} { img ['naturalWidth' ]} x{ img ['naturalHeight' ]} loaded={ img ['loaded' ]} " )
101+
102+ if failed_requests :
103+ print ("\n === FAILED REQUESTS ===" )
104+ for f in failed_requests :
105+ print (f" { f } " )
106+
107+ if console_msgs :
108+ print ("\n === CONSOLE (last 20) ===" )
109+ for m in console_msgs [- 20 :]:
110+ print (f" { m } " )
111+
112+ # Capture full-page screenshot
113+ print (f"\n === CAPTURING FULL-PAGE SCREENSHOT to { SCREENSHOT_PATH } ===" )
114+ await page .screenshot (path = str (SCREENSHOT_PATH ), full_page = True )
115+ print (f"Screenshot saved: { SCREENSHOT_PATH } " )
116+ print (f"File size: { SCREENSHOT_PATH .stat ().st_size } bytes" )
117+
118+ await browser .close ()
119+
120+ asyncio .run (main ())
0 commit comments