
    ҫfi                       d dl mZ d dlZd dlZd dlZd dlmZmZmZm	Z	 d dl
Z
d dlZd dlZd dlmZmZmZmZmZmZmZmZ d dlmZmZmZ d dlmZ d dlmZ d dlm Z  d	d
l!m"Z" d	dl#m$Z$ d	dl%m&Z& d	dl'm(Z( d	dl)m*Z* d	dl+m,Z, d	dl-m.Z. d	dl/m0Z0 d	dl1m2Z2 d	dl3m4Z4 d	dl5m6Z6m7Z7 ejp                   G d d             Z9 G d d      Z:y)    )annotationsN)Any	AwaitableCallableOptional)BrowserBrowserContextPage
PlaywrightProxySettingsasync_playwrightTimeoutErrorError)	urlencodequoteurlparse)ProxyProvider)	Algorithm)ProxyFormat   )stealth_async)random_choice)User)Video)Sound)Hashtag)Comment)Trending)Search)Playlist)InvalidJSONExceptionEmptyResponseExceptionc                  z    e Zd ZU dZded<   ded<   dZded<   dZded	<   dZded
<   dZded<   dZ	ded<   dZ
ded<   y)TikTokPlaywrightSessionz!A TikTok session using Playwrightr   contextpageNstrproxydictparamsheadersms_tokenhttps://www.tiktok.combase_urlTboolis_valid)__name__
__module____qualname____doc____annotations__r(   r*   r+   r,   r.   r0        P/home/homepc/tiktok-worker/venv/lib/python3.12/site-packages/TikTokApi/tiktok.pyr$   r$   ,   sK    +L
IE3FDGTHc,Hc,Hdr7   r$   c                     e Zd ZdZeZeZeZ	e
ZeZeZeZeZej*                  dfd#dZej.                  fd$dZd Zd%dZd&dZd%dZ	 	 d'd	Zd
 Zdddi ddddddf
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d(dZddddddddi dddddddddddf	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d)dZ d Z!d*dZ"d Z#d Z$d Z%d+dZ&d,dZ'd,dZ(	 	 	 	 d-	 	 	 	 	 	 	 	 	 d.dZ)d Z*d,dZ+d/dZ,d/d Z-d! Z.d" Z/y)0	TikTokApizThe main TikTokApi class that contains all the endpoints.

    Import With:
        .. code-block:: python

            from TikTokApi import TikTokApi
            api = TikTokApi()
    Nc                   g | _         d| _        t        j                         | _        d| _        d| _        d| _        d| _        |t        }| j                  ||       | t        _        | t        _        | t        _        | t        _        | t         _        | t"        _        | t$        _        | t&        _        d| _        d| _        y)z
        Create a TikTokApi object.

        Args:
            logging_level (int): The logging level you want to use.
            logger_name (str): The name of the logger you want to use.
        TFN)sessions_session_recovery_enabledasyncioLock_session_creation_lock_cleanup_called_auto_cleanup_dead_sessions_proxy_provider_proxy_algorithmr1   _TikTokApi__create_loggerr   parentr   r   r   r   r   r   r    browser
playwright)selflogging_levellogger_names      r8   __init__zTikTokApi.__init__M   s     )-&&-lln#$+/(8<59"K[-8 $&*r7   c                   t        j                  |      | _        | j                  j                  |       t        j                         }t        j
                  d      }|j                  |       | j                  j                  |       y)zCreate a logger for the class.z4%(asctime)s - %(name)s - %(levelname)s - %(message)sN)logging	getLoggerloggersetLevelStreamHandler	FormattersetFormatter
addHandler)rI   namelevelhandler	formatters        r8   __create_loggerzTikTokApi.__create_loggerm   si    &-&7&7&=U#'')%%B
	 	Y'w'r7   c                   | j                   sy| j                  s| j                  s| j                  rT| j                  j                  dt        | j                         d| j                  rdnd d| j                  rdnd        yyy)z
        Destructor to ensure cleanup happens even if user forgets.

        Warning: This is a safety net. Users should still call close_sessions() explicitly
        in async contexts. This will log a warning if cleanup wasn't called properly.
        zTikTokApi object is being destroyed but cleanup was not called. Please use 'async with TikTokApi()' or call 'await api.close_sessions()' and 'await api.stop_playwright()' explicitly to avoid resource leaks. Leaked resources: z sessions, browser=existsnonez, playwright=N)rA   r<   rG   rH   rP   warninglenrI   s    r8   __del__zTikTokApi.__del__x   s     ##}}##) *-T]]);(< =+/<<xVD E".2oo(6!JL 1@ $r7   c                  K   |j                   j                  d       d{   }|j                   j                  d       d{   }|j                   j                  d       d{   }t        t        j                  dd            }t        t        j                  dd            }t        t        j                  d	d
            }t        t        j                  dd            }|j                   j                  d       d{   }	i ddd|ddd|ddddd|d|ddddd|ddddd d!d"|d#d$d%d||d&d&d'|||	|d(	}
