+
    >i;                        R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
Ht ]P                  ! ]4      tRtRt ! R R4      tR	 R
 ltR# )ui  
Flow Token Service — uses headless Playwright to automatically extract
project_id and fresh reCAPTCHA tokens from labs.google/fx.

This service:
1. Loads labs.google/fx with the user's cookies
2. Intercepts network requests to capture the project_id
3. Extracts reCAPTCHA tokens on-demand via grecaptcha.enterprise.execute()
4. Keeps the browser alive so tokens can be refreshed without reloading

Usage:
    service = FlowTokenService(session_token, csrf_token)
    await service.start()
    project_id = service.project_id
    recaptcha_token = await service.get_fresh_recaptcha_token()
    await service.stop()
)annotationsN)Path)Optional(6LdsFiUsAAAAAIjVDZcuLhaHiDn5nnHVXVRQGeMVz%https://labs.google/fx/tools/image-fxc                  `    ] tR t^#tRtR R ltRR R lltR R ltR R	 ltR
 R lt	R t
RtR# )FlowTokenServicez<Headless browser service that extracts Flow API credentials.c                    V ^8  d   QhRRRR/# )   session_tokenstr
csrf_token )formats   "Y/home/gabslocked/Desktop/Projetos/Images/video_automation/providers/flow_token_service.py__annotate__FlowTokenService.__annotate__&   s           c                	r    Wn         W n        R V n        R V n        R V n        R V n        R V n        RV n        R # )NF)r
   r   
project_id_recaptcha_token_browser_context_page_running)selfr
   r   s   &&&r   __init__FlowTokenService.__init__&   s:    
 +$)-/3
r   c                    V ^8  d   QhRRRR/# )r	   
timeout_msintreturndictr   )r   s   "r   r   r   5   s     f fc fd fr   c                  a a"   ^ RI Hp RRRRRR/p V! 4       P                  4       G Rj  xL
 S n        S P                  P                  P                  RRR.R	7      G Rj  xL
 S n        S P                  P                  R
RRRR/R7      G Rj  xL
 S n        S P                  P                  RRRS P                  RRRRRRRRRR/RRRS P                  RRRRRRRRRR/.4      G Rj  xL
  S P                  P                  4       G Rj  xL
 S n        RoVV 3R lpS P                  P                  RV4       \        P!                  R\"        4       S P                  P%                  \"        RVR 7      G Rj  xL
  \        P!                  R!S P                  P&                  4       \(        P*                  ! ^4      G Rj  xL
  S'       gC    S P                  P-                  R"4      G Rj  xL
 oS'       d   \        P!                  R#S4       S P2                  '       g    S P5                  4       G Rj  xL
 S n        S'       g/   \        P!                  R&4        S P9                  4       G Rj  xL
 oSS n        SVR&   S P2                  VR&   RS n        \        P!                  R(S;'       g    R)\?        S P2                  4      4       V#  EL ELp ELE EL EL ELd EL L  \.         d!   p\        P1                  R$T4        Rp?LRp?ii ; i L  \.         d!   p\        P7                  R%T4        Rp?LRp?ii ; i L  \.         d!   p\        P7                  R'T4        Rp?LRp?ii ; i  \.         dI   p\A        T4      TR&   \        PC                  R*T4       S PE                  4       G Rj  xL 
   Rp?T# Rp?ii ; i5i)+z
Launch headless browser, navigate to labs.google/fx, and extract credentials.

Returns dict with:
    - project_id: str or None
    - recaptcha_token: str or None
    - error: str or None
)async_playwrightr   Nrecaptcha_tokenerrorTz--no-sandboxz---disable-blink-features=AutomationControlled)headlessargszeMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36widthi   heighti   )
user_agentviewportnamez __Secure-next-auth.session-tokenvaluedomainzlabs.googlepath/securehttpOnlysameSiteLaxz__Host-next-auth.csrf-tokenc                  <"   V P                   p\        P                  ! R V4      pV'       d(   VP                  ^4      o	\        P                  RS	4       RV9   Ed    V P                  pV'       d   \        P                  ! V4      pVP                  R4      ;'       g    VP                  R/ 4      pVP                  R4      ;'       g    VP                  R4      pV'       d   Vo	\        P                  RV4       VP                  R4      ;'       g    VP                  R	/ 4      pVP                  R
4      pV'       d)   VS
n
        \        P                  R\        V4      4       R# R# R# R#   \         d     R# i ; i5i)z2aisandbox-pa\.googleapis\.com/v1/projects/([^/]+)/z$Captured project_id from request: %szaisandbox-pa.googleapis.comclientContextclient_context	projectIdr   z!Captured project_id from body: %srecaptchaContextrecaptcha_contexttokenz.Captured reCAPTCHA token from request (len=%d)N)urlresearchgrouploggerinfo	post_datajsonloadsgetr   len	Exception)requestr<   matchbodydatactxpidrecapr;   captured_project_idr   s   &        r   
