U
    Xi|0                     @   sp  d dl Z d dlZd dlZd dlmZmZ d dlmZm	Z	m
Z
mZmZ dZdZdZdZdZd	Zeed
ddZeedddZeedddZeeedddZeeedddZdddeeeeeeeeeeee edddZdddeeeeeeeeeeee eddd Zeeedd!d"Zed# Zddd$ddd%eeeeeeeeeee eee ee ed&d'd(Z dS ))    N)OptionalLiteral)TIKTOK_CLIENT_KEYTIKTOK_CLIENT_SECRETTIKTOK_REDIRECT_URITIKTOK_SCOPESTIKTOK_PRODUCTIONz)https://www.tiktok.com/v2/auth/authorize/z+https://open.tiktokapis.com/v2/oauth/token/z=https://open.tiktokapis.com/v2/post/publish/inbox/video/init/z7https://open.tiktokapis.com/v2/post/publish/video/init/z?https://open.tiktokapis.com/v2/post/publish/creator_info/query/z9https://open.tiktokapis.com/v2/post/publish/status/fetch/)statereturnc                 C   s$   t dtt| d}td tj| S )Ncode)
client_keyZresponse_typescoperedirect_urir	   ?)r   r   r   TIKTOK_OAUTH_AUTHORIZE_URLurllibparse	urlencode)r	   params r   +/var/www/html/luxverbi-app/tiktok_client.pybuild_authorize_url"   s    r   )r   r
   c                 C   s0   t td| td}tjt|dd}|  | S )NZauthorization_code)r   Zclient_secretZ
grant_typer   r      )datatimeout)r   r   r   requestspostTIKTOK_OAUTH_TOKEN_URLraise_for_statusjson)r   payloadrespr   r   r   exchange_code_for_token-   s    r"   )access_tokenr
   c                 C   sf   d|  dd}t jt|i dd}|  | }|di }|ddkrZtd	| |d
i S )a  
    Mandatory for audit: retrieve latest creator info right before rendering Post-to-TikTok page.

    Returns data dict with fields such as:
      - creator_nickname
      - privacy_level_options (list)
      - comment_disabled / duet_disabled / stitch_disabled (bool)
      - max_video_post_duration_sec (int)
      - may also include "can_post" flags depending on account state
    Bearer application/json; charset=UTF-8AuthorizationContent-Typer   headersr   r   errorr   okzcreator_info error: r   )r   r   CREATOR_INFO_URLr   r   getRuntimeError)r#   r*   r!   r    errr   r   r   query_creator_info>   s    r1   )r#   
publish_idr
   c                 C   sj   d|  dd}t jt|d|idd}|  | }|di }|dd	kr^td
| |di S )z=
    Poll post publish status so users can see progress.
    r$   r%   r&   r2   r   r)   r+   r   r,   zstatus_fetch error: r   )r   r   STATUS_FETCH_URLr   r   r.   r/   )r#   r2   r*   r!   r    r0   r   r   r   fetch_post_statusX   s       r4   )	file_pathr#   r
   c              	   C   s   t j| }d| dd}dd||ddi}tjt||dd	}|  | }|d
i }|ddkrxt	d| |di }|d}	|	st	d| |d }
dd|
 d| d}t
| d}tj|	||dd}W 5 Q R X |  |S )z
    Upload as draft (inbox) using video.upload:
      1) INIT -> /post/publish/inbox/video/init/
      2) PUT  -> upload_url with full file (Content-Range)
    r$   r%   r&   source_infoFILE_UPLOAD   sourceZ
video_size
chunk_sizeZtotal_chunk_count<   r)   r+   r   r,   zTikTok inbox init error: r   
upload_urlz(No upload_url in TikTok inbox response: 	video/mp4bytes 0-/r(   zContent-Rangerb,  r*   r   r   )ospathgetsizer   r   INBOX_INIT_URLr   r   r.   r/   openput)r5   r#   	file_sizer*   body	init_resp	init_datar+   r   r=   end_byteput_headersfput_respr   r   r   _upload_video_as_draftq   s:    	
rS   T)is_aigcvideo_cover_timestamp_ms)r#   	video_urlcaptionprivacy_leveldisable_commentdisable_duetdisable_stitchbrand_content_togglebrand_organic_togglerT   rU   r
   c              	   C   s   |rt |tstdd|  dd}||p.d||||||	d}|
