o
    l>jI                     @  s  d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	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mZ eeZeh dZdZe
ddG dd dZdnddZdoddZdpd"d#Z dqd&d'Z!drd)d*Z"dsd.d/Z#dtd1d2Z$dud4d5Z%dvd6d7Z&dwd9d:Z'dtd;d<Z(dxd?d@Z)dydAdBZ*dzdEdFZ+d{dIdJZ,d|dKdLZ-d}dNdOZ.d~dQdRZ/ddTdUZ0ddZd[Z1dd\d]Z2dd_d`Z3ddddeZ4ddfdgZ5ddjdkZ6ddldmZ7dS )z9Local materialization helpers for the Photos sync engine.    )annotationsN)	dataclass)datetime	timedeltatimezone)Path)Any)ElementTree   )decode_encrypted_textrecord_field_value>   .arw.cr2.cr3.crw.dng.nef.nrf.nrw.orf.pef.raf.rw2zpyicloud photos-cloudkitT)slotsc                   @  s   e Zd ZU 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< 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< dZded< dZded< dS )PhotoXmpMetadataz$Metadata exported into XMP sidecars.strtoolkitN
str | Nonetitledescription
int | Noneorientationmakedigital_source_typelist[str] | Nonekeywordsfloat | Nonegps_altitudegps_latitudegps_longitude	gps_speeddatetime | Nonegps_timestampcreate_daterating)__name__
__module____qualname____doc____annotations__r   r   r!   r"   r#   r%   r'   r(   r)   r*   r,   r-   r.    r4   r4   b/home/thesage/.local/lib/python3.10/site-packages/pyicloud/services/photos_cloudkit/materialize.pyr   '   s    
 r   resourcer   returnboolc                 C  s>   t | ddpd }d|v rdS tt | ddj }|tv S )z7Return ``True`` when a resource looks like a RAW image.typeN rawTfilename)getattrlowerr   suffixRAW_EXTENSIONS)r6   resource_typer?   r4   r4   r5   resource_is_raw;   s
   rB   	resourcesdict[str, Any]policyr   c                 C  s   t | }|dkr
|S |d}|d}|du s|du r|S t|}t|}|dkr9|r9|s9|||d< |d< |S |dkrJ|rJ|sJ|||d< |d< |S )zEReturn a resource mapping with RAW+JPEG original/alternative aligned.zas-isoriginalalternativeN)dictgetrB   )rC   rE   alignedrF   rG   original_is_rawalternative_is_rawr4   r4   r5   apply_align_raw_policyE   s   

rM   pathr   taken_atr   Nonec                 C  s   | j  dvr	dS z|  }W n ty   td|  Y dS w t|r&dS t||dd}|du r;td|  dS z| 	| W dS  tyS   td|  Y dS w )zBWrite EXIF created timestamps for JPEGs that do not have them yet.>   .jpg.jpegNz!Failed to read %s for EXIF updatez%Y:%m:%d %H:%M:%S)
jpeg_bytes	timestampz$Failed to update EXIF datetime on %sz$Failed to write %s after EXIF update)
r?   r>   
read_bytesOSErrorLOGGERdebug_jpeg_has_exif_datetime_insert_exif_datetime_segmentstrftimewrite_bytes)rN   rO   dataupdatedr4   r4   r5   set_exif_datetime_if_missingZ   s,   r_   asset_recorddry_runc                 C  s`   t |}|du r
dS | | j d}| rt|sdS |r!dS |tjt|ddd dS )zBWrite or refresh a generated XMP sidecar for the given asset file.Nz.xmpzutf-8T)encodingxml_declaration)	build_xmp_metadata	with_namenameexists_can_overwrite_xmp_sidecarr\   r	   tostring_render_xmp_xml)rN   r`   ra   metadatasidecar_pathr4   r4   r5   write_xmp_sidecarv   s   rm   PhotoXmpMetadata | Nonec                 C  s   | du rdS t | d}t | d}t| }t| }t| }t| }t| }t| d}|dkr/dnd}	|dkr7dnd}
tt||||	|
||	d|	d	|	d
|	d|	d||dS )z;Build an XMP metadata payload from a CloudKit asset record.N
captionEncextendedDescEncassetSubtypeV2   
ScreenshotscreenCapturealtitudelatitude	longitudespeedrT   )r   r   r   r!   r"   r#   r%   r'   r(   r)   r*   r,   r-   r.   )
r   _extract_orientation_extract_keywords_extract_location_extract_create_date_extract_ratingr   r   PYICLOUD_XMP_TOOLKITrI   )r`   r   r   r!   r%   locationr-   r.   asset_subtyper"   r#   r4   r4   r5   rd      s8   


rd   record
field_namebytes | Nonec                 C  sd   t | |}|d u rd S t|tr|}nt|tr|d}nd S zt|W S  ty1   | Y S w )Nascii)r   
isinstancebytesr   encodebase64	b64decode	Exception)r   r   valuer;   r4   r4   r5   _decode_field_bytes   s   


r   r    c                 C  s   t | d}|r|drd S ztt|tj }W n
 ty%   Y d S w |d}t	|t
s2d S |d}t	|tr>|S d S )NadjustmentSimpleDataEnc)s   crdts   bplist00rk   r!   )r   
startswithjsonloadszlib
decompress	MAX_WBITSr   rI   r   rH   int)r`   r;   adjustmentsrk   r!   r4   r4   r5   ry      s   



ry   r$   c                 C  sR   t | d}|s	d S zt|}W n
 ty   Y d S w t|ts"d S dd |D S )NkeywordsEncc                 S  s   g | ]}t |qS r4   )r   ).0itemr4   r4   r5   
<listcomp>   s    z%_extract_keywords.<locals>.<listcomp>)r   plistlibr   r   r   list)r`   r;   r   r4   r4   r5   rz      s   

rz   c                 C  s   t | d}|s	i S zt|}W n ty   i  Y S w t|ts#i S |d}|d ur3t|ts3d }t|dt|dt|dt|d|dS )NlocationEncrT   altlatlonrx   )ru   rv   rw   rx   rT   )	r   r   r   r   r   rH   rI   r   _maybe_float)r`   r;   r   rT   r4   r4   r5   r{      s&   


r{   r+   c                 C  sj   t | d}t|tr|S t|ttfsd S t | d}t|ttfr%t|nd}tj|d tt|ddS )N	assetDatetimeZoneOffsetr   g     @@)seconds)tz)r   r   r   r   floatfromtimestampr   r   )r`   
asset_dateoffsetoffset_secondsr4   r4   r5   r|      s   


r|   c                 C  s:   t | ddkr	dS t | ddkrdS t | ddkrdS d S )NisHiddenr
   	isDeleted
isFavorite   )r   )r`   r4   r4   r5   r}     s   r}   r   r&   c                 C  s   t | ttfrt| S d S N)r   r   r   )r   r4   r4   r5   r     s   r   c                 C  sV   z	t |  }W n t jy   Y dS w |jdp |jd}t|to*|t	S )NFz{adobe:ns:meta/}xmptkx:xmptk)
r	   parsegetroot
ParseErrorattribrI   r   r   r   r~   )rN   rootr   r4   r4   r5   rh     s   rh   rk   ElementTree.Elementc                 C  sd  t dd| jd}t |dddi}t ddd	d
}t dddd}t dddd}t dddd}t dddd}t dddd}| jrT| jt |d_| jr_| jt |d_| jr{t |d}	t |	d}
| jD ]	}|t |
d_qq| jd urt	| jt |d_| j
r| j
t |d_| jr| jt |d_| jd urt	| jt |d_| jd urt	| jt |d_| jd urt	| jt |d_| jd urt	| jt |d _| jd ur| jd!t |d"_| jd ur| jd!}|t |d#_|t |d$_| jd urt	| jt |d%_||||||fD ]}tt|d&kr.|| q|S )'Nz	x:xmpmetazadobe:ns:meta/)zxmlns:xr   zrdf:RDFz	xmlns:rdfz+http://www.w3.org/1999/02/22-rdf-syntax-ns#zrdf:Descriptionr:   z http://purl.org/dc/elements/1.1/)	rdf:aboutzxmlns:dczhttp://ns.adobe.com/exif/1.0/)r   z
xmlns:exifz+http://iptc.org/std/Iptc4xmpExt/2008-02-29/)r   zxmlns:Iptc4xmpExtz"http://ns.adobe.com/photoshop/1.0/)r   zxmlns:photoshopzhttp://ns.adobe.com/tiff/1.0/)r   z
xmlns:tiffzhttp://ns.adobe.com/xap/1.0/)r   z	xmlns:xmpzdc:titlezdc:descriptionz
dc:subjectzrdf:Seqzrdf:liztiff:Orientationz	tiff:MakezIptc4xmpExt:DigitalSourceTypezexif:GPSAltitudezexif:GPSLatitudezexif:GPSLongitudezexif:GPSSpeedz%Y-%m-%dT%H:%M:%S%zzexif:GPSTimeStampzxmp:CreateDatezphotoshop:DateCreatedz
xmp:Ratingr   )r	   Elementr   
SubElementr   textr   r%   r!   r   r"   r#   r'   r(   r)   r*   r,   r[   r-   r.   lenr   append)rk   xml_docrdfdescription_dcdescription_exifdescription_iptcdescription_photoshopdescription_tiffdescription_xmpsubjectseqkeywordrT   r   r4   r4   r5   rj     s   









rj   rS   r   c           	        s   t | d u r
dS t}|d u rdS td|}|d u r dS t|}|d u r+dS |\}}dD ]}t||}|r> dS q1t|d}|d u rKdS t|}|d u rVdS |\} t fdddD S )	NF   )2  Ti  c                 3  s    | ]	}t  |V  qd S r   )_read_ascii_tag)r   tagexif_ifdexif_payloadr4   r5   	<genexpr>  s    z*_jpeg_has_exif_datetime.<locals>.<genexpr>)    )_extract_exif_payload_tiff_byte_order_read_uint32_parse_tiff_ifdr   _read_long_tagany)	rS   
byte_orderifd0_offsetparsed_ifd0r   r   exif_ifd_offsetr4   r   r5   rY     s4   

rY   c                 C  s   t | dk s| d d dkrd S d}|d t | krx| | dkr"d S | |d  }|dv r.d S td| |d |d  d }|dk sL|d | t | krNd S |d }|d | }|d	krn| ||d
  dkrn| |d
 | S |}|d t | ksd S )Nr            r
   >         >Hr            Exif  )r   structunpack)rS   indexmarkersegment_lengthpayload_startpayload_endr4   r4   r5   r     s(    r   r   c                 C  s<   t | dk rd S | d d dkrdS | d d dkrdS d S )Nr      II   <   MM   >)r   )r   r4   r4   r5   r     s   r   rT   c                 C  sv   t | dk s| d d dkrd S |dd }t|}d| }dtdt |d  | }| d d | | dd   S )Nr   r   r       r   s   r   )r   r   _build_exif_tiffr   pack)rS   rT   ascii_timestamptiffpayloadsegmentr4   r4   r5   rZ     s   rZ   r   c                 C  s   d}|t dd t dd }d}d}|| }|t|  }d}|| }|t|  }	tdt| |td|g}
td	t| |td
t| |	g}|t dt|
 d|
 t dd |  t dt| d| t dd |  |  S )Nr   z<H*   <I      r   r   r   r       r   )r   r   r   _pack_ascii_entry_pack_long_entryjoin)r   r   tiff_headerr   	ifd0_sizeifd0_data_offsetr   exif_ifd_sizeexif_data_offsetdigitized_offsetr   r   r4   r4   r5   r     sF   

	r   r   r   countr   c                 C  s   t d| d|t d| S )N<HHIr   r   r   r   )r   r  r   r4   r4   r5   r   
     r   c                 C  s   t d| ddt d| S )Nr	  r   r
   r   r
  )r   r   r4   r4   r5   r     r  r   4tuple[bytes, dict[int, tuple[int, int, int]]] | Nonec                 C  s  t | dk s|d t | krd S | d d }|dkrd}n	|dkr$d}nd S t| ||}|d u r2d S i }|d }t|D ]I}|d t | krI d S t| ||}t| |d |}	t| |d |}
t| |d |}d ||	|
|hv rr d S t|	t|
t|f|t|< |d7 }q<||fS )	Nr   r   r   r   r   r      r   )r   _read_uint16ranger   r   )r   r   r   fmtr  entriesentry_offsetr   r   
field_type
item_countvalue_offsetr4   r4   r5   r     s2   
r   ifddict[int, tuple[int, int, int]]r   c                 C  s   | |}|d u rd S |\}}}|dks|dk rd S |dkr)td|d | }n|| t| kr:| |||  }nd S |djdddpGd S )	Nr   r
   r   r   r   r   ignore)errors)rI   r   r   r   rstripdecode)r   r  r   entryr  r  r  r;   r4   r4   r5   r   2  s   

r   c                 C  s8   | |}|d u rd S |\}}}|dks|dkrd S |S )Nr   r
   )rI   )r   r  r   r  r  r  r  r4   r4   r5   r   D  s   

r   r]   r  c                 C  :   |d t | kr
d S t|  d| ||d  d S )Nr   Hr   r   r   r   r  r]   r   r  r4   r4   r5   r  P     &r  c                 C  r  )Nr   Ir   r  r   r4   r4   r5   r   V  r!  r   )r6   r   r7   r8   )rC   rD   rE   r   r7   rD   )rN   r   rO   r   r7   rP   )rN   r   r`   r   ra   r8   r7   rP   )r`   r   r7   rn   )r   r   r   r   r7   r   )r`   r   r7   r    )r`   r   r7   r$   )r`   r   r7   rD   )r`   r   r7   r+   )r   r   r7   r&   )rN   r   r7   r8   )rk   r   r7   r   )rS   r   r7   r8   )rS   r   r7   r   )r   r   r7   r   )rS   r   rT   r   r7   r   )r   r   r7   r   )r   r   r  r   r   r   r7   r   )r   r   r   r   r7   r   )r   r   r   r   r7   r  )r   r   r  r  r   r   r7   r   )r   r   r  r  r   r   r7   r    )r]   r   r   r   r  r   r7   r    )8r2   
__future__r   r   r   loggingr   r   r   dataclassesr   r   r   r   pathlibr   typingr   	xml.etreer	   mappersr   r   	getLoggerr/   rW   	frozensetr@   r~   r   rB   rM   r_   rm   rd   r   ry   rz   r{   r|   r}   r   rh   rj   rY   r   r   rZ   r   r   r   r   r   r   r  r   r4   r4   r4   r5   <module>   s^    







#








	
~





#


 

