fix view
This commit is contained in:
+33
-11
@@ -135,27 +135,41 @@ class BrowserService:
|
||||
) -> VisitResult:
|
||||
"""Выполняет просмотр страницы."""
|
||||
page = await browser.new_page()
|
||||
|
||||
initial_url = url
|
||||
final_url = url
|
||||
redirect = False
|
||||
reading_completed = False
|
||||
|
||||
try:
|
||||
await page.set_viewport_size({
|
||||
"width": settings.VIEWPORT_WIDTH,
|
||||
"height": settings.VIEWPORT_HEIGHT
|
||||
})
|
||||
|
||||
|
||||
goto_task = asyncio.create_task(
|
||||
page.goto(url, wait_until="commit", timeout=30000)
|
||||
)
|
||||
await self._move_mouse(page, goto_task)
|
||||
await goto_task
|
||||
|
||||
|
||||
initial_url = page.url
|
||||
final_url, redirect = await self._wait_redirect(page, initial_url)
|
||||
|
||||
try:
|
||||
final_url, redirect = await self._wait_redirect(page, initial_url)
|
||||
except Exception as e:
|
||||
logger.warning(f"Redirect wait error (ignored): {e}")
|
||||
final_url = page.url
|
||||
|
||||
await self._simulate_reading(page, reading_time)
|
||||
|
||||
reading_completed = True
|
||||
|
||||
screenshot_path = None
|
||||
if settings.SCREENSHOTS_DIR:
|
||||
screenshot_path = await self._take_screenshot(page, final_url)
|
||||
|
||||
try:
|
||||
screenshot_path = await self._take_screenshot(page, final_url)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return VisitResult(
|
||||
url=url,
|
||||
initial_url=initial_url,
|
||||
@@ -166,12 +180,20 @@ class BrowserService:
|
||||
screenshot_path=screenshot_path,
|
||||
success=True
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception as e:
|
||||
return VisitResult(url=url, reading_time=reading_time,
|
||||
success=False, error=str(e))
|
||||
return VisitResult(
|
||||
url=url,
|
||||
initial_url=initial_url,
|
||||
final_url=final_url,
|
||||
redirect_occurred=redirect,
|
||||
proxy_info=proxy_info,
|
||||
reading_time=reading_time,
|
||||
success=reading_completed,
|
||||
error=str(e) if not reading_completed else None
|
||||
)
|
||||
finally:
|
||||
if page.url == url:
|
||||
logger.error()
|
||||
await page.close()
|
||||
|
||||
async def _move_mouse(self, page, task):
|
||||
|
||||
+52
-31
@@ -165,17 +165,19 @@ class TwitchIRCClient:
|
||||
return False
|
||||
|
||||
async def listen_for_messages(
|
||||
self,
|
||||
on_url_found: Callable[[str, str], Awaitable[None]],
|
||||
duration: int,
|
||||
allowed_domains: Optional[List[str]] = None,
|
||||
is_active: Callable[[], bool] = None, # Функция проверки активности
|
||||
) -> dict:
|
||||
self,
|
||||
on_url_found: Callable[[str, str], Awaitable[None]],
|
||||
duration: int,
|
||||
allowed_domains: Optional[List[str]] = None,
|
||||
is_active: Callable[[], bool] = None,
|
||||
on_drain_fail: Callable[[], Awaitable[None]] = None,
|
||||
) -> dict:
|
||||
stats = {"links_found": 0, "messages": 0, "reconnects": 0}
|
||||
|
||||
|
||||
start_time = datetime.now()
|
||||
last_message_time = datetime.now()
|
||||
|
||||
drain_errors = 0
|
||||
|
||||
if not await self.connect():
|
||||
raise ConnectionError(f"IRC connect failed for #{self.channel}")
|
||||
|
||||
@@ -194,28 +196,47 @@ class TwitchIRCClient:
|
||||
# === ПЕРЕПОДКЛЮЧЕНИЕ КАЖДЫЕ 30 СЕКУНД ===
|
||||
if (datetime.now() - last_message_time).seconds > 30:
|
||||
logger.info("🔄 Reconnecting (30s)...")
|
||||
|
||||
# Сначала читаем всё что осталось
|
||||
try:
|
||||
while True:
|
||||
line = await asyncio.wait_for(self._reader.readline(), timeout=1.0)
|
||||
if not line:
|
||||
break
|
||||
decoded = line.decode('utf-8', errors='ignore').strip()
|
||||
if 'PRIVMSG' in decoded:
|
||||
msg = self._parse_message(decoded)
|
||||
if msg:
|
||||
stats["messages"] += 1
|
||||
for url in self._extract_urls(msg['message']):
|
||||
if self._is_domain_allowed(url, allowed_domains):
|
||||
stats["links_found"] += 1
|
||||
try:
|
||||
await on_url_found(url, msg['display_name'])
|
||||
except Exception as e:
|
||||
logger.warning(f"URL callback error: {e}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error draining IRC data: {e}")
|
||||
|
||||
|
||||
# Сначала читаем всё что осталось (с retry)
|
||||
drain_ok = False
|
||||
for attempt in range(3):
|
||||
try:
|
||||
while True:
|
||||
line = await asyncio.wait_for(self._reader.readline(), timeout=1.0)
|
||||
if not line:
|
||||
break
|
||||
decoded = line.decode('utf-8', errors='ignore').strip()
|
||||
if 'PRIVMSG' in decoded:
|
||||
msg = self._parse_message(decoded)
|
||||
if msg:
|
||||
stats["messages"] += 1
|
||||
for url in self._extract_urls(msg['message']):
|
||||
if self._is_domain_allowed(url, allowed_domains):
|
||||
stats["links_found"] += 1
|
||||
try:
|
||||
await on_url_found(url, msg['display_name'])
|
||||
except Exception as e:
|
||||
logger.warning(f"URL callback error: {e}")
|
||||
drain_ok = True
|
||||
break
|
||||
except asyncio.TimeoutError:
|
||||
drain_ok = True
|
||||
break
|
||||
except Exception as e:
|
||||
logger.warning(f"Error draining IRC data (attempt {attempt + 1}/3): {e}")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
if not drain_ok:
|
||||
drain_errors += 1
|
||||
logger.error(f"IRC drain failed 3 times, total failures: {drain_errors}")
|
||||
if drain_errors >= 3:
|
||||
logger.error("IRC drain failed 3 consecutive times — pausing task")
|
||||
if on_drain_fail:
|
||||
await on_drain_fail()
|
||||
return stats
|
||||
else:
|
||||
drain_errors = 0
|
||||
|
||||
# Переподключаемся
|
||||
try:
|
||||
await self.disconnect()
|
||||
@@ -223,7 +244,7 @@ class TwitchIRCClient:
|
||||
logger.warning(f"Disconnect error: {e}")
|
||||
await asyncio.sleep(1)
|
||||
await self.connect()
|
||||
|
||||
|
||||
stats["reconnects"] += 1
|
||||
last_message_time = datetime.now()
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user