o
    l>jJ                     @  s  d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlZddlmZmZmZ ddlmZmZmZmZmZmZmZ dd	lmZmZ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)m*Z* ddl+m,Z,m-Z- dZ.dZ/ej0ddZ1dd!d"Z2dd)d*Z3dd+d,Z4dd0d1Z5dd6d7Z6ddMdNZ7ddTdUZ8dd\d]Z9dd_d`Z:ddbdcZ;e1<dddddddeeefddfdgZ=e1<dhdddddeeefddidjZ>e1<dkdddddeeefddldmZ?e1<dnej@ddodpdej@dqdre.dej@dedse/dej@dtdudvdwdxdddddeeefddzd{ZAe1<d|ejBd}d~dej@ddoddej@dedse/dej@dqdre.ddddddeeefdddZCe1<dej@dqdre.dej@ddddej@ddudvddxdddddeeef
dddZDe1<dej@dqdre.ddddddeeefdddZEe1<dejBd}d~dej@ddoddej@dedse/dej@dqdre.dej@d}dddej@dddddddddeeefdddZFe1<dej@d}ddeddddej@ddoddej@dqdre.dej@dddeddddej@ddddej@ddddej@ddddej@dddvddxej@dddvddxej@dedddej@dedddej@ddddej@dedddej@dedddej@dddddxej@dedddej@dedddej@deddddddddeeefdddZGe1<dej@d}ddeddddej@ddoddej@dqdre.dej@dddeddddej@ddddej@ddddej@ddddej@dddvddxej@dddvddxej@dedddej@dedddej@ddddej@dedddej@dedddej@dddddxej@dedddej@dedddej@dedddej@dddvddxej@dddvddxdddddeeefdddȄZHdS )zPhotos commands.    )annotationsN)islice)Path)AnyIteratorOptional)CLIAbort	get_stateservice_call)normalize_albumnormalize_photonormalize_photo_changenormalize_photo_detailsnormalize_photo_librarynormalize_photo_sync_resultnormalize_sync_cursor)
DEFAULT_LOG_LEVELDEFAULT_OUTPUT_FORMATHttpProxyOptionHttpsProxyOptionLogLevelOptionNoVerifySslOptionOutputFormatOptionSessionDirOptionUsernameOptionstore_command_options)console_tableprint_json_textto_json_string)PhotosServiceExceptionPhotoSyncOptions)(legacy_shared_stream_unsupported_message(unsupported_shared_library_album_messagezPhoto library key.zUse shared photo stream.z"Browse and download iCloud Photos.)helpctxtyper.Contextusernamer   session_dirr   
http_proxyr   https_proxyr   no_verify_sslr   output_formatr   	log_levelr   c          
   
     sJ   t | |||||||d t| }|  td fdd jd}	| |	fS )Nr&   r'   r(   r)   r*   r+   r,   Photosc                         j S Nphotos apir3   Q/home/thesage/.local/lib/python3.10/site-packages/pyicloud/cli/commands/photos.py<lambda>F       z)_resolve_photos_service.<locals>.<lambda>account_name)r   r	   get_apir
   r:   )
r$   r&   r'   r(   r)   r*   r+   r,   stater2   r3   r4   r6   _resolve_photos_service/   s   

r=   r5   r   r2   library_keystrreturnc                   s>   t d fdd| jd}||}|d u rtd| d|S )Nr.   c                     r/   r0   )	librariesr3   r1   r3   r6   r7   M   r8   z(_resolve_photo_library.<locals>.<lambda>r9   zNo photo library matched ''.)r
   r:   getr   )r5   r2   r>   rA   libraryr3   r1   r6   _resolve_photo_libraryJ   s   