dk	rTt|
|d< d	|d
|d}tjt||dd}|jdkrtd|j d|j	 |
  | }|di }|ddkrtd| |S )a  
    Direct Post using PULL_FROM_URL (TikTok pulls the video from your URL).
    This is the correct mode when the MP4 already exists on your server/storage.

    Important:
      - video_url must be reachable by TikTok servers.
      - Your domain/prefix must be allowed in TT4D "Manage URL properties".
      - privacy_level must be explicitly selected by the user from privacy_level_options.
    z'video_url is required for PULL_FROM_URLr$   r%   r&    rX   titlerY   rZ   r[   r\   r]   rT   NrU   PULL_FROM_URL)r:   rV   r6   	post_infor<   r)     Direct init failed : r+   r   r,   z*TikTok direct init (PULL_FROM_URL) error: )
isinstancestr
ValueErrorintr   r   DIRECT_POST_INIT_URLstatus_coder/   textr   r   r.   )r#   rV   rW   rX   rY   rZ   r[   r\   r]   rT   rU   r*   rc   rL   rM   rN   r+   r   r   r   _publish_video_from_url   s<    

rn   )r5   r#   rW   rX   rY   rZ   r[   r\   r]   rT   rU   r
   c              	   C   sD  t j| }d| dd}||p$d||||||	d}|
dk	rJt|
|d< d||d	d
|d}tjt||dd}|jdkrtd|j d|j	 |
  | }|di }|ddkrtd| |di }|d}|std| |d	 }dd| d| d}t| d}tj|||dd}W 5 Q R X |
  |S )af  
    Direct Post (FILE_UPLOAD):
      1) INIT -> /v2/post/publish/video/init/ with source_info + post_info
      2) PUT  -> upload_url with full file (Content-Range)
      3) TikTok publishes based on post_info

    NOTE: Not recommended when the video is already on your server-side storage.
    Use PULL_FROM_URL for audit compliance in that scenario.
    r$   r%   r&   r^   r_   NrU   r7   r8   r9   rb   r<   r)   rd   re   rf   r+   r   r,   z(TikTok direct init (FILE_UPLOAD) error: r   r=   z)No upload_url in TikTok direct response: r>   r?   r@   rA   rB   rC   rD   )rE   rF   rG   rj   r   r   rk   rl   r/   rm   r   r   r.   rI   rJ   )r5   r#   rW   rX   rY   rZ   r[   r\   r]   rT   rU   rK   r*   rc   rL   rM   rN   r+   r   r=   rO   rP   rQ   rR   r   r   r   %_upload_and_publish_video_file_upload   sT    



ro   c                 C   s   t | |dS )Nr5   r#   )rS   rp   r   r   r   upload_video_draftA  s    rq   )ra   r7   ra   )rT   rU   moderV   r5   )r#   rW   rX   rY   rZ   r[   r\   r]   rT   rU   rr   rV   r5   r
   c                 C   sv   |
dkr2|st dt| ||||||||||	dS |
dkrd|sFt dt|| |||||||||	dS t d|
 dS )	z
    Unified entrypoint:
      - mode="PULL_FROM_URL": requires video_url (recommended for audit if video is on your server)
      - mode="FILE_UPLOAD": requires file_path (fallback/tests)
    ra   z/video_url is required when mode='PULL_FROM_URL')r#   rV   rW   rX   rY   rZ   r[   r\   r]   rT   rU   r7   z-file_path is required when mode='FILE_UPLOAD')r5   r#   rW   rX   rY   rZ   r[   r\   r]   rT   rU   zUnsupported mode: N)ri   rn   ro   )r#   rW   rX   rY   rZ   r[   r\   r]   rT   rU   rr   rV   r5   r   r   r   upload_video_direct_postG  sB    rs   )!rE   r   urllib.parser   typingr   r   configr   r   r   r   r   r   r   rH   rk   r-   r3   rh   r   dictr"   r1   r4   rS   boolrj   rn   ro   rq   ZPublishModers   r   r   r   r   <module>   s   ?QV