|
|_        y7 37 7 7 Uw))z4Set the session params for a TikTokPlaywrightSessionz() => navigator.userAgentNz2() => navigator.language || navigator.userLanguagez() => navigator.platforml     NZol   9V r   
   iX  i8  i   i  z6() => Intl.DateTimeFormat().resolvedOptions().timeZoneaid1988app_languageapp_name
tiktok_webbrowser_languagebrowser_nameMozillabrowser_onlinetruebrowser_platformbrowser_versionchannelcookie_enabled	device_iddevice_platformweb_pcfocus_state	from_pageuserhistory_lenis_fullscreenfalseis_page_visible US)	languageospriority_regionrefererregionscreen_heightscreen_widthtz_namewebcast_language)r&   evaluater'   randomrandintr*   )rI   session
user_agentr~   platformrr   rx   r   r   timezonesession_paramss              r8   __set_session_paramszTikTokApi.__set_session_params   s    "<<001LMM
 ..@
 
 !../IJJvz:;	&..B/0FNN3566>>#t45 ..D
 

6
H
 
 	

 I
 f
 
 z
 |
 f
 
 x
 6
 
 ;
  W!
" v#
$ !!*( (5
8 (S N
 K

sG   EE"EE"E'E(BEEAEEEEc                   K   |j                   sy	 |j                  j                  }y# t        t        f$ r/}| j
                  j                  d|        d|_         Y d}~yd}~ww xY ww)z
        Check if a session is still valid/alive.

        Args:
            session: The session to check

        Returns:
            bool: True if session is valid, False otherwise
        FTzSession validation failed: N)r0   r&   urlPlaywrightErrorAttributeErrorrP   r^   )rI   r   _es       r8   _is_session_validzTikTokApi._is_session_valid   sf      	   A0 	KK"=aS AB$G	s*   A)( A)A&%A!A)!A&&A)c                  K   d|_         	 |j                  r"|j                  j                          d{    	 |j                  r"|j                  j                          d{    | j                  r]|| j                  v rN	 | j                  j                  |       | j                  j                  dt        | j                                yyy7 # t        $ r(}| j                  j                  d|        Y d}~d}~ww xY w7 # t        $ r(}| j                  j                  d|        Y d}~d}~ww xY w# t        $ r Y yw xY ww)z
        Mark a session as invalid and attempt cleanup.

        Args:
            session: The session to mark as invalid
        FNz(Error closing page during invalidation: z+Error closing context during invalidation: z9Automatically removed dead session from pool. Remaining: )r0   r&   close	ExceptionrP   debugr%   rB   r<   remover_   
ValueErrorrI   r   r   s      r8   _mark_session_invalidzTikTokApi._mark_session_invalid   s0     !	N||ll((***	Qoo++--- ++4==0H$$W-!!OPSTXTaTaPbOcd 1I+ + 	NKK HLMM	N
 . 	QKK KA3OPP	Q  s   E)C CC )D
 #D$D
 (EAD> EC 	DD ;E DED
 
	D;D61E6D;;E>	E
E	E

Ec                  K   d}t        |      D ]A  }|j                  d      k|d   }|t        | j                        k  r| j                  |   }| j	                  |       d{   r||fc S | j
                  j                  d| d       neg }t        | j                        D ]2  \  }}| j	                  |       d{   s |j                  ||f       4 |rt        j                  |      c S | j                  rG||dz
  k  r?| j
                  j                  d|dz    d| d	       | j                          d{    8 t        d
       t        d
      7 7 7 "w)a1  
        Get a valid session, with automatic recovery if needed.

        Args:
            session_index (int, optional): Specific session index to use

        Returns:
            tuple: (index, session)

        Raises:
            Exception: If no valid sessions available and recovery fails
           session_indexNzRequested session z is invalidr   z6No valid sessions found, attempting recovery (attempt /)ztNo valid sessions available. All sessions appear to be dead. Please call create_sessions() again or restart the API.)rangegetr_   r<   r   rP   r^   	enumerateappendr   choicer=   _recover_sessionsr   )rI   kwargsmax_attemptsattemptir   valid_sessionsidxs           r8   _get_valid_session_indexz"TikTokApi._get_valid_session_index   s     \* 	Gzz/*6?+s4==))"mmA.G!33G<<< 'z)++.@;,OP "$$-dmm$< >LC!33G<<<&--sGn=> "!==88 --'L1<L2L##LWWX[MYZ[gZhhij ,,...F
 	
;	: F
 	