rE   c                 C  sB   t | ||}t|dd }t|dd dkst|tstt||S )Nzone_idscopezshared-stream)rE   getattr
isinstancedictr   r!   )r5   r2   r>   rD   rF   r3   r3   r6   _resolve_cloudkit_photo_libraryV   s   rK   rD   
album_namer   c                 C  s.   t | dd dkrtt||S td| dS )NrG   zshared-libraryzNo album named 'z' was found.)rH   r   r"   )rD   r>   rL   r3   r3   r6   _album_lookup_error`   s
   rM   albumOptional[str]shared_streamboolc                  s   |s#t | |td fdd| jd} r!|du r!t| |S  r?td fdd| jd}|du r=tj| |S td)a  Resolve album object from either CloudKit library or shared streams.

    Args:
        api: PyiCloudService instance
        photos: Photos service instance
        album: Album name (optional for CloudKit, required for shared streams)
        library: Library key (used only for CloudKit path)
        shared_stream: Whether to use shared streams instead of CloudKit

    Returns:
        Resolved album object

    Raises:
        CLIAbort: If album resolution fails or constraints are violated
    r.   c                     s    rj  S jS r0   )albumsfindallr3   )rN   library_objr3   r6   r7          z _resolve_album.<locals>.<lambda>r9   Nc                     s   j  S r0   )shared_streamsrS   r3   )rN   r2   r3   r6   r7          z4The --shared-stream option requires an --album name.)rK   r
   r:   rM   rW   r   )r5   r2   rN   rD   rP   	album_objr3   )rN   rU   r2   r6   _resolve_albumh   s(   rZ   	directoryr   	state_dirOptional[Path]Optional[list[str]]sizelive_photo_sizefolder_structurerecentOptional[int]until_foundskip_videosskip_live_photos	align_rawxmp_sidecarset_exif_datetimekeep_icloud_recent_daysonly_print_filenamesdry_runauto_deleter    c                 C  s~   t di d| d|d|dt|pdd|d|d|d	|d
|d|	d|
d|d|d|d|d|d|d|S )z@Build one canonical sync options object for sync-style commands.r[   r\   rD   rR   r3   r_   r`   ra   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   )r    tuple)r[   r\   rD   rN   r_   r`   ra   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   r3   r3   r6   _build_photo_sync_options   sJ   	
ro   r<   payloaddict[str, Any]titleNonec                C  s   | j t|ddgd|d fd|d fd|d fd	d
|d p dfd|d p'dfd|d fd|d fd|d fd|d fd|d fg
 |d D ]}|d dkrRqI| j |d  d|d   qIdS ) z*Render one photo sync result in text mode.MetricValue	Directoryr[   z
State Path
state_pathLibraryrD   Albumsz, rR   z(all photos)Sync Cursorsync_cursor zShort Circuitedshort_circuited
Downloadeddownloaded_countSkippedskipped_countDeleteddeleted_countListedlisted_countitemsactionskippedz: pathN)consoleprintr   join)r<   rp   rr   itemr3   r3   r6   _render_photo_sync_result   s,   







 r   optionsinterval_secondsint
iterations
int | NoneIterator[dict[str, Any]]c                 #  sx    t d fdd| jdd}	 zt dfdd| jd}W n
 ty+   Y dS w |d	7 }t|}||d
< |V  q)z7Yield normalized sync payloads from the watch iterator.r.   c                     s   j  dS )N)r   r   )watchr3   )r   r   r   r2   r3   r6   r7      s
    z+_iter_photo_watch_results.<locals>.<lambda>r9   r   Tc                     s   t  S r0   )nextr3   )
watch_iterr3   r6   r7          N   	iteration)r
   r:   StopIterationr   )r5   r2   r   r   r   
run_numbersync_resultrp   r3   )r   r   r   r2   r   r6   _iter_photo_watch_results   s,   
	

r   r   c             	   C  sJ   |du r| j d| d| d dS | j d| d| d| d dS )zGPrint a lightweight progress message before one watch iteration starts.NzStarting photo watch run z (poll interval zs)... of r   r   )r<   r   r   r   r3   r3   r6   _print_photo_watch_start     	r   next_iterationc             	   C  sJ   |du r| j d| d| d dS | j d| d| d| d dS )z<Print a progress message between completed watch iterations.NzWaiting zs before photo watch run z...r   r   )r<   r   r   r   r3   r3   r6   _print_photo_watch_wait  r   r   rR   Fc              
     z   t | |||||||d\}}	 dd td fdd|	jdD }
|jr*||
 dS |jtd	g d