on_request*FlowTokenService.start.<locals>.on_requestp   sC    kk		I */++a.'KK FH[\ 1C7&00#'::d#3D"&((?";"]"]txxHXZ\?]C"%''+"6"O"O#'',:OC"69 3 &,OQT U %(GG,>$?$c$c377K^`bCcE$)IIg$6E$8= 5 &,\^abg^h i  %   8$ % sN   AFE0 3-E0 !*E0 E0 &/E0 +E0 &E0 (F0E?;F>E??FrH   zNavigating to %s...networkidle)
wait_untiltimeoutzPage loaded: %saL  
                        () => {
                            // Deep search: recursively look for projectId in __NEXT_DATA__
                            const nextData = document.getElementById('__NEXT_DATA__');
                            if (nextData) {
                                try {
                                    const text = nextData.textContent;
                                    // Regex search for projectId pattern
                                    const match = text.match(/"projectId"\s*:\s*"([a-z0-9]+)"/);
                                    if (match) return match[1];
                                } catch(e) {}
                            }
                            // Search all script tags for projectId
                            const scripts = document.querySelectorAll('script');
                            for (const s of scripts) {
                                const t = s.textContent || '';
                                const match = t.match(/projectId['"\s:=]+['"]([a-z0-9]{10,})['"]/);
                                if (match) return match[1];
                            }
                            // Check window/global
                            if (window.__PROJECT_ID__) return window.__PROJECT_ID__;
                            return null;
                        }
                    zFound project_id in page JS: %sz(Could not extract project_id from JS: %sz%Could not extract reCAPTCHA token: %szHproject_id not found passively. Triggering a generation to capture it...z(Could not trigger project_id capture: %sz4Auto-setup complete: project_id=%s, has_recaptcha=%sz	NOT FOUNDzAuto-setup failed: %s)#playwright.async_apir#   start_pwchromiumlaunchr   new_contextr   add_cookiesr
   r   new_pager   onr@   rA   LABS_URLgotor<   asynciosleepevaluaterG   debugr   _extract_recaptcha_tokenwarning_trigger_and_capture_project_idr   r   boolr   r%   stop)r   r   r#   resultrP   erO   s   f&    @r   rV   FlowTokenService.start5   s     	:&7wMW	-/5577DH"&(("3"3":":"C #; # DM #'--";";I "437 #< # DM --++>T//mCd 9T__mCd-   *  $}}5577DJ #' D JJMM)Z0 KK-x8**//(}j/YYYKK)4::>>: --""" 'P04