/ = = /s>   A#E&%E &AE&E"E&A:E&E$E&"E&$E&c                  K   | j                   4 d{    | j                  j                  d       t        | j                        }| j                  D cg c]  }| j                  |       d{   s|  c}| _        |t        | j                        z
  }|dkD  r| j                  j                  d| d       ddd      d{    y7 7 `c c}w 7 # 1 d{  7  sw Y   yxY ww)z
        Attempt to recover from session failures by cleaning up dead sessions
        and potentially creating new ones if we have the necessary configuration.
        NzStarting session recovery...r   zRemoved z dead session(s))r@   rP   infor_   r<   r   )rI   initial_countsremoved_counts       r8   r   zTikTokApi._recover_sessions"  s     
 .. 	M 	MKK;<  .M==$2H2H2K,K,KDM *C,>>Mq   8M?:J!KL	M 	M 	M -L	M 	M 	M 	Mso   C.CC.?CC/C0C5C9AC=C.C	C.CCC.C+C" C+'C.r-   r   i0u  c           	       K   	 	 |	|i }||d<   | j                   D| j                   j                  | j                        }|j                  t        j
                        }|
| j                  }n& | j                  j                  dd|i| d {   }|U|j                         D cg c]!  \  }}|||t        |      j                  dd# }}}|j                  |       d {    |	r |	|       d {   }nD|j                          d {   }t        |       d {    |j                  |       d {   }d|j                  vr|j                  d       d {   }d fd}|j!                  d|       |j#                  d	fd
       d {    |j%                  |       t'        j(                  dd      t'        j(                  dd      }}t'        j(                  dd      t'        j(                  dd      }}|j*                  j-                  ||       d {    |j/                  d       d {    |j*                  j-                  ||       d {    t1        |||||d      }|t3        j4                  |       d {    | j7                  |       d {   }|j9                  d      }||_        |2| j<                  j?                  dtA        | jB                         d       | jB                  jE                  |       | jG                  |       d {    y 7 c c}}w 7 Y7 J7 47 $7 7 7 7 +7 7 7 7 7 /# tH        $ r}| j<                  jK                  d|        dtM               v r*	 jO                          d {  7   n# tH        $ r Y nw xY wdtM               v r*	 jO                          d {  7    # tH        $ r Y  w xY w d }~ww xY ww)NmsTokenr(   r   )rV   valuedomainpathtiktokr-   c                    | j                   y N)r+   )requestrequest_headerss    r8   handle_requestz2TikTokApi.__create_session.<locals>.handle_requestk  s    ")//r7   r   z**/*c                `    |j                   v r| j                         S | j                         S r   )resource_typeabort	continue_)router   suppress_resource_load_typess     r8   <lambda>z,TikTokApi.__create_session.<locals>.<lambda>t  s3    "004PP   #__. r7   r   2   r   d      networkidleT)r,   r(   r+   r.   r0   z'Failed to get msToken on session index z*, you should consider specifying ms_tokenszFailed to create session: r&   r%   r6   )(rC   	get_proxyrD   formatr   