dd |
D  dS )zList photo albums.r-   c                 S     g | ]}t |qS r3   r   .0rN   r3   r3   r6   
<listcomp>D      z!photos_albums.<locals>.<listcomp>r.   c                     
   t  jS r0   )listrR   r3   r1   r3   r6   r7   H     
 zphotos_albums.<locals>.<lambda>r9   NzPhoto AlbumsNamez	Full NameCountc                 S  "   g | ]}|d  |d |d fqS name	full_namecountr3   r   r3   r3   r6   r   S     " r=   r
   r:   json_output
write_jsonr   r   r   r$   r&   r'   r(   r)   r*   r+   r,   r<   r5   rp   r3   r1   r6   photos_albums.  6   


r   zshared-streamsc              
     r   )zList shared photo streams.r-   c                 S  r   r3   r   r   r3   r3   r6   r   n  r   z)photos_shared_streams.<locals>.<listcomp>r.   c                     r   r0   )r   rW   r3   r1   r3   r6   r7   r  r   z'photos_shared_streams.<locals>.<lambda>r9   NzShared Photo Streamsr   c                 S  r   r   r3   r   r3   r3   r6   r   }  r   r   r   r3   r1   r6   photos_shared_streamsX  r   r   rA   c              
     r   )z0List available photo libraries and sync cursors.r-   c                 S  s   g | ]	\}}t ||qS r3   )r   )r   keyrD   r3   r3   r6   r     s    z$photos_libraries.<locals>.<listcomp>r.   c                     s
    j  S r0   )rA   r   r3   r1   r3   r6   r7     r   z"photos_libraries.<locals>.<lambda>r9   NzPhoto Libraries)KeyScopeZoneIndexingrz   c                 S  .   g | ]}|d  |d |d |d |d fqS )r   rG   	zone_nameindexing_stater{   r3   r   r   r3   r3   r6   r         r   r   r3   r1   r6   photos_libraries  s:   


r   r   z--albumz#Album name. Defaults to all photos.rootz	--libraryz--shared-stream2   z--limitr   zMaximum photos to show.)minr#   limitc              
     s   t | |||||	|
|d\}}}t||||d dd td fdd|jdD }|jr4|| d	S |jtdg d
rBddgng  fdd|D  d	S )zList photo assets.r-   rN   rD   rP   c                 S  r   r3   )r   r   r3   r3   r6   r     r   zphotos_list.<locals>.<listcomp>r.   c                     s   t t jS r0   )r   r   r2   r3   )rY   r   r3   r6   r7     s    zphotos_list.<locals>.<lambda>r9   N)IDFilenameTypeCreatedSizeLikedz
Like Countc                   sF   g | ]}|d  |d |d |d |d f r|d |d fnd qS )idfilename	item_typecreatedr_   liked
like_countr3   r3   )r   photo)rP   r3   r6   r     s    	)	r=   rZ   r
   r:   r   r   r   r   r   )r$   rN   rD   rP   r   r&   r'   r(   r)   r*   r+   r,   r<   r5   r2   rp   r3   )rY   r   rP   r6   photos_list  sL   

	r   rC   .zPhoto asset id.z7Album name to search before falling back to all photos.photo_idc              
     s   t | |||||	|
|d\}}t||||d ztd fdd|jd}W n ty= } z	td d|d	}~ww t|}|jrL|| d	S t	|j
| d	S )
z0Show detailed metadata for a single photo asset.r-   r   r.   c                         d ur  S j  S r0   rT   r3   rY   r   r2   r3   r6   r7   (      zphotos_get.<locals>.<lambda>r9   No photo matched 'rB   N)r=   rZ   r
   r:   KeyErrorr   r   r   r   r   r   )r$   r   rN   rP   rD   r&   r'   r(   r)   r*   r+   r,   r<   r5   r   errrp   r3   r   r6   
photos_get  s@   

r   changesz--sincez#Sync cursor to fetch changes after.d   zMaximum changes to show.sincec              
     s   t | ||||||	|
d\}}}t||| dd td fdd|jdD }|jr2|| dS |jtd	g d
dd |D  dS )z%List incremental photo change events.r-   c                 S  r   r3   )r   )r   changer3   r3   r6   r   P  r   z"photos_changes.<locals>.<listcomp>r.   c                     s   t t jdS )N)r   )r   r   iter_changesr3   rU   r   r   r3   r6   r7   T  rV   z photos_changes.<locals>.<lambda>r9   NzPhoto Changes)KindRecordr   r   Modifiedc                 S  r   )kindrecord_namerecord_typedeletedmodifiedr3   r   r3   r3   r6   r   _  r   )	r=   rK   r
   r:   r   r   r   r   r   )r$   rD   r   r   r&   r'   r(   r)   r*   r+   r,   r<   r5   r2   rp   r3   r   r6   photos_changes4  s<   