0C0C E 1 +'0 +$EGZ[
 (((O262O2O2Q,QD)
 'fgR040T0T0V*V' 2DO#6F< (,(=(=F$% DMKKF#22{T**+ q 8* 8V Z #
+4 ! PLL!KQOOP -R  ONN#JANNO +W  RNN#MqQQR  	!!fF7OLL0!4))+	s  O
M4 K5M4 "K#-M4 KAM4 *K+!M4 KA-M4 :K;AM4 K!M4 K& .K$/K& ;K& M4 $L 7L8	L M4 	M4 M 2M3M 7:M4 2M4 O
M4 M4 M4 M4 M4 M4 !M4 $K& &L1LM4 LM4 L M!L<7M4 <MM4 M M1M,'M4 ,M11M4 4O?7O6N97O<O
OO
c                   V ^8  d   QhRR/# r	   r    zOptional[str]r   )r   s   "r   r   r      s     + + +r   c                d  "   V P                   '       g   R#  V P                   P                  RRR7      G Rj  xL
  T P                   P                  R	\         R
\         R24      G Rj  xL
 pT'       d    \        P                  R\        T4      4       T#  L_  \         d    \        P	                  R4       \
        P                  ! ^4      G Rj  xL 
   T P                   P                  RRR7      G Rj  xL 
   L  \         d    \        P	                  R4         R# i ; ii ; i L5i)z>Execute reCAPTCHA Enterprise on the page to get a fresh token.NzW() => typeof grecaptcha !== 'undefined' && typeof grecaptcha.enterprise !== 'undefined'i'  rT   z>grecaptcha.enterprise not found on page, trying alternative...z'() => typeof grecaptcha !== 'undefined'i  zNo grecaptcha found at allz
            async () => {
                try {
                    if (typeof grecaptcha !== 'undefined' && grecaptcha.enterprise) {
                        const token = await grecaptcha.enterprise.execute('z', {action: 'generate'});
                        return token;
                    }
                    if (typeof grecaptcha !== 'undefined' && grecaptcha.execute) {
                        const token = await grecaptcha.execute('z', {action: 'generate'});
                        return token;
                    }
                    return null;
                } catch(e) {
                    return null;
                }
            }
        z(Extracted fresh reCAPTCHA token (len=%d))r   wait_for_functionrG   r@   re   r`   ra   rb   RECAPTCHA_SITE_KEYrA   rF   )r   r;   s   & r   rd   )FlowTokenService._extract_recaptcha_token   s)    zzz	**..i /   " jj)) /L M_K_ `A BT@T U	+  " KKBCJOI  	NN[\--"""jj22=  3     ;<	s   D0 B BB -D0*D.+D07!D0B 9D+CD+ D:C=;D D0 D'"D+#D0&D''D++D0c                   V ^8  d   QhRR/# rm   r   )r   s   "r   r   r   
  s     L L} Lr   c                  "   V P                   '       g   R#  . ROpRpV F  p V P                   P                  V4      P                  pVP                  RR7      G Rj  xL
 '       dP   VP	                  RR7      G Rj  xL
  VP                  RRR7      G Rj  xL
  Rp\        P                  RV4        MK  	  V'       g   \        P                  R	4       R# \        P                  ! ^4      G Rj  xL
  . ROpRpV F}  p V P                   P                  V4      P                  pVP                  RR7      G Rj  xL
 '       d5   VP	                  RR7      G Rj  xL
  Rp\        P                  R