PLAYWRIGHTrG   new_contextitemsr   netlocadd_cookiesnew_pager   gotor   oncer   set_default_navigation_timeoutr   r   mousemovewait_for_load_stater$   r>   sleepget_session_cookiesr   r,   rP   r   r_   r<   r   _TikTokApi__set_session_paramsr   errorlocalsr   )rI   r   r,   r(   context_optionssleep_aftercookiesr   timeoutpage_factorybrowser_context_factory	proxy_objr%   kvformatted_cookiesr&   r   r   xyabr   r   r   s          `                 @r8   __create_sessionzTikTokApi.__create_session8  s    d	2#? G%-	"##/ 00::4;P;PQ	!(()?)?@&2,, 8 8 8 Xu X XX" !(%1} hsm6J6JTWX%! %
 ))*;<<<)'22$--//#D)))))C.(txx'))$<== #O2 IIi0+7jj   //8 >>!R(&..B*?qA>>!R(&..c*BqA**//!Q'''**=999**//!Q'''-!'G mm   !% 8 8 AA";;y1#+ #KK$$A#dmmBTAUU  A MM  )++G444O Y%
 = 3/)( >  (9' B 5 	KK :1#>?!**,&&  FH$!--/))  ! 	s  PBM% L9M% ,&L<M% )M*M% ;M<M% MM% 'M(M%  M&M% 'M(7M% M BM% ,M-M% M#M% )M*0M% MM% 3M!4A?M% 3M#4M% 8P9M% <M% M% M% M% M% M% M% M% M% M% M% !M% #M% %	O>.*O9N3,N/-N32O93	N?<O9>N??O9O)"O%#O)(O9)	O52O94O55O99O>>P   TchromiumFc                   	K   | _          _        | _        t        d      t	               j                          d{    _           j                         d{    _        n|dk(  rI|r|
dg}
d} j                  j                  j                  ||
t              |       d{    _        n|dk(  r@ j                  j                  j                  ||
t              |       d{    _        nP|dk(  r@ j                  j                  j                  ||
t              |       d{    _        nt        d	      |r t        j                  	 fd
t        |      D        ddi d{   }t!        d |D              }t#         j$                        }||nd}||k  rC|D cg c]  }t'        |t(              st+        |        }}t)        d| d| d| d|dd        |dkD  rk j,                  j/                  d| d| d| d       t1        |      D ]7  \  }}t'        |t(              s j,                  j3                  d| d|        9 yyt        j                  	 fdt        |      D          d{    y7 j7 L7 7 7 }7 2c c}w 7 w)aW  
        Create sessions for use within the TikTokApi class.

        These sessions are what will carry out requesting your data from TikTok.

        Args:
            num_sessions (int): The amount of sessions you want to create.
            headless (bool): Whether or not you want the browser to be headless.
            ms_tokens (list[str]): A list of msTokens to use for the sessions, you can get these from your cookies after visiting TikTok.
                                   If you don't provide any, the sessions will try to get them themselves, but this is not guaranteed to work.
            proxies (list): **DEPRECATED - Use proxy_provider instead.** A list of proxies to use for the sessions.
                           This parameter is maintained for backwards compatibility but will be removed in a future version.
            proxy_provider (ProxyProvider | None): A ProxyProvider instance for smart proxy rotation.
                                                   See examples/proxy_provider_example.py for usage examples. Full documentation: https://davidteather.github.io/proxyproviders/
            proxy_algorithm (Algorithm | None): Algorithm for proxy selection (RoundRobin, Random, First, or custom) per session.
                                               Only used with proxy_provider. Defaults to RoundRobin if not specified.
            sleep_after (int): The amount of time to sleep after creating a session, this is to allow the msToken to be generated.
            starting_url (str): The url to start the sessions on, this is usually https://www.tiktok.com.
            context_options (dict): Options to pass to the playwright context.
            override_browser_args (list[dict]): A list of dictionaries containing arguments to pass to the browser.
            cookies (list[dict]): A list of cookies to use for the sessions, you can get these from your cookies after visiting TikTok.
            suppress_resource_load_types (list[str]): Types of resources to suppress playwright from loading, excluding more types will make playwright faster.. Types: document, stylesheet, image, media, font, script, textrack, xhr, fetch, eventsource, websocket, manifest, other.
            browser (str): firefox, chromium, or webkit; default is chromium
            executable_path (str): Path to the browser executable
            page_factory (Callable[[BrowserContext], Awaitable[Page]]) | None: Optional async function for instantiating pages.
            browser_context_factory (Callable[[Playwright], Awaitable[BrowserContext]]) | None: Optional async function for creating browser contexts. When provided, you can choose any browser (chromium/firefox/webkit) inside the factory, and the 'browser' parameter is ignored.
            timeout (int): The timeout in milliseconds for page navigation
            enable_session_recovery (bool): Enable automatic session recovery on failures (default: True)
            allow_partial_sessions (bool): If True, succeed even if some sessions fail to create. If False (default), fail if any session fails
            min_sessions (int | None): Minimum number of sessions required. Only used if allow_partial_sessions=True. If None, defaults to 1.

        Example Usage:
            .. code-block:: python

                from TikTokApi import TikTokApi

                async with TikTokApi() as api:
                    await api.create_sessions(num_sessions=5, ms_tokens=['msToken1', 'msToken2'])

        Proxy Provider Usage:
            For proxy provider examples with different algorithms and configurations,
            see examples/proxy_provider_example.py

        Custom Launchers:
            To implement custom functionality, such as login or captcha solving, when the session is being created,
            you may use the keyword arguments `browser_context_factory` and `page_factory`.
            These arguments are callable functions that TikTok-Api will use to launch your browser and pages,
            and allow you to perform custom actions on the page before the session is created.
            You can find examples in the test file: tests/test_custom_launchers.py
        NzCannot use both 'proxies' and 'proxy_provider' parameters. Please use 'proxy_provider' (recommended) or 'proxies' (deprecated).r   z--headless=newF)headlessargsr(   executable_pathfirefoxwebkitzInvalid browser argument passedc              3     K   | ]>  }	j                  t              nd t              
t              
       @ y wN)
r(   r,   r   r   r   r   r   r   r   r   _TikTokApi__create_sessionr   .0r   r   r   r   	ms_tokensr   proxiesproxy_providerrI   r   starting_urlr   r   s     r8   	<genexpr>z,TikTokApi.create_sessions.<locals>.<genexpr>$  `        ))6D6LM'2RV!.y!9((7$/ -g 65Q '%10G *    AAreturn_exceptionsTc              3  B   K   | ]  }t        |t              sd   ywr   N)
isinstancer   )r   rs     r8   r   z,TikTokApi.create_sessions.<locals>.<genexpr>9  s     NQZ95MqNs   r   z4Failed to create minimum required sessions. Created r   z, needed at least z
.
Errors: r   r   zCreated z sessions successfully. z session(s) failed to create.zSession z creation failed: c              3     K   | ]>  }	j                  t              nd t              
t              
       @ y wr   r   r   s     r8   r   z,TikTokApi.create_sessions.<locals>.<genexpr>Q  r  r  )r=   rC   rD   r   r   startrH   rG   r   launchr   r   r   r>   gatherr   sumr_   r<   r  r   r'   rP   r^   r   r   )rI   num_sessionsr   r   r   r   proxy_algorithmr   r   r   override_browser_argsr   r   rG   r   r   r   r   enable_session_recoveryallow_partial_sessionsmin_sessionsresultsfailed_countsuccess_countminimum_requiredr  error_messagesr   results   `  ``` ``` ``  ```           r8   create_sessionszTikTokApi.create_sessions  s    V *A&- />#=W 
 !1 2 8 8 ::".!8!IIDL