r   zsync-cursorc	              
     s   t | |||||||d\}	}
}t|
|| t ds"td| dtd fdd|
jd}t||d	}|	jr>|	| d
S |	j	
| d
S )z1Show the current sync cursor for a photo library.r-   r{   zPhoto library 'z ' does not support sync cursors.r.   c                     s      S r0   )r{   r3   rU   r3   r6   r7     r   z$photos_sync_cursor.<locals>.<lambda>r9   )rD   N)r=   rK   hasattrr   r
   r:   r   r   r   r   r   )r$   rD   r&   r'   r(   r)   r*   r+   r,   r<   r5   r2   cursorrp   r3   r   r6   photos_sync_cursorm  s.   



r   downloadz--outputzDestination file path.originalz	--versionzPhoto version to download.outputversionc              
     s   t | |||	|
|||d\}}t||||d ztd fdd|jdW n ty= } z	td d|d	}~ww tdfd
d|jd}|d	u rStd|jjddd || |j	rp|
t|d d	S |jt| d	S )zDownload a photo asset.r-   r   r.   c                     r   r0   r   r3   r   r3   r6   r7     r   z!photos_download.<locals>.<lambda>r9   r   rB   Nc                     s    j dS )N)r   )r   r3   )r   r   r3   r6   r7     rX   z,No data was returned for that photo version.T)parentsexist_ok)r   r   r   )r=   rZ   r
   r:   r   r   parentmkdirwrite_bytesr   r   r?   r   r   )r$   r   rN   rP   rD   r   r   r&   r'   r(   r)   r*   r+   r,   r<   r5   r   datar3   )rY   r   r   r2   r   r6   photos_download  sT   

r  syncz--directoryTz(Destination directory for synced photos.)	file_okaydir_okayresolve_pathr#   z3Album name to sync. Repeat to sync multiple albums.z--state-dirzMDirectory for persistent sync state. Defaults to <directory>/.pyicloud-state.z--sizez7Primary photo size to sync: original, medium, or thumb.z--live-photo-sizez:Live photo video size to sync: original, medium, or thumb.nonez--folder-structurezODatetime folder layout, for example '{:%Y/%m}', or 'none' for a flat directory.z--recentz.Only sync photos added within the last N days.z--until-foundz/Stop after N consecutive already-current files.z--skip-videosz7Skip standalone videos and live photo video companions.z--skip-live-photosz Skip live photo assets entirely.zas-isz--align-rawz9Treat RAW+JPEG pairs as: as-is, original, or alternative.z--xmp-sidecarzAExport generated XMP sidecars next to synced primary photo files.z--set-exif-datetimezJSet JPEG EXIF created timestamps when the file does not already have them.z--keep-icloud-recent-dayszSDelete remote assets after local confirmation unless they were taken within N days.z--only-print-filenamesz4Print the target filenames without downloading them.z	--dry-runz4Preview sync actions without writing files or state.z--auto-deletezLDelete local files that are no longer present remotely for this sync target.c               
     s.  t | |||||||d\}}tdi d|d|d|d|d|d|d|d	|d
|	d|
d|d|d|d|d|d|d|d| ztd fdd|jd}W n tyl } ztt||d}~ww t|}|jr{|	| dS |r|d D ]
}|j
|d  qdS t||dd dS )z3Synchronize photo resources into a local directory.r-   r[   r\   rD   rN   r_   r`   ra   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   r.   c                     
     S r0   r  r3   r   r2   r3   r6   r7   f  r   zphotos_sync.<locals>.<lambda>r9   Nr   r   z
Photo Syncrr   r3   )r=   ro   r
   r:   r   r   r?   r   r   r   r   r   r   ) r$   r[   rN   rD   r\   r_   r`   ra   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   r&   r'   r(   r)   r*   r+   r,   r<   r5   r   r   rp   r   r3   r  r6   photos_sync  s   k
	


r  r   i,  z
--intervalz+Poll interval in seconds between sync runs.z--iterationsz?Stop after N sync runs. Defaults to watching until interrupted.intervalc           %   
     sR  t | |||||||d\}}td&i d|d|d|d|d|d|d|d	|d