V4        MK  	  V'       gC   \        P                  R4       V P                   P                  P                  R4      G Rj  xL
  \        P                  R4       \        ^4       Fa  p\        P                  ! ^4      G Rj  xL
  V P                  '       g   K5  \        P                  RV P                  4       V P                  u # 	  \        P                  R4       R#  EL
 EL EL  \         d     EK`  i ; i EL ELH EL+  \         d     EK  i ; i L L  \         d"   p	\        P                  RT	4        Rp	?	R# Rp	?	ii ; i5i)zSType a simple prompt and click generate to capture project_id from the API request.NFi  ro   za red apple on a tablei  TzFilled prompt input via: %sz Could not find/fill prompt inputzClicked generate button via: %sz+No generate button found, pressing Enter...Enterz*Waiting for API request with project_id...zCaptured project_id: %sz3project_id not captured after triggering generationzError triggering generation: %s)z textarea[aria-label*="prompt" i]z!textarea[placeholder*="prompt" i]zdiv[contenteditable="true"]textareazinput[type="text"])z button[aria-label*="generate" i]zbutton[aria-label*="create" i]zbutton:has-text("Generate")zbutton:has-text("Create")zbutton[type="submit"]zbutton[aria-label*="send" i])r   locatorfirst
is_visibleclickfillr@   rA   rG   re   r`   ra   keyboardpressranger   )
r   prompt_selectorsfilledselelbutton_selectorsclickedbtn_rj   s
   &         r   rf   0FlowTokenService._trigger_and_capture_project_id
  sR    zzzG	  F'	++C066B]]4]888 hhth444 gg&>gMMM!%$A3G 9 ( AB--"""  G'**,,S177C ^^D^999!iii555"&$EsK	 : ( IJjj))//888 KKDE2YmmA&&&???KK 94??K??*	  NNPQi 94M !  #" :5 !  9
 '  	NN<a@	s0  KJ$ :I1I(	I1)I1>I+?I1I.I16J$ J$ KJ$ 4J5J$ :J?J 	J
JJ
 J<J$ 
=J$ J A J$ J"	J$ !-J$ KJ$ &K(I1+I1.I11J<J$  JJ$ J
JJJ$ JJ$ "J$ $K/KKKKc                   V ^8  d   QhRR/# rm   r   )r   s   "r   r   r   X  s     ) ) )r   c                H  "   V P                   '       d   V P                  '       g   V P                  #  V P                  4       G Rj  xL
 pV'       d   Wn        V P                  #  L  \         d-   p\
        P                  RT4       T P                  u Rp?# Rp?ii ; i5i)z@Get a fresh reCAPTCHA token (call this before each API request).Nz%Failed to refresh reCAPTCHA token: %s)r   r   r   rd   rG   r@   re   )r   r;   rj   s   &  r   get_fresh_recaptcha_token*FlowTokenService.get_fresh_recaptcha_tokenX  s~     zzz(((	)7799E(-%((( :  	)NNBAF(((	)sQ   $B"B"A( A&A( A( %B"&A( (B3!BBB"BB"c                  "   RV n          V P                  '       d#   V P                  P                  4       G Rj  xL
   T P                  '       d#   T P                  P                  4       G Rj  xL
  RT n        RT n        RT n        \        P                  R4       R#  Le  \         d     Lpi ; i LC  \         d     LNi ; i5i)zClose the browser and clean up.FNzToken service stopped)
r   r   closerG   rW   rh   r   r   r@   rA   )r   s   &r   rh   FlowTokenService.stopf  s     	}}}mm))+++	xxxhhmmo%% 
+, , 		 & 		sn   C/B" B B"  B5 B5 /B30B5 4,C B" "B0-C/B00C3B5 5C CCC)	r   r   r   rW   r   r   r   r   r
   N)i0u  )__name__
__module____qualname____firstlineno____doc__r   rV   rd   rf   r   rh   __static_attributes__r   r   r   r   r   #   s(    FfP+ZL\)-r   r   c               $    V ^8  d   QhRRRRRR/# )r	   r
   r   r   r    r!   r   )r   s   "r   r   r   y  s&       
r   c                   "   \        W4      pVP                  RR7      G Rj  xL
 pVP                  4       G Rj  xL
  V#  L L5i)z
One-shot auto-setup: extract project_id and recaptcha_token, then close browser.

Returns:
    {
        "project_id": str | None,
        "recaptcha_token": str | None,
        "error": str | None,
    }
iȯ  )r   N)r   rV   rh   )r
   r   serviceri   s   &&  r   auto_setup_flow_credentialsr   y  s@      }9G==E=22F
,,.M 3s   !AAAAAA)r   
__future__r   r`   rC   loggingosr=   pathlibr   typingr   	getLoggerr   r@   rq   r^   r   r   r   r   r   <module>r      sQ   $ #    	 	  			8	$? 2S- S-l
r   