"19)9(:% !%!9!9!@!@!*#G, /	 "A " DL 	!!%!8!8!?!?!*#G, /	 "@ " DL  !%!7!7!>!>!*#G, /	 "? " DL >?? "#NN  #<0$ #'% G, N'NNL.M/;/G|Q//29!VQZ9=U#a&!V!V,oQ|n<NO_N` a-bq124 
 !##}oQ|n<T#n$AC
 "+7!3 TIAv!&)4))HQC7I&*RST " ..  #<0  ] ;I
8 "W"s   A KJ8 K/J;0AK=J>>AKKAKKAKK:KK
&K
3A'KAK2K3K;K>KKKK
Kc                R  K   | j                   j                  dt        | j                         d       | j                  D ]`  }	 |j                  r"|j                  j                          d{    	 |j                  r"|j                  j                          d{    b | j                  j                          	 | j                  r)| j                  j                          d{    d| _	        	 | j                  r)| j                  j                          d{    d| _
        d| _        | j                   j                  d	       y7 # t        $ r)}| j                   j                  d|        Y d}~	d}~ww xY w7 # t        $ r)}| j                   j                  d|        Y d}~rd}~ww xY w7 # t        $ r(}| j                   j                  d|        Y d}~d}~ww xY w7 # t        $ r(}| j                   j                  d|        Y d}~d}~ww xY ww)
z
        Close all the sessions. Should be called when you're done with the TikTokApi object

        This is called automatically when using the TikTokApi with "with"
        zClosing z sessions...NzError closing page: zError closing context: Error closing browser: Error stopping playwright: Tz6All sessions and browser resources closed successfully)rP   r   r_   r<   r&   r   r   r%   clearrG   rH   stoprA   r   s      r8   close_sessionszTikTokApi.close_sessionsd  s     	HS%7$8EF}} 	AG><<!,,,,...A??!////111	A 		=||ll((***#	Aoo**,,,"&  $RS7 / >!!$8"<==>
 2 A!!$;A3"?@@A + 	=KK 7s;<<	=
 - 	AKK ;A3?@@	As   AH')E.E/E4)FFF"H'?)F= (F;)F= 5)G3 G1G3 *#H'E	FE<6H'<FH'F	F8F3-H'3F88H';F= =	G.G)$H')G..H'1G3 3	H$<HH'H$$H'c                D    t        j                  |      }d| d| d| dS )z:Generate a javascript fetch function for use in playwrightzj
            () => {
                return new Promise((resolve, reject) => {
                    fetch('z', { method: 'z', headers: z })
                        .then(response => response.text())
                        .then(data => resolve(data))
                        .catch(error => reject(error.message));
                });
            }
        )jsondumps)rI   methodr   r+   
headers_jss        r8   generate_js_fetchzTikTokApi.generate_js_fetch  s8    ZZ(
  5x|J< P		 		r7   c                    t        | j                        dk(  rt        d      |j                  d      |d   }n,t	        j
                  dt        | j                        dz
        }|| j                  |   fS )ac  Get a random session

        DEPRECATED: Use _get_valid_session_index() for better error handling

        Args:
            session_index (int): The index of the session you want to use, if not provided a random session will be used.

        Returns:
            int: The index of the session.
            TikTokPlaywrightSession: The session.
        r   z1No sessions created, please create sessions firstr   r   )r_   r<   r   r   r   r   )rI   r   r   s      r8   _get_sessionzTikTokApi._get_session  sl     t}}"OPP::o&2'Aq#dmm"4q"89A$--"""r7   c                V   K   |j                   j                  |       d{    y7 w)z
        Set the cookies for a session

        Args:
            session (TikTokPlaywrightSession): The session to set the cookies for.
            cookies (dict): The cookies to set for the session.
        N)r%   r   )rI   r   r   s      r8   set_session_cookieszTikTokApi.set_session_cookies  s       oo))'222s   )')c                   K   |j                   j                          d{   }|D ci c]  }|d   |d    c}S 7 c c}w w)z
        Get the cookies for a session

        Args:
            session (TikTokPlaywrightSession): The session to get the cookies for.

        Returns:
            dict: The cookies for the session.
        NrV   r   )r%   r   )rI   r   r   cookies       r8   r   zTikTokApi.get_session_cookies  sC       //11>EFFvw/FF 2Fs   A<A>AAc                  K   | j                  d||      }	  | j                  di | d{   \  }}	 |j                  j                  |       d{   }|S 7 -# t        $ r  | j                  di |\  }}Y Hw xY w7 ,# t        $ r>}| j                  j                  d|        | j                  |       d{  7    d}~ww xY ww)a  
        Execute a javascript fetch function in a session

        Args:
            url (str): The url to fetch.
            headers (dict): The headers to use for the fetch.

        Returns:
            any: The result of the fetch. Seems to be a string or dict
        GETNzSession failed during fetch: r6   )
r%  r   r   r'  r&   r   r   rP   r   r   )	rI   r   r+   r   	js_scriptr   r   r  r   s	            r8   run_fetch_scriptzTikTokApi.run_fetch_script  s      **5#w?		5<t<<FvFFJAw
	"<<00;;FM G 	5***4V4JAw	5
 < 	KK =aSAB,,W555		ss   CA AA B B B CA A=:C<A==C B 	C	2C=C >CC		Cc                ~  K   	  | j                   di | d{   \  }}d}d}||k  rB|dz  }	 t        j                  dd      }|j
                  j                  d|       d{    	 	 |j
                  j                  d| d       d{   }
|
S 7 |# t        $ r  | j                  di |\  }}Y w xY w7 U# t        $ rY}||k(  rt        d	| d
      g d}	|j
                  j                  t        j                  |	             d{  7   Y d}~nMd}~wt        $ r>}| j                  j                  d|        | j                  |       d{  7    d}~ww xY w||k  rE7 # t        $ r>}| j                  j                  d|        | j                  |       d{  7    d}~ww xY ww)z%Generate the X-Bogus header for a urlNr   r   r   i  i N  z#window.byted_acrawler !== undefined)r   zFailed to load tiktok after z! attempts, consider using a proxy)https://www.tiktok.com/foryour-   zhttps://www.tiktok.com/@tiktokr1  z(Session died during x-bogus generation: z3() => { return window.byted_acrawler.frontierSign("z") }z(Session died during x-bogus evaluation: r6   )r   r   r'  r   r   r&   wait_for_functionr   r   r   r   rP   r   r   r   )rI   r   r   r   r   r   attemptstimeout_timer   try_urlsr  s              r8   generate_x_boguszTikTokApi.generate_x_bogus  s    	5<t<<FvFFJAw
 %MH%~~dE:ll449< 5    *		"<<00Fse5Q F MO G 	5***4V4JAw	5   A|+&6|nDef  ll''h(?@@@" !!$LQC"PQ00999	- %:  	KK HLM,,W555		s   F=B BB F=6B> &B<'B> +F=-"E3 E1E3 F=B B96F=8B99F=<B> >	E%A	DDDF=E%'2E EE  E%%F=1E3 3	F:<2F5.F1/F55F::F=c                6  K   	  | j                   di | d{   \  }}| j                  ||       d{   j	                  d      }|t        d      d|v r|dz  }n|dz  }|d| z  }|S 7 W# t        $ r  | j                  di |\  }}Y rw xY w7 _w)	z
Sign a urlNr   zX-BoguszFailed to generate X-Bogus?&zX-Bogus=r6   )r   r   r'  r6  r   )rI   r   r   r   r   x_boguss         r8   sign_urlzTikTokApi.sign_url  s     	5<t<<FvFFJAw ..s!.DDII)T?899#:3JC3JC'##
% G 	5***4V4JAw	5 EsA   BA3 A1A3 BB9B1A3 3BBBBc                  K   	  | j                   di | d{   \  }}|j                  i |j                  |}|i |j                  |}n|j                  }|j                  d      h|j                  |j                  |d<   nL| j                  |       d{   }	|	j                  d      }
|
| j                  j                  d       |
|d<   | dt        |dt               }| j                  ||       d{   }d}||k  r|d	z  }	 | j                  |||
       d{   }|t        d      |dk(  rt        |d      	 t        j                   |      }|j                  d      dk7  r| j                  j#                  d|        |S yy7 # t        $ r  | j                  di |\  }}Y w xY w7 %7 7 # t        j$                  j&                  $ r ||k(  r(| j                  j#                  d|        t)               | j                  j+                  d| d| d       |r"t-        j.                  d|z         d{  7   nt-        j.                  d	       d{  7   Y nw xY wn# t0        $ r}| j                  j#                  d|        | j3                  |       d{  7   ||k  rr| j                  j+                  d| d| d       	  | j                   di | d{  7  \  }}n1# t        $ r$}| j                  j#                  d|         d}~ww xY w Y d}~nd}~ww xY w||k  r=w)a  
        Makes a request to TikTok through a session.

        Args:
            url (str): The url to make the request to.
            headers (dict): The headers to use for the request.
            params (dict): The params to use for the request.
            retries (int): The amount of times to retry the request if it fails.
            exponential_backoff (bool): Whether or not to use exponential backoff when retrying the request.
            session_index (int): The index of the session you want to use, if not provided a random session will be used.

        Returns:
            dict: The json response from TikTok.

        Raises:
            Exception: If the request fails.
        Nr   zZFailed to get msToken from cookies, trying to make the request anyway (probably will fail)r9  =)safe	quote_viar8  r   r   )r+   r   z(TikTokApi.run_fetch_script returned Noner|   zTikTok returned an empty response. They are detecting you're a bot, try some of these: headless=False, browser='webkit', consider using a proxystatus_codezGot an unexpected status code: z Failed to decode json response: zFailed a request, retrying (r   r      z!Playwright error during request: zRetrying with a new session (zFailed to get valid session: r6   )r   r   r'  r*   r+   r   r,   r   rP   warnr   r   r<  r/  r"   r!  loadsr   decoderJSONDecodeErrorr!   r   r>   r   r   r   )rI   r   r+   r*   retriesexponential_backoffr   r   r   r   r,   encoded_params
signed_urlretry_countr  datar   session_errors                     r8   make_requestzTikTokApi.make_request*  ss    4	5<t<<FvFFJAw
 >>%11&1F44G4GooG ::i (+$+$4$4y! !% 8 8 AA";;y1#KK$$t %-y!5)F"N!OP==q=II
G#1K1#44q  5    >#$NOOR<0 j 
/::f-Dxx.!3)),KD6*RSK) $A G 	5***4V4JAw	5& B J$ ||33 /"g-)),LVH*UV244KK$$6{m1WIQO +%mmA{N;;;%mmA.../ # !!$EaS"IJ00999(KK$$7}AgYaP+H4+H+H+R6+R%R%R
7$ ));M?K 	  #C G#s  MF FF A<MGA$MGMI> +G,"I> AG	 MF F?;M>F??MMI> 	B	I:II:1I42I:7I> 9I::I> =M>	M2L<9J<:,L<'L<K?=LL<	L3L..L33L<7M<MMc                  K   	 | j                   r)| j                   j                          d{    d| _         	 | j
                  r*| j
                  j                          d{    d| _        yy7 C# t        $ r(}| j                  j	                  d|        Y d}~fd}~ww xY w7 C# t        $ r(}| j                  j	                  d|        Y d}~yd}~ww xY ww)z
        Stop the playwright browser.

        Note: It's better to use close_sessions() which calls this automatically.
        Nr  r  )rG   r   r   rP   r   rH   r  )rI   r   s     r8   stop_playwrightzTikTokApi.stop_playwright  s     	=||ll((***#	Aoo**,,,"&  + 	=KK 7s;<<	=
 - 	AKK ;A3?@@	Ass   C)A3 A1A3 )B) #B'$B) /C1A3 3	B$<BCB$$C'B) )	C2CCCCc                p  K   	  | j                   di | d{   \  }}	 |j                  j	                          d{   S 7 *# t        $ r  | j                  di |\  }}Y Ew xY w7 *# t
        $ r>}| j                  j                  d|        | j                  |       d{  7    d}~ww xY ww)zGet the content of a urlNz)Session died during get_session_content: r6   )	r   r   r'  r&   contentr   rP   r   r   )rI   r   r   r   r   r   s         r8   get_session_contentzTikTokApi.get_session_content  s     	5<t<<FvFFJAw
	 --/// G 	5***4V4JAw	5
 0 	KK I!MN,,W555	sr   B6A AA A, A* A, B6A A'$B6&A''B6*A, ,	B352B.'B*(B..B33B6c           	        t        d | j                  D              }t        | j                        |z
  }t        | j                        ||| j                  du| j                  du| j
                  | j                  | j                  dS )z
        Get statistics about current resource usage.

        Useful for monitoring and detecting potential memory leaks.

        Returns:
            dict: Statistics including session count, browser status, etc.
        c              3  :   K   | ]  }|j                   sd   ywr  )r0   r   r   s     r8   r   z/TikTokApi.get_resource_stats.<locals>.<genexpr>  s     D1QDs   N)total_sessionsr   invalid_sessionshas_browserhas_playwrightcleanup_calledauto_cleanup_enabledrecovery_enabled)r  r<   r_   rG   rH   rA   rB   r=   )rI   r   rX  s      r8   get_resource_statszTikTokApi.get_resource_stats  s}     DDDt}}-> "$--0, 0<<t3"ooT9"22$($D$D $ > >	
 		
r7   c                R  K   | j                         }g }t        | j                        D ]=  \  }}| j                  |       d{   }|j	                  |||j
                  d       ? ||d<   t        d |D              |d<   |d   dkD  r| j                  s|d    d|d	<   |S 7 `w)
