ADM-Purchasing-Tools / app /studio_navigator.py
abdulsalam2121
Add automation bot with Flask and Playwright
5b29309
Raw
History Blame Contribute Delete
6.15 kB
import logging
import re
import time
from typing import Optional
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
from browser_session import BrowserSession
logger = logging.getLogger("bot")
ALL_STUDIOS_URL = "https://www.adultdvdmarketplace.com/xcart/adult_dvd/studios.php"
class StudioNavigator:
def __init__(self, session: BrowserSession):
self.session = session
@property
def page(self):
return self.session.page
# ------------------------------------------------------------------
# Navigate by direct URL
# ------------------------------------------------------------------
def navigate_to_studio_url(self, url: str) -> bool:
"""Go to a studio listing URL, ensuring price ordering is set."""
url = self._ensure_price_sort(url)
logger.info(f"Opening studio URL: {url}")
if not self.session.goto(url):
return False
time.sleep(1)
logger.info("Studio page loaded")
return True
# ------------------------------------------------------------------
# Navigate by studio name
# ------------------------------------------------------------------
def _open_view_all_studios(self) -> bool:
page = self.page
top_studios_selectors = [
"a:has-text('TOP STUDIOS')",
"a:has-text('Top Studios')",
"button:has-text('TOP STUDIOS')",
"button:has-text('Top Studios')",
]
for sel in top_studios_selectors:
try:
menu = page.locator(sel).first
if menu.is_visible(timeout=1000):
try:
menu.hover(timeout=1000)
except Exception:
pass
menu.click()
time.sleep(1.5)
break
except Exception:
continue
view_all_selectors = [
"a:has-text('VIEW ALL STUDIOS...')",
"a:has-text('VIEW ALL STUDIOS')",
"a:has-text('View All Studios')",
"button:has-text('VIEW ALL STUDIOS')",
"button:has-text('View All Studios')",
]
for sel in view_all_selectors:
try:
link = page.locator(sel).first
if link.is_visible(timeout=2000):
logger.info(f"Found View All Studios link with selector: {sel}")
link.click()
page.wait_for_load_state("domcontentloaded", timeout=10000)
time.sleep(1)
logger.info("Opened all studios directory from menu")
return True
except Exception as e:
logger.debug(f"Failed to find/click VIEW ALL STUDIOS with {sel}: {e}")
continue
logger.warning("Could not open View All Studios from menu; using directory URL")
return self.session.goto(ALL_STUDIOS_URL)
def _click_studio_link(self, studio_name: str) -> bool:
page = self.page
escaped = re.escape(studio_name.strip())
patterns = [
re.compile(rf"^{escaped}\s+DVD Movies$", re.I),
re.compile(rf"^{escaped}$", re.I),
re.compile(escaped, re.I),
]
for attempt in range(1, 4):
try:
# Wait for studio directory content to render before searching links.
page.locator("a:has-text('DVD Movies')").first.wait_for(timeout=4000)
except Exception:
pass
for pattern in patterns:
try:
link = page.get_by_role("link", name=pattern).first
if link.is_visible(timeout=2000):
link.click()
page.wait_for_load_state("domcontentloaded", timeout=10000)
time.sleep(1)
return True
except Exception:
continue
try:
anchors = page.locator("a").all()
target = studio_name.lower().strip()
for anchor in anchors:
try:
text = anchor.inner_text(timeout=500).strip().lower()
if target in text and "dvd movies" in text:
anchor.click()
page.wait_for_load_state("domcontentloaded", timeout=10000)
time.sleep(1)
return True
except Exception:
continue
except Exception:
pass
if attempt < 3:
logger.warning(f"Studio link not found on attempt {attempt}; reloading all studios directory")
self.session.goto(ALL_STUDIOS_URL)
time.sleep(1)
return False
def find_studio_by_name(self, studio_name: str) -> Optional[str]:
"""Open the all-studios directory from the menu and click the matching studio."""
logger.info(f"Searching for studio: '{studio_name}'")
if not self._open_view_all_studios():
return None
if self._click_studio_link(studio_name):
current_url = self.page.url
logger.info(f"Opened studio page: {current_url}")
return self._ensure_price_sort(current_url)
logger.warning(f"Could not click studio link for: {studio_name}")
return None
# ------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------
@staticmethod
def _ensure_price_sort(url: str) -> str:
if "order_by=" in url:
return url
sep = "&" if "?" in url else "?"
return f"{url}{sep}order_by=price"
@staticmethod
def _make_absolute(href: str, base: str = "https://www.adultdvdmarketplace.com/xcart/") -> str:
if href.startswith("http"):
return href
from urllib.parse import urljoin
return urljoin(base, href)