o
    o›Xj?  ã                   @  s–   d dl mZ d dl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
gZdddddœddd„ZG dd„ dƒZdS )é    )ÚannotationsN)ÚPath)ÚRequest)Úservice_account)ÚCredentials)ÚInstalledAppFlow)Úbuild)ÚMediaFileUploadz*https://www.googleapis.com/auth/drive.fileF©Úoauth_client_secretsÚoauth_token_fileÚservice_account_fileÚuse_shared_driver   úPath | Noner   r   r   Úboolc                 C  sæ   d}|r(|  ¡ r(t t|ƒt¡}|r'|jr'|jr'| tƒ ¡ |j	| 
¡ dd� nC| rP|   ¡ rPt t| ƒt¡}|jdd�}|rO|jjddd� |j	| 
¡ dd� n|rg|  ¡ rg|s\tdƒ‚tjjt|ƒtd	�}ntd
ƒ‚tdd|dd�S )zPPrefer OAuth (personal My Drive). Service account only works with Shared Drives.Nzutf-8)Úencodingr   )ÚportT)ÚparentsÚexist_okzÁGoogle service accounts cannot upload to normal My Drive folders (no storage quota). Use OAuth once (see docs/SETUP.md) or put the folder in a Shared Drive and set GOOGLE_USE_SHARED_DRIVE=true.)ÚscopeszcNo Google credentials found. Add config/google_oauth_client.json and run: python bin/google_auth.pyÚdriveÚv3F)ÚcredentialsÚcache_discovery)Úexistsr   Úfrom_authorized_user_fileÚstrÚSCOPESÚexpiredÚrefresh_tokenÚrefreshr   Ú
write_textÚto_jsonr   Úfrom_client_secrets_fileÚrun_local_serverÚparentÚmkdirÚRuntimeErrorr   Úfrom_service_account_fileÚFileNotFoundErrorr   )r   r   r   r   ÚcredsÚflow© r,   ú>/home/esfera/Documents/content_generation/src/storage/drive.pyÚbuild_drive_service   s4   €€ÿÿÿr.   c                   @  sd   e Zd Zdddddœd(dd„Zd)d*dd„Zd)d+dd„Zd)d*dd„Zd,dd„Zd-d d!„Zd.d&d'„Z	dS )/ÚDriveUploaderNFr
   Úparent_folder_idr   r   r   r   r   r   r   c                C  s@   |st dƒ‚t||||d�| _|| _|rddi| _d S i | _d S )NzGOOGLE_DRIVE_FOLDER_ID is emptyr
   ÚsupportsAllDrivesT)Ú
ValueErrorr.   Úservicer0   Ú_drive_params)Úselfr0   r   r   r   r   r,   r,   r-   Ú__init__9   s   	üzDriveUploader.__init__ÚnameÚ	parent_idú
str | NoneÚreturnc                 C  sB   |p| j }|d|gdœ}| j ¡ jd|ddœ| j¤Ž ¡ }|d S )Nz"application/vnd.google-apps.folder)r7   ÚmimeTyper   zid, webViewLink)ÚbodyÚfieldsÚidr,   )r0   r3   ÚfilesÚcreater4   Úexecute)r5   r7   r8   r%   ÚmetaÚfolderr,   r,   r-   Úcreate_folderM   s   
ýÿÿÿýzDriveUploader.create_folderc                 C  sp   |p| j }| dd¡}d|› d|› d�}| j ¡ jd|dddd	œ| j¤Ž ¡ }| d
¡p-g }|r6|d d S dS )z?Return folder id if a child folder with this exact name exists.ú'z\'zname = 'z' and 'zT' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = falser   zfiles(id, name)é   )ÚqÚspacesr=   ÚpageSizer?   r   r>   Nr,   )r0   Úreplacer3   r?   Úlistr4   rA   Úget)r5   r7   r8   r%   ÚsaferG   Úrespr?   r,   r,   r-   Úfind_folder[   s$   
ÿÿûú÷zDriveUploader.find_folderc                 C  s    |   ||¡}|r
|S |  ||¡S ©N)rO   rD   )r5   r7   r8   Úexistingr,   r,   r-   Úget_or_create_folderr   s   z"DriveUploader.get_or_create_folderÚ
local_pathr   Údictc                 C  s^   t  t|ƒ¡\}}|pd}tt|ƒ|dd�}|j|gdœ}| j ¡ jd||ddœ| j¤Ž 	¡ S )Nzapplication/octet-streamT)ÚmimetypeÚ	resumable)r7   r   zid, name, webViewLink)r<   Ú
media_bodyr=   r,   )
Ú	mimetypesÚ
guess_typer   r	   r7   r3   r?   r@   r4   rA   )r5   rS   r8   ÚmimeÚ_ÚmediarB   r,   r,   r-   Úupload_filex   s   ÿÿÿýzDriveUploader.upload_fileÚ	local_dirÚdate_folderÚbatch_folderc                C  sà   |   || j¡}|  ||¡}d|i}g }t| d¡ƒD ]A}| ¡ s!q|jdv r'qd|jv r2|jdkr2qd|jv r8q| 	|¡}	t
|	jƒdkrIt
|	jƒnd}
|  |
||¡}| |  ||¡¡ qd|› �}d|› �}|||||||d	œS )
a)  Upload preserving structure under: parent / YYYY-MM-DD / batch_HHMMSS / ...

        Example:
          Content Root/
            2026-07-16/
              batch_093933/
                idea-01_topic/
                  linkedin.txt
                  hero.png
                manifest.json
        Ú Ú*>   ú
frames.txtÚframesz.pngÚ_video_workÚ.z'https://drive.google.com/drive/folders/)Ú	folder_idÚ
folder_urlr_   Údate_folder_idÚdate_folder_urlr`   r?   )rR   r0   rD   ÚsortedÚrglobÚis_filer7   ÚpartsÚsuffixÚrelative_tor   r%   Ú_ensure_nested_folderÚappendr]   )r5   r^   r_   r`   Údate_idÚbatch_idÚfolder_cacheÚuploadedÚpathÚrelÚ
parent_relÚparent_drive_idÚlinkÚ	date_linkr,   r,   r-   Úupload_treeƒ   s6   




ùzDriveUploader.upload_treeÚrel_dirÚcacheúdict[str, str]Úroot_idc                 C  sr   |s|S ||v r|| S t |ƒj}d}|}|D ]}|r"|› d|› �n|}||vr0|  ||¡||< || }q|| S )Nra   ú/)r   rn   rD   )r5   r~   r   r�   rn   Úcurrentr8   Úpartr,   r,   r-   rq   ·   s   

z#DriveUploader._ensure_nested_folder)
r0   r   r   r   r   r   r   r   r   r   rP   )r7   r   r8   r9   r:   r   )r7   r   r8   r9   r:   r9   )rS   r   r8   r   r:   rT   )r^   r   r_   r   r`   r   r:   rT   )r~   r   r   r€   r�   r   r:   r   )
Ú__name__Ú
__module__Ú__qualname__r6   rD   rO   rR   r]   r}   rq   r,   r,   r,   r-   r/   8   s    ù

4r/   )r   r   r   r   r   r   r   r   )Ú
__future__r   rX   Úpathlibr   Úgoogle.auth.transport.requestsr   Úgoogle.oauth2r   Úgoogle.oauth2.credentialsr   Úgoogle_auth_oauthlib.flowr   Úgoogleapiclient.discoveryr   Úgoogleapiclient.httpr	   r   r.   r/   r,   r,   r,   r-   Ú<module>   s     û(