z
        Perform a health check on all resources.

        This actively validates all sessions and returns detailed health info.
        Useful for monitoring and debugging.

        Returns:
            dict: Health check results
        N)indexvalidmarked_validsession_detailsc              3  ,   K   | ]  }|d    s	d  yw)ra  r   Nr6   rV  s     r8   r   z)TikTokApi.health_check.<locals>.<genexpr>  s     (Qqaj(Qs   
healthy_sessionsrX  r   z6 invalid sessions accumulating (auto-cleanup disabled)r^   )r^  r   r<   r   r   r0   r  rB   )rI   healthsession_healthr   r   r0   s         r8   health_checkzTikTokApi.health_check  s      ((* #DMM2 	JAw!33G<<H!!%$+$4$4	 %3 !%((QN(Q%Q!" $%)$2R2R,-..de 9 % =s   AB'B%A!B'c                   K   | S wr   r6   r`   s    r8   
__aenter__zTikTokApi.__aenter__  s     s   c                   K   | j                          d{    | j                  s| j                          d{    yy7 *7 w)z3Ensure cleanup happens when exiting context managerN)r  rA   rP  )rI   exc_typeexctbs       r8   	__aexit__zTikTokApi.__aexit__  sC     !!#####&&((( $ 	$ )s   AA#AAAA)rJ   intrK   r'   )rV   r'   rW   rp  )r   r$   )r   r$   returnr/   )rq  z#tuple[int, TikTokPlaywrightSession])r   r'   r,   
str | Noner(   z%dict[str, Any] | ProxySettings | Noner   dict[str, Any]r   rp  r   zdict[str, Any] | Noner   z	list[str]r   rp  r   2Callable[[BrowserContext], Awaitable[Page]] | Noner   8Callable[[Playwright], Awaitable[BrowserContext]] | None)(r  rp  r   r/   r   list[str] | Noner   z+list[dict[str, Any] | ProxySettings] | Noner   zOptional[ProxyProvider]r  zOptional[Algorithm]r   rp  r   r'   r   rs  r  rv  r   zlist[dict[str, Any]] | Noner   rv  rG   r'   r   rr  r   rt  r   ru  r   rp  r  r/   r  r/   r  z
int | None)r#  r'   r   r'   r+   r)   rq  r'   )r   r'   r+   r)   )r   r'   )NNr   T)
r   r'   r+   r)   r*   r)   rG  rp  rH  r/   )rq  r)   )0r1   r2   r3   r4   r   rw   r   videor   soundr   hashtagr   commentr   trendingr   searchr    playlistrN   WARNrL   DEBUGrE   ra   r   r   r   r   r   r   r  r  r%  r'  r)  r   r/  r6  r<  rN  rP  rS  r^  rh  rj  ro  r6   r7   r8   r:   r:   :   s    DEEGGHFH,3LLT +@ 7>mm 	($+(Z.B1
	,1
fM0 ,#7;*,)-26KO ss s 5	s
 (s s 's '0s s Is Esn &*?C26/34*,26/39=!&*KO (,',#'/uu u $	u
 =u 0u -u u u (u  0u -u '7u u $u  I!u$ E%u( )u* "&+u, !%-u. !/un&TP#*3G8/b4 $(nn n 	n
 n "n`A(
.!F)r7   r:   );
__future__r   r>   rN   dataclassestypingr   r   r   r   r   timer!  playwright.async_apir   r	   r
   r   r   r   r   r   r   urllib.parser   r   r   proxyprovidersr   proxyproviders.algorithmsr   proxyproviders.models.proxyr   stealthr   helpersr   api.userr   	api.videor   	api.soundr   api.hashtagr   api.commentr   api.trendingr   
api.searchr   api.playlistr    
exceptionsr!   r"   	dataclassr$   r:   r6   r7   r8   <module>r     s    "    5 5   	 	 	 4 3 ( / 3 " "        "  " 
 
 
E) E)r7   