
    +j=                        S SK r S SKrS SKrS SKJr  S SKJr  S SKJrJ	r	J
r
JrJrJrJr  S SKJr  S SKJrJrJrJrJrJrJrJrJrJrJrJrJrJ r J!r!J"r"J#r#J$r$J%r%  S SK&J'r'  S SK(J)r)  S S	K*J+r+J,r,J-r-J.r.J/r/J0r0J1r1J2r2  S S
K3J4r4   S-S\5S\5S\,S-  4S jjr6       S.S\5S\5S-  S\\5   S-  S\0S\5S\5S\5S-  S\5S-  S\,4S jjr7 S/S\5S\5S\8S\84S jjr9  S0S\5S\5S-  S\5S\,4S jjr:S\5S\84S jr;S\5S\+S-  4S jrSr<          S1S\5S\\5   S-  S\\5   S-  S \5S-  S!\=S-  S"\>S#\>S$\5S%\5S&\5S-  S\/4S' jjr?S(\S\@4S) jrAS$\5S%\5S\5S-  4S* jrB S-S\5S\5S\.S-  4S+ jjrC S-S\5S\5S\.4S, jjrDg)2    N)timezone)Sequence)CursorPayloadInvalidCursorErrordecode_cursordecode_cursor_intdecode_cursor_timeencode_cursorencode_cursor_from_time)Asset)asset_exists_by_hashreference_exists_for_asset_iddelete_reference_by_idfetch_reference_and_assetsoft_delete_reference_by_idfetch_reference_asset_and_tagsget_asset_by_hashget_reference_by_idget_reference_with_owner_checklist_references_pagelist_all_file_paths_by_asset_idlist_references_by_asset_idset_reference_metadataset_reference_previewset_reference_tagsupdate_asset_hash_and_mimeupdate_reference_access_timeupdate_reference_nameupdate_reference_updated_at)select_best_live_path)compute_relative_filename)	AssetDataAssetDetailResultAssetSummaryDataDownloadResolutionResultListAssetsResultUserMetadataextract_asset_dataextract_reference_data)create_sessionreference_idowner_idreturnc                     [        5        n[        UU US9nU(       d
   S S S 5        g Uu  pEn[        [        U5      [	        U5      US9sS S S 5        $ ! , (       d  f       g = f)Nr+   r,   refassettags)r*   r   r#   r)   r(   )r+   r,   sessionresultr1   r2   r3   s          D/home/wildlama/comfy/ComfyUI/app/assets/services/asset_management.pyget_asset_detailr7   7   sb     
	W/%

  
	 "D &s+$U+
 
		s   A!A
A!namer3   user_metadata
tag_origin	mime_type
preview_idc                    [        5        n[        XU5      n	Sn
Ub  XR                  :w  a  [        XUS9  Sn
U	R                  (       a  [        U	R                  5      OS nS nUb  [        U5      nO<U(       a5  U	R                  =(       d    0 nUR                  S5      U:w  a  [        U5      nUb  U(       a  XS'   [        XUS9  Sn
Ub  [        UU UUS9  Sn
Ub  [        XR                  US9nU(       a  Sn
Ub  [        UU US9  Sn
U
(       a  Uc	  [        XS	9  [        UU US
9nU(       d  [!        S5      eUu  n	nn[#        [%        U	5      ['        U5      US9nUR)                  5         UsS S S 5        $ ! , (       d  f       g = f)NF)r+   r8   Tfilename)r+   r9   )r+   r3   origin)asset_idr;   r+   preview_reference_idr+   r/   zState changed during updater0   )r*   r   r8   r   	file_pathr!   dictr9   getr   r   r   r@   r   r   r   RuntimeErrorr#   r)   r(   commit)r+   r8   r3   r9   r:   r,   r;   r<   r4   r1   touchedcomputed_filenamenew_metacurrent_metaupdatedr5   r2   tag_listdetails                      r6   update_asset_metadatarP   L   s    
	W,WHM 0!'4PGHK5cmmD[_ $$M*H,,2L
+/@@- '8$"( G)!	 G 0,,)G !!)%/
 G},'K/%

 <==%UH"&s+$U+

 	K 
		s   E!E66
Fdelete_content_if_orphanc                    [        5        nU(       d%  [        X0US9nUR                  5         UsSSS5        $ [        X0S9nU(       a  UR                  OSnU(       a  UR
                  OSn[        X0US9nU(       d  UR                  5          SSS5        gU(       d  UR                  5          SSS5        g[        X6S9nU(       a  UR                  5          SSS5        g[        X6S9n	U(       a  U	R                  U5        UR                  [        U5      n
U
b  UR                  U
5        UR                  5         U	 Hg  n[        R                  " [        5         U(       a:  [         R"                  R%                  U5      (       a  [         R&                  " U5        SSS5        Mi     SSS5        g! , (       d  f       M  = f! , (       d  f       g= f)a  Delete an asset reference.

With ``delete_content_if_orphan=False`` (a soft delete), the reference is
hidden and the underlying content is preserved. With ``True``, the content
is also removed once it becomes orphaned.

Note: the public DELETE /api/assets/{id} endpoint always soft-deletes
(passes ``False``); the orphan-reclamation path is intentionally
internal-only, retained for a future GC/admin caller.
r/   NrC   FTr@   )r*   r   rH   r   r@   rD   r   r   r   appendrF   r   delete
contextlibsuppress	Exceptionospathisfileremove)r+   r,   rQ   r4   deletedref_rowr@   rD   still_exists
file_paths	asset_rowps               r6   delete_asset_referencerc      sv    
	W'1XG NN 
	 &gI'.7##D)0G%%d	(
 NN% 
	( NN- 
	0 5WPNN7 
	> 5WP
i(KKx0	 NN9% A$$Y/**IIaL 0/ W 
` 	 0/Y 
	` s=   #GAGG7!G!A:GAF2G2
G<G
GrB   c                    [        5        n[        X0U5        [        UU US9  [        X0US9nU(       d  [	        S5      eUu  pVn[        [        U5      [        U5      US9nUR                  5         UsS S S 5        $ ! , (       d  f       g = f)NrA   r/   z#State changed during preview updater0   )	r*   r   r   r   rG   r#   r)   r(   rH   )	r+   rB   r,   r4   r5   r1   r2   r3   rO   s	            r6   set_asset_previewre      s    
 
	W&whG%!5	
 0
 DEE!D"&s+$U+

 	/ 
		s   A'A<<
B

asset_hashc                 ^    [        5        n[        XS9sS S S 5        $ ! , (       d  f       g = fN)rf   )r*   r   )rf   r4   s     r6   asset_existsri      s    		W#GC 
		s   	
,c                 t    [        5        n[        XS9n[        U5      sS S S 5        $ ! , (       d  f       g = frh   )r*   queries_get_asset_by_hashr(   )rf   r4   r2   s      r6   r   r     s(    		W)'I!%( 
		s   )
7)
created_at
updated_atr8   sizeinclude_tagsexclude_tagsname_containsmetadata_filterlimitoffsetsortorderafterc
                    Sn
SnU[         ;   nU	bk  U[         ;  a  [        SU< 35      e[        U	[         US9nUR                  U:w  a  [        SUR                  < SU< 35      e[	        U5      UR
                  pU(       a  US-   OUn[        5        n[        UU UUUUUUUUU
US9u  nnnSnU(       a&  [        U5      U:  a  [        UUS-
     Xx5      nUSU n/ nU HS  nUR                  [        [        U5      [        UR                  5      UR                  UR
                  / 5      S95        MU     [!        UUUS	9sSSS5        $ ! , (       d  f       g= f)
a
  List assets with optional cursor pagination.

When ``after`` is supplied it overrides ``offset``. The cursor's sort field
must match ``sort`` and be in the cursor-supported allowlist; mismatches
raise InvalidCursorError so the handler can map to 400 INVALID_CURSOR.
Nz,cursor pagination is not supported for sort=)expected_orderzcursor sort field z does not match request sort    )r,   ro   rp   rq   rr   rs   rt   ru   rv   after_cursor_valueafter_cursor_idr0   )itemstotalnext_cursor)_CURSOR_SORT_FIELDSr   r   
sort_field_resolve_cursor_valueidr*   r   len_encode_next_cursorrT   r$   r)   r(   r2   rF   r&   )r,   ro   rp   rq   rr   rs   rt   ru   rv   rw   cursor_value	cursor_idmint_cursorpayloadfetch_limitr4   refstag_mapr~   r   r}   r1   s                         r6   list_assets_pager     s   $ #'L I
 --K**$>thG   ':5Q%$$W%7%7$::WX\W_`  #8"@'**i
  +%!)K		W3%%'++% 
gu #'3t9u, .d519otKK<D(*CLL .s3,SYY7 SVVR0   e5kRE 
		s   B-E
Er   c                     U R                   S;   a  [        U 5      R                  SS9$ U R                   S:X  a  [        U 5      $ U R                  $ )z<Map a decoded cursor payload to a column-typed Python value.)rl   rm   Ntzinforn   )r   r	   replacer   value)r   s    r6   r   r   _  sO    99 "'*22$2??V# ))==    c                    US:X  a   [        SU R                  U R                  US9$ US:X  aX  U R                  b  U R                  R                  c  g[        S[        U R                  R                  5      U R                  US9$ US:X  a  U R                  OU R                  nUc  g[        XR                  [        R                  S9U R                  US9$ )uZ  Mint a cursor pointing at *ref* for the given sort dimension.

Returns None when the boundary row carries a NULL sort value (e.g. an asset
record whose size_bytes hasn't been backfilled). Continuing pagination
across a NULL boundary is undefined under keyset ordering — better to
truncate cleanly here than to mint a cursor that mis-positions.
r8   )rv   rn   Nrl   r   )r
   r8   r   r2   
size_bytesstrrl   rm   r   r   r   utc)r1   ru   rv   r   s       r6   r   r   j  s     v~VSXXsvvUCCv~99		 4 4 <VS)=)=%>eTT"l2CNNE}"4hll)KSVV[`aar   c                    [        5        n[        X 5      nU(       d
   SSS5        g[        X#R                  S9nU Vs/ s H'  nUR                  S:X  d  UR                  U:X  d  M%  UPM)     nn[        U5      nU(       d
   SSS5        g[        R                  R                  U5      nU H4  n	U	R                  U:X  d  M  U	R                  (       d  M(  U	R                  n  O   UR                  =(       d"    [        R                  " U5      S   =(       d    Sn
SSS5        [        WW
WS9$ s  snf ! , (       d  f       N= f)a  Resolve a blake3 hash to an on-disk file path.

Only references visible to *owner_id* are considered (owner-less
references are always visible).

Returns a DownloadResolutionResult with abs_path, content_type, and
download_name, or None if no asset or live path is found.
NrS    r   application/octet-streamabs_pathcontent_typedownload_name)r*   rk   r   r   r,   r    rY   rZ   basenamerD   r8   r;   	mimetypes
guess_typer%   )rf   r,   r4   r2   r   rvisibler   display_namer1   ctypes              r6   resolve_hash_to_pathr     s    
	W)'> 
	 +7XXF
!zzR1::#9 t 	 
 )1 
	 ww''1C}}(SXXX"xx 
 OO *##L1!4*) 	# 
, $" #
 
	s:   D1D1$D,'D,-D12D1D1AD1,D11
D?c           
         [        5        n[        X US9nU(       d  [        SU  S35      eUu  pEUR                  (       a;  [        R
                  R                  UR                  5      (       a  UR                  nON[        X%R                  S9n[        U5      nU(       d)  [        SU  SUR                   SUR                   S35      eUR                  nUR                  n	[        X S	9  UR                  5         U	=(       d+    [        R                   " U=(       d    U5      S
   =(       d    Sn
U=(       d    [        R
                  R#                  U5      n[%        UU
US9sS S S 5        $ ! , (       d  f       g = f)Nr/   zAssetReference z
 not foundrS   z No live path for AssetReference z (asset id=z, name=)rC   r   r   r   )r*   r   
ValueErrorrD   rY   rZ   r[   r   r   r    FileNotFoundErrorr8   r;   r   rH   r   r   r   r%   )r+   r,   r4   pairr1   r2   r   r   ref_name
asset_mimer   r   s               r6   resolve_asset_for_downloadr     sB    
	W(
 |nJGHH
 ==RWW^^CMM::}}H /wJD,T2H'6|n E!!&
'#((1>  88__
$WH  *##H$89!<*) 	
 !>BGG$4$4X$>''
G 
		s   EE++
E9)r   )NNNmanualr   NN)T)Nr   )
r   NNNN   r   rl   descN)ErV   r   rY   datetimer   typingr   app.assets.services.cursorr   r   r   r   r	   r
   r   app.assets.database.modelsr   app.assets.database.queriesr   r   r   r   r   r   r   rk   r   r   r   r   r   r   r   r   r   r   r   r   app.assets.helpersr    app.assets.services.path_utilsr!   app.assets.services.schemasr"   r#   r$   r%   r&   r'   r(   r)   app.database.dbr*   r   r7   rP   boolrc   re   ri   r   rE   intr   objectr   r   r   r    r   r6   <module>r      s     	     -     * 5 D	 	 	 +
 


 
. !%"& !OO
*O 3-$
O  	O
 O O TzO d
O Oj &*??? #? 
	?H (,*  	>DS DT D
)# ))d*: ) C  )-)- $#'MSMS3-$&MS 3-$&MS :	MS
 D[MS MS MS MS MS :MS MS`= V b3 bs bsTz b. &&& $&V +
+
+
 +
r   