|	d|
d|d|d|d|d|d|d|d| z|jr||du rit| ||dD ]
}|jt| q[W dS tt| ||d}|| W dS d} |du s| |k r| d }!| dkrt	|||!|d t
| |j  t||!||d td fdd|jd}"| d7 } t|"}| |d< |r|du s|r|dkr|jd|d   |d  D ]
}#|j|#d!  qnt||d"|d  d# |du s| |k sW dS W dS  ty }$ ztt|$|$d}$~$w ty( }$ ztjd$d%|$d}$~$ww )'z;Watch a photo sync target and rerun it on a fixed interval.r-   r[   r\   rD   rN   r_   r`   ra   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   N)r5   r2   r   r   r   r   r   )r   r   r   )r   r   r   r.   c                     r	  r0   r
  r3   r  r3   r6   r7   8  r   zphotos_watch.<locals>.<lambda>r9   r   zrun r   r   zPhoto Watch Run r     )coder3   )r=   ro   r   r   r   r   r   r   r   r   timesleepr   r
   r:   r   r   r   r   r?   KeyboardInterrupttyperExit)%r$   r[   rN   rD   r\   r_   r`   ra   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   r  r   r&   r'   r(   r)   r*   r+   r,   r<   r5   rp   payloadscompleted_iterationsr   r   r   r   r3   r  r6   photos_watchv  s   x
	


	

$r  )r$   r%   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   )r5   r   r2   r   r>   r?   r@   r   )rD   r   r>   r?   rL   r?   r@   r   )r5   r   r2   r   rN   rO   rD   r?   rP   rQ   r@   r   )&r[   r   r\   r]   rD   r?   rN   r^   r_   r?   r`   r?   ra   r?   rb   rc   rd   rc   re   rQ   rf   rQ   rg   r?   rh   rQ   ri   rQ   rj   rc   rk   rQ   rl   rQ   rm   rQ   r@   r    )r<   r   rp   rq   rr   r?   r@   rs   )r5   r   r2   r   r   r    r   r   r   r   r@   r   )
r<   r   r   r   r   r   r   r   r@   rs   )
r<   r   r   r   r   r   r   r   r@   rs   )r$   r%   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )r$   r%   rN   rO   rD   r?   rP   rQ   r   r   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )r$   r%   r   r?   rN   rO   rP   rQ   rD   r?   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )r$   r%   rD   r?   r   rO   r   r   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )r$   r%   rD   r?   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )r$   r%   r   r?   rN   rO   rP   rQ   rD   r?   r   r   r   r?   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )6r$   r%   r[   r   rN   r^   rD   r?   r\   r]   r_   r?   r`   r?   ra   r?   rb   rc   rd   rc   re   rQ   rf   rQ   rg   r?   rh   rQ   ri   rQ   rj   rc   rk   rQ   rl   rQ   rm   rQ   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   ):r$   r%   r[   r   rN   r^   rD   r?   r\   r]   r_   r?   r`   r?   ra   r?   rb   rc   rd   rc   re   rQ   rf   rQ   rg   r?   rh   rQ   ri   rQ   rj   rc   rk   rQ   rl   rQ   rm   rQ   r  r   r   rc   r&   r   r'   r   r(   r   r)   r   r*   r   r+   r   r,   r   r@   rs   )I__doc__
__future__r   r  	itertoolsr   pathlibr   typingr   r   r   r  pyicloud.cli.contextr   r	   r
   pyicloud.cli.normalizer   r   r   r   r   r   r   pyicloud.cli.optionsr   r   r   r   r   r   r   r   r   r   pyicloud.cli.outputr   r   r   pyicloud.services.photosr   r    +pyicloud.services.photos_cloudkit.constantsr!   r"   _PHOTO_LIBRARY_KEY_HELP_PHOTO_SHARED_STREAM_HELPTyperappr=   rE   rK   rM   rZ   ro   r   r   r   r   commandr   r   r   Optionr   Argumentr   r   r   r  r  r  r3   r3   r3   r6   <module>   s   $0	






1
-

#
))2F78%F 