
    i=2                     \    d Z ddlZddlZddlZddlmZ ddlmZmZm	Z	  G d d          Z
dS )z
Browser Base Implementation - Persistent Firefox Browser Management

This module implements the base persistent Firefox browser that stays alive across
multiple requests, eliminating the overhead of browser startup/shutdown.
    N)Optional)async_playwrightBrowserContext
Playwrightc                   x    e Zd ZdZddedefdZd ZdefdZ	d	 Z
d
 Zd Zd Zd Zd Zd ZdefdZdefdZdS )PersistentBrowserBasea  
    Base class for persistent Firefox browser management.
    
    This class maintains a single Firefox browser context that stays alive
    throughout the application lifetime, providing significant performance
    benefits over opening/closing browsers for each request.
      user_data_dirslowmoc                 L    || _         || _        d| _        d| _        d| _        dS )z
        Initialize the persistent browser.
        
        Args:
            user_data_dir (str): Path to Firefox profile directory for persistence
            slowmo (int): Delay in milliseconds between browser actions (default: 500)
        N)r
   r   
playwrightbrowser_contextbrowser)selfr
   r   s      5/home/byschii/byschiidev/penelope/lib/browser_base.py__init__zPersistentBrowserBase.__init__   s/     + 159=    c                    K   |                                  s|                                  d{V  | j                            d           dS )z.Initialize the browser context asynchronously.Na  
            Object.defineProperty(navigator, 'webdriver', {
                get: () => undefined
            });

            window.chrome = {
                runtime: {}
            };
            
            // More realistic plugins
            Object.defineProperty(navigator, 'plugins', {
                get: () => [
                    {name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format'},
                    {name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: ''},
                    {name: 'Native Client', filename: 'internal-nacl-plugin', description: ''}
                ]
            });
            
            // Languages
            Object.defineProperty(navigator, 'languages', {
                get: () => ['en-US', 'en']
            });
            
            // Platform
            Object.defineProperty(navigator, 'platform', {
                get: () => 'Linux x86_64'
            });
            
            // Hardware concurrency (CPU cores)
            Object.defineProperty(navigator, 'hardwareConcurrency', {
                get: () => 4
            });
            
            // DeviceMemory
            Object.defineProperty(navigator, 'deviceMemory', {
                get: () => 8
            });

                                             
            const originalGetContext = HTMLCanvasElement.prototype.getContext;
            HTMLCanvasElement.prototype.getContext = function(type, attributes) {
                const context = originalGetContext.call(this, type, attributes);
                
                if (type === 'webgl' || type === 'webgl2' || type === 'experimental-webgl') {
                    const getParameter = context.getParameter.bind(context);
                    
                    context.getParameter = function(parameter) {
                        // Vendor
                        if (parameter === 7936) {
                            return 'WebKit';
                        }
                        // Renderer
                        if (parameter === 7937) {
                            return 'WebKit WebGL';
                        }
                        // Unmasked vendor
                        if (parameter === 37445) {
                            return 'Intel Inc.';
                        }
                        // Unmasked renderer
                        if (parameter === 37446) {
                            return 'Intel(R) Iris(TM) Plus Graphics 640';
                        }
                        
                        return getParameter(parameter);
                    };
                    
                    // Also spoof the extension
                    const getSupportedExtensions = context.getSupportedExtensions.bind(context);
                    context.getSupportedExtensions = function() {
                        const extensions = getSupportedExtensions();
                        // Optionally filter out or add extensions
                        return extensions;
                    };
                }
                
                return context;
            };

        )is_initialized_initialize_browser_contextr   add_init_scriptr   s    r   
initializez PersistentBrowserBase.initialize(   sn      ""$$ 	522444444444,, O. O	 O	 O	 O	 O	r   returnc                 &    | j         duo| j        duS )z,Check if the browser is already initialized.N)r   r   r   s    r   r   z$PersistentBrowserBase.is_initialized~   s    d*Ot/C4/OOr   c                   K   	 t                                                       d{V | _        |                                  d{V  t	          d           t	          dt          | j        j                              dS # t          $ r2}t	          d|            | 	                                 d{V   d}~ww xY w)a"  
        Initialize the persistent Firefox browser context.
        
        Creates a Firefox browser with persistent profile that stays open
        across multiple operations. Uses slowmo for human-like behavior.
        Can either launch new browser or connect to existing one.
        Nu4   ✅ Firefox browser context initialized successfullyu   🌐 Browser pages available: u*   ❌ Failed to initialize browser context: )
r   startr   _launch_new_browserprintlenr   pages	Exception_cleanup_on_error)r   es     r   r   z1PersistentBrowserBase._initialize_browser_context   s      	$4$6$6$<$<$>$>>>>>>>DO **,,,,,,,,,IJJJT3t7K7Q3R3RTTUUUUU 	 	 	BqBBCCC((*********	s   A=B 
B?-B::B?c                   K   t          d           t          d| j                    t          d| j         d           t          j        | j        d           t          j        dd          }|r'|                                }t          d	|            ng d
}t          d|            | j        j        	                    | j        d| j        dgd|           d{V | _
        dS )z)Launch a new persistent Chromium browser.u&   🔥 Launching new Chromium browser...u   📁 Profile directory: u   ⏱️  Slowmo delay: msT)exist_okCHROME_FLAGS u"   🚀 Using Chrome flags from env: )z--no-sandboxz--disable-dev-shm-usagez--disable-gpuz---disable-features=WebRtcHideLocalIpsWithMdnsu!   🚀 Using default Chrome flags: Fz--disable-extensions)r
   headlessslow_moignore_default_argsno_viewportargsN)r   r
   r   osmakedirsgetenvsplitr   chromiumlaunch_persistent_contextr   )r   chrome_flags_envchrome_flagss      r   r   z)PersistentBrowserBase._launch_new_browser   s:     7888=);==>>>6t{666777 	D&6666 9^R88 	F+1133LE|EEFFFF  L DlDDEEE &*_%=%W%W,K!7 8 &X 
&
 
&
 
 
 
 
 
 
 
 
 
 
 
 
r   c                 R  K   | j         r/	 | j                                          d{V  n#  Y nxY wd| _         | j        r/	 | j                                         d{V  n#  Y nxY wd| _        | j        r1	 | j                                         d{V  n#  Y nxY wd| _        dS dS )z+Clean up resources if initialization fails.N)r   closer   r   stopr   s    r   r#   z'PersistentBrowserBase._cleanup_on_error   s       	(*002222222222#'D < 	 l((**********DL? 	#o**,,,,,,,,,,"DOOO	# 	#s    + /A! !A%7B Bc                 H  K   t          d           	 | j        rGt          d           | j        j        D ]$}	 |                                 d{V  #  Y "xY wd| _        | j        rXt          d           t          j        | j                                        d           d{V  d| _        t          d           | j        rXt          d           t          j        | j                                        d           d{V  d| _        t          d	           t          d
           dS # t
          j	        $ r( t          d           d| _        d| _        d| _        Y dS t          $ r2}t          d|            d| _        d| _        d| _        Y d}~dS d}~ww xY w)zM
        Gracefully close the browser context and cleanup resources.
        u*   🔒 Closing persistent browser context...u   📄 Closing all pages...Nu"   🔌 Disconnecting from browser...g      $@)timeoutu   ✅ Browser disconnectedu   🎭 Stopping Playwright...u   ✅ Playwright stoppedu+   🎉 Browser cleanup completed successfullyu4   ⚠️ Browser cleanup timed out, forcing cleanup...u%   ⚠️ Error during browser cleanup: )r   r   r!   r8   r   asynciowait_forr   r9   TimeoutErrorr"   )r   pager$   s      r   r8   zPersistentBrowserBase.close   s      	:;;;-	## ,1222 06  D"jjll******** (,$| 2:;;;&t|'9'9';';TJJJJJJJJJJ#0111 03444&t';';'='=tLLLLLLLLLL"&.///?@@@@@# 	# 	# 	#HIII#'D DL"DOOOO 	# 	# 	#=!==>>>#'D DL"DOOOOOOO	#s5   $D0 AD0 ACD0 03F!&	F!/'FF!c                 |    | j         | j        | j        &t          d           d| _         d| _        d| _        dS dS )z
        Destructor to ensure browser cleanup when object is destroyed.
        
        This is a safety net to prevent resource leaks if close() is not
        explicitly called. Note: In async context, this should not be relied upon.
        NuD   🚨 Browser cleanup via destructor (should call close() explicitly))r   r   r   r   r   s    r   __del__zPersistentBrowserBase.__del__  sN     +t|/G4?KfXYYY#'D DL"DOOO LgKfr   c                 >   K   |                                   d{V  | S )zAsync context manager entry.N)r   r   s    r   
__aenter__z PersistentBrowserBase.__aenter__  s-      oor   c                 >   K   |                                   d{V  dS )zAsync context manager exit.NF)r8   )r   exc_typeexc_valexc_tbs       r   	__aexit__zPersistentBrowserBase.__aexit__"  s+      jjllur   c                    K   	 | j         sdS | j         j        }t          |          dk    S # t          $ r}t	          d|            Y d}~dS d}~ww xY w)z
        Check if the browser context is alive and responsive.
        
        Returns:
            bool: True if browser context is alive, False otherwise
        Fr   u-   ⚠️  Browser context health check failed: N)r   r!   r    r"   r   r   r!   r$   s      r   is_alivezPersistentBrowserBase.is_alive'  s{      
	' u (.Eu::?" 	 	 	E!EEFFF55555	s   , , 
AAAc                    K   | j         sddd| j        dS 	 | j         j        }ddt          |          | j        | j        dS # t
          $ r"}dt          |          | j        d	cY d}~S d}~ww xY w)
z
        Get current status information about the browser context.
        
        Returns:
            dict: Status information including context state and page count
        not_initializedNr   )statuscontextr!   profile_diractivezFirefox persistent context)rN   rO   r!   rP   r   error)rN   rR   rP   )r   r
   r!   r    r   r"   strrJ   s      r   
get_statusz PersistentBrowserBase.get_status:  s       # 	+#1	  	(.E"7U#1+    	 	 	!Q#1       	s   *A 
A.A)#A.)A.N)r	   )__name__
__module____qualname____doc__rS   intr   r   boolr   r   r   r#   r8   rA   rC   rH   rK   dictrT    r   r   r   r      s         c 3     T T TlP P P P P  2$
 $
 $
P# # #.3# 3# 3#j# # #  
  
    &$      r   r   )rX   r/   sysr<   typingr   patchright.async_apir   r   r   r   r\   r   r   <module>r`      s     
			 



        N N N N N N N N N NH H H H H H H H H Hr   