
    ujT                       d dl mZ d dlZ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 d dlmZmZ  ee      j!                         j"                  d   Z ee      ej(                  vr"ej(                  j+                  d  ee             d dlmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+  G d d	      Z,y)
    )annotationsN)PathPurePosixPath)quoteunquote)AnyCallable   )connect_databasecreate_database_filedefault_database_pathget_post_detailget_post_statsinitialize_databaselist_account_postslist_accountslist_collection_accountslist_database_fileslist_deleted_accountsopen_database_filereplace_collection_accountssave_database_assoft_delete_accountupsert_observationbuild_instagram_media_pathderive_stdown_rootIMAGE_EXTENSIONSVIDEO_EXTENSIONSsafe_media_componentc                  6   e Zd Zd%d&dZed'd       Zed(d       Zed)d       Zd*dZ	d+dZ
dd	d
dd	 	 	 	 	 	 	 	 	 d,dZd-d.dZed/d       Zd0dZd1dZd2dZdd	ddd3dZd4dZddd5dZd6dZd6dZd+dZd6dZd6dZd6dZd+d Zd6d!Zd7d"Zd8d#Zd9d$Zy):AnalyzeRepositoryNc                4   t        |      j                         j                         | _        |r't        |      j                         j                         nd | _        t        j                         | _        | j                  xs t        | j                        | _	        t        | j                        j                         | _        | j                  dz  j                         | _        | j                  | _        t        | j                  | j                         y )N	instagram)r   
expanduserresolvest_root_explicit_db_path	threadingRLock_db_lockr   db_pathr   stdown_rootinstagram_root_default_file_selector_file_selectorr   )selfr&   r+   s      ,D:\_St\Analyze8780\analyze8780_repository.py__init__zAnalyzeRepository.__init__*   s    G}//199;IPg!9!9!;!C!C!EVZ!)--T1Ft||1T-dll;CCE#//+=FFH6:6Q6QDLL$,,7    c                x   t         j                  dk(  r:t        j                  dd|  gt        j                  t        j                         y | j
                  }t         j                  dk(  rdt        |      gndt        |      g}t        j                  |t        j                  t        j                         y )Nwin32zexplorer.exez/select,)stdoutstderrdarwinopenzxdg-open)sysplatform
subprocessPopenDEVNULLparentstr)pathfoldercommands      r1   r.   z(AnalyzeRepository._default_file_selector4   s    <<7"8D6!23!))!))
 +.<<8+C63v;'*VYZ`VaIb););JDVDVWr3   c                F    	 | j                  |       y# t        $ r Y yw xY w)NTF)relative_to
ValueError)rA   roots     r1   _is_relative_toz!AnalyzeRepository._is_relative_toA   s*    	T" 		s    	  c                   t        |j                  d      xs d      j                         }t        |j                  d      xs d      j                  dd      j                         }|r|st	        d|j                  d             t        |      }|j                         sd|j                  v rt	        d	|j                  d             t        |      j                         j                         } |j                  |j                   j                         }| j                  ||      st	        d	|j                  d             |S )
N	root_path relative_path\/z)media asset path is incomplete: asset_id=idz..z0media asset path escaped storage root: asset_id=)r@   getstripreplacerF   r   is_absolutepartsr   r$   r%   joinpathrH   )clsasset	root_textrelative_textrelativerG   targets          r1   _resolve_asset_pathz%AnalyzeRepository._resolve_asset_pathI   s#   		+.4"5;;=	EIIo6<"=EEdCPVVXHSWHYZ[[ /!TX^^%;OPUPYPYZ^P_O`abbI))+335/779""640OPUPYPYZ^P_O`abbr3   c                    |j                  dt        |      f      j                         }|D cg c]  }t        |       c}S c c}w )Na  
            SELECT ma.id, ma.post_id, ma.asset_kind, ma.media_index, ma.storage_root_id,
                   ma.folder_name, ma.file_name, ma.relative_path, ma.local_status,
                   sr.root_path
            FROM media_assets ma
            LEFT JOIN storage_roots sr ON sr.id=ma.storage_root_id
            WHERE ma.post_id=? AND ma.local_status='AVAILABLE'
            ORDER BY ma.media_index, ma.id
            )executeintfetchalldict)r0   connpost_idrowsrows        r1   _post_asset_rowsz"AnalyzeRepository._post_asset_rowsX   sJ    || \O
 (* 	 &**TcS	T***s   Ac                    | j                   5  dddt        | j                        | j                  j                  dcd d d        S # 1 sw Y   y xY w)NTAnalyze8780z	2.3.8.297)okserviceversionr+   db_filename)r*   r@   r+   namer0   s    r1   healthzAnalyzeRepository.healthg   s:    ]](&t||,#||00 ]]s   /AAr
   2   FrK   page	page_sizeinclude_deletedsearch_patternc               z    | j                   5  t        | j                  ||||      cd d d        S # 1 sw Y   y xY w)Nrq   )r*   r   r+   )r0   rr   rs   rt   ru   s        r1   accountszAnalyzeRepository.accountsq   s0     ]] # /- ]]s   1:c           
        t        |xs d      }| j                  5  t        | j                        }	 d}t	        |j                  d|f      j                               }|st        d|       |j                  d      j                         }|D cg c]  }t        |d          }}|dgk(  }	t        |j                  d      j                         d         }
|r.t        |j                  d	|f      j                         d         }n|
}|	||||||
| j                  j                  d
|j                          cd d d        S c c}w # |j                          w xY w# 1 sw Y   y xY w)NrK   social_accountsz9SELECT 1 FROM sqlite_master WHERE type='table' AND name=?zrequired table not found: zPRAGMA quick_checkr   ri   zJSELECT COUNT(*) FROM social_accounts WHERE active=1 AND deleted_at IS NULLz
                        SELECT COUNT(*) FROM social_accounts
                        WHERE active=1 AND deleted_at IS NULL
                          AND username LIKE ? COLLATE NOCASE
                        )ri   
table_nametable_existsquick_checkru   total	total_allrl   )r@   r*   r   r+   boolr^   fetchonerF   r`   r_   rm   close)r0   ru   patternrb   rz   exists
quick_rowsre   r|   quick_okr~   r}   s               r1   account_table_checkz%AnalyzeRepository.account_table_check   sf   n*+]]#DLL1D#.
dllOR\Q^(* $'A*%NOO!\\*>?HHJ
6@Ajss3q6{jA&4&0`!(*Q!  !	 
 !
! hj!$ %E &E"",$*#.&-"!*#'<<#4#4	 

K ] B6 

K ]s6   EAE	E'BE	*EE		EEE'c                6    t        t        | xs d      d      S )NrK   )safe)r   r@   )values    r1   _virtual_componentz$AnalyzeRepository._virtual_component   s    S"%B//r3   c                P    t        |d      }t        |d      }g }dt        fdt        ffD ]  \  }}|D ]  }t         j                  |||      j                         }	|	j                         r|	j                         j                  dk  rWt        d||	j                        j                         }
|j                  ||	j                  |	j                  j                         ||
t        |	      ddj!                   fdt        |
      j"                  D              z   d	         |S )
Nr#   postIMAGEVIDEOr   z	/_StDown/rN   c              3  @   K   | ]  }j                  |        y wN)r   ).0partr0   s     r1   	<genexpr>z:AnalyzeRepository._standard_media_files.<locals>.<genexpr>   s!      :Bd$//5Bds   )
asset_kind	file_name	extensionfolder_namerL   absolute_pathvirtual_url)r   r   r   r   r&   r%   is_filestatst_sizer   rm   as_posixappendsuffixlowerr@   joinrT   )r0   account_name	shortcodeaccountcodefilesr   
extensionsr   rA   rL   s   `          r1   _standard_media_filesz'AnalyzeRepository._standard_media_files   s   &|[A#Iv6&((/1A'BWN^D_&`"J
'	1$,,yYaac||~)<)<)A -k7DII N W W Y",!%!%!2!2!4#*%2%(Y#. :BOP]B^BdBd: 2 $
 
 ( 'a" r3   c                   t        t        |xs d      j                  dd      d         j                  dd      }|j	                  d      j                  d      D cg c]  }|s|	 }}t        |      dk7  s|d   dk7  s|d   j                         d	k7  rt        d
      |d   |d   }}|t        |d      k7  s|st        d      t        |      }|j                  |k7  s|j                  st        d      |j                  t        |j                  d      k7  rt        d      |j                  j                         t        t              t        t              z  vrt        d      | j                   |z  |z  j#                         }| j%                  || j                         st        d      |j'                         st)        t        |            |S c c}w )NrK   ?r
   r   rM   rN      _StDownr#   zinvalid Instagram virtual path      zinvalid Instagram account pathz invalid Instagram media filenamez$invalid Instagram shortcode filenamez%unsupported Instagram media extensionz)Instagram media path escaped _StDown root)r   r@   splitrR   rQ   lenr   rF   r   r   rm   stemr   setr   r   r-   r%   rH   r   FileNotFoundError)	r0   virtual_pathdecodedr   	raw_partsr   filename	file_pathr[   s	            r1   resolve_stdown_virtual_pathz-AnalyzeRepository.resolve_stdown_virtual_path   s   #l0b177Q?BCKKDRUV&-mmC&8&>&>s&CL&CdtT&C	Ly>Q)A,)";y|?Q?Q?SWb?b=>>%aL)A,*7B77w=>>N	>>X%Y^^?@@>>1).."EECDD!!#3/?+@3GWCX+XXDEE%%/(:CCE##FD,?,?@HII~~#CK00% Ms   G&Gc                    | j                  |      }| j                  |       dd|j                  j                  |j                  t	        |      t	        |      dS )NTr#   )openedr;   r   r   r   r   )r   r/   r?   rm   r@   )r0   r   rA   s      r1   open_local_media_folderz)AnalyzeRepository.open_local_media_folder   sS    //=D!#;;++ Y|,
 	
r3   views)rr   rs   sort_byc          	        | j                   5  t        | j                        }	 |j                  dt	        |      f      j                         }|j                          |st        d|       t        |d   xs d      }t        | j                  ||||d      }|j                  d      xs g D ]  }	dD ]  }
|	j                  |
d         | j                  ||	j                  d	            }||	d
<   ||	d<   t	        t        d |D                    |	d<   t	        t        d |D                    |	d<    |cd d d        S # |j                          w xY w# 1 sw Y   y xY w)NzFSELECT username FROM social_accounts WHERE id=? AND deleted_at IS NULLzaccount_id not found: usernamerK   F)
account_idrr   rs   r   include_media_assetsitems)media_assetsr   r   rL   has_jpghas_mp4r   r   media_filesc              3  ,   K   | ]  }|d    dk(    yw)r   r   N r   files     r1   r   z2AnalyzeRepository.account_posts.<locals>.<genexpr>       +bVadD,>',IVa   	has_imagec              3  ,   K   | ]  }|d    dk(    yw)r   r   Nr   r   s     r1   r   z2AnalyzeRepository.account_posts.<locals>.<genexpr>  r   r   	has_video)r*   r   r+   r^   r_   r   r   rF   r@   r   rP   popr   any)r0   r   rr   rs   r   rb   r   r   resultitem
legacy_keyr   s               r1   account_postszAnalyzeRepository.account_posts   sY   ]]#DLL1D,,\_& (* 
 

 #9*!FGG7:.4"5H'%#%*F 

7+1r1#J HHZ.# #88488KCXY'/^$&1]#$'+bVa+b(b$c[!$'+bVa+b(b$c[! 2 = ] 

 ]s#   E*E C(E EEEc                D   | j                   5  t        | j                  |d      }|s
	 d d d        y |j                  dd        t	        |j                  d      xs d      }||d<   | j                  ||j                  d            |d<   |cd d d        S # 1 sw Y   y xY w)	NF)r   r   r   rK   r   r   r   )r*   r   r+   r   r@   rP   r   )r0   rc   r   r   s       r1   r   zAnalyzeRepository.post	  s    ]]"4<<uUD ] HH^T*488J/526H#+D "&"<"<XtxxP[G\"]D ]]s   BABB   limitc               v    | j                   5  t        | j                  ||      cd d d        S # 1 sw Y   y xY w)Nr   )r*   r   r+   )r0   rc   r   s      r1   
post_statszAnalyzeRepository.post_stats  s#    ]]!$,,uE ]]s   /8c                *   | j                   5  t        | j                  fi dt        |j	                  d      xs |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs |j	                  d      xs d      d	t        |j	                  d	      xs d      d
t        |j	                  d
      xs d      d|j	                  d      dt        |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs |j	                  d      xs d      dt        |j	                  d      xs d      dt        |j	                  d      xs |j	                  d      xs d      dt        |j	                  d      xs |j	                  d      xs d      dt        |j	                  d      xs |j	                  d      xs d      d|j	                  d      xs$ |j	                  d      xs |j	                  d      cd d d        S # 1 sw Y   y xY w) Nr   r   rK   platform_account_iddisplay_nameprofile_urlr   r   post_urlcaptionpublished_atthumbnail_url	video_urlr   
sort_field
sort_valuer   source_kindLOCALr   
play_countviews_availablelikes
like_countcommentscomment_countrepostsmedia_repost_countobserved_atcollected_atcaptured_at)r*   r   r+   r@   rP   r_   )r0   payloads     r1   save_observationz"AnalyzeRepository.save_observation  s   ]]%W[[4TI8NTRTU %(4I(J(Pb$Q !^!<!BC	
  M : @bA gkk+6S'++f:MSQST W[[4:; GKK	28b9 %[[8 "'++o">"D"E gkk+6<"= GKK	2Ugkk,6OUSUV w{{<8=A>  M : EgF '++g.P'++l2KPqQ  !$GKK0A$B$Ga H!" '++g.P'++l2KPqQ#$ W[[4YO8TYXYZ%& GKK	2\gkkBV6W\[\]'( $KK6s'++n:UsY`YdYderYs) ]]s   K2L		Lc                   t        |t              r|j                  d      ng }t        |t              st	        d      t        |      dkD  rt	        d      | j                  5  g }g }g }t        |      D ]p  \  }}t        |t              s|j                  |dd       +	 | j                  |      }|j                  d      r|j                  |       n|j                  |       r | t        |      t        |      t        |      |||dcd d d        S # t        $ rW}	|j                  |t        |j                  d      xs |j                  d	      xs d
      t        |	      d       Y d }	~	d }	~	ww xY w# 1 sw Y   y xY w)Nr   items must be an arrayi  zitems limit is 500zitem must be an object)indexerrorskipped_unchangedr   r   rK   )r   r   r   )ri   saved_countskipped_countfailed_countr   skipped_itemsfailures)
isinstancera   rP   listrF   r   r*   	enumerater   r   	Exceptionr@   )
r0   r   r   savedskippedfailedr   r   r   excs
             r1   save_observationsz#AnalyzeRepository.save_observations1  sr   (27D(AG$r%&566u:122]]EGF(/t!$-MME<T"UVJ!2248Fzz"56v.V,  0 !j"5z!$W #F!("! ] ! JMMEDHH[DYDs]a]e]efl]mDsqs@t  @C  DG  @H  #I  J  JJ ]s8   $=E;"AD''E;	E8!AE3.E;3E88E;;Fc                    | j                   5  t        | j                        }ddi|| j                  j                  t        | j                        dcd d d        S # 1 sw Y   y xY w)Nri   T)active_filenameactive_path)r*   r   r&   r+   rm   r@   )r0   infos     r1   database_filesz AnalyzeRepository.database_filesQ  sL    ]]&t||4D$o$o4<<;L;L]`aeamam]no ]]s   AAA'c                p   | j                   t        d      t        |t              rt	        |j                  d      xs d      nd}| j                  5  t        | j                  |      }t        |d         j                         | _        ddd|| j                         cd d d        S # 1 sw Y   y xY w)N8runtime database switching is disabled when --db is usedr   rK   r+   Tr9   ri   action)r'   rF   r  ra   r@   rP   r*   r   r&   r   r%   r+   collection_accountsr0   r   r   r   s       r1   open_databasezAnalyzeRepository.open_databaseV  s    !!-WXX9CGT9R3w{{:.4"5XZ]]'h?Fy 12::<DL&YFYd>V>V>XY ]]   AB,,B5c                p   | j                   t        d      t        |t              rt	        |j                  d      xs d      nd}| j                  5  t        | j                  |      }t        |d         j                         | _        ddd|| j                         cd d d        S # 1 sw Y   y xY w)Nr  r   rK   r+   Tnewr  )r'   rF   r  ra   r@   rP   r*   r   r&   r   r%   r+   r  r  s       r1   new_databasezAnalyzeRepository.new_database_  s    !!-WXX9CGT9R3w{{:.4"5XZ]])$,,AFy 12::<DL%X6XT=U=U=WX ]]r  c                   | j                   t        d      t        |t              rt	        |j                  d      xs d      nd}| j                  5  t        | j                  | j                  |      }t        |d         j                         | _	        ddd|| j                         cd d d        S # 1 sw Y   y xY w)Nr  r   rK   r+   Tsave_asr  )r'   rF   r  ra   r@   rP   r*   r   r&   r+   r   r%   r  r  s       r1   r   z"AnalyzeRepository.save_database_ash  s    !!-WXX9CGT9R3w{{:.4"5XZ]]%dllDLL(KFy 12::<DL)\v\AYAYA[\ ]]s   AB77C c                    | j                   5  t        | j                  d      }d|t        |      | j                  j                  t        | j                        dcd d d        S # 1 sw Y   y xY w)NT)rt   )ri   r   r}   rl   r+   )r*   r   r+   r   rm   r@   )r0   r   s     r1   r  z%AnalyzeRepository.collection_accountsq  s^    ]],T\\4PEUTXT`T`TeTeruvz  wC  wC  sD  E ]]s   AA&&A/c                R   t        |t              r|j                  d      ng }t        |t              st	        d      | j
                  5  t        | j                  |      }ddi|| j                  j                  t        | j                        dcd d d        S # 1 sw Y   y xY w)Nr   r   ri   T)rl   r+   )
r  ra   rP   r  rF   r*   r   r+   rm   r@   )r0   r   r   r   s       r1   r   z-AnalyzeRepository.replace_collection_accountsv  s}    (27D(AG$r%&566]]0uEF$i&i9J9JWZ[_[g[gWhi ]]s   ABB&c                r    | j                   5  t        | j                  |      cd d d        S # 1 sw Y   y xY wr   )r*   r   r+   )r0   r   s     r1   delete_accountz AnalyzeRepository.delete_account~  s!    ]]&t||Z@ ]]s   -6c                   g }g }| j                   5  t        | j                        }d}	 |j                  d       |j                  dt	        |      f      j                         }|st        d|       | j                  ||      }i }|D ]  }	| j                  |	      }
t	        |j                  dt	        |      |	j                  d      |	j                  d      f      j                         d         }|rt        d	|
j                         |	||
<    | j                  |d
   |d         D ].  }|j                  t        |d         j                         i        0 |D ]  }
|
j                         s|j!                  |
j                         /|
j#                         st        d|
       |
j%                  d|
j                   dt'        j(                         j*                         }|
j-                  |       |j!                  |
|f        |j                  dt	        |      f       |j                  dt	        |      f       |j                  dt	        |      f      j.                  }|dk7  rt1        d|       |j3                          d}	 |j;                          	 d d d        g }|D ]  \  }}	 |j=                           |rt1        ddj?                  |      z         t	        |      tA        d         dtC        |      |dS # t4        $ rZ |sV|j7                          t9        |      D ]8  \  }}|j                         s|j                         r(|j-                  |       :  w xY w# |j;                          w xY w# 1 sw Y   xY w# t4        $ r+}|j!                  |j                   d|        Y d }~d }~ww xY w)NFzBEGIN IMMEDIATEz
                    SELECT p.id, p.shortcode, a.username
                    FROM posts p
                    JOIN social_accounts a ON a.id=p.account_id
                    WHERE p.id=? AND p.deleted_at IS NULL
                    zpost_id not found: z
                        SELECT COUNT(*) FROM media_assets
                        WHERE post_id<>? AND local_status='AVAILABLE'
                          AND storage_root_id IS ? AND relative_path=?
                        storage_root_idrL   r   z!shared media reference detected: r   r   r   zmedia path is not a file: .z.analyze8780-delete-zJDELETE FROM deletion_events WHERE entity_type='POST' AND entity_local_id=?zEDELETE FROM sync_queue WHERE entity_type='POST' AND entity_local_id=?zDELETE FROM posts WHERE id=?r
   zpost delete failed: Tz: z3post DB delete completed but media cleanup failed: z; )rc   r   deleteddeleted_file_countmissing_files)"r*   r   r+   r^   r_   r   rF   rf   r\   rP   rm   r   
setdefaultr   r%   r   r   r   	with_nameuuiduuid4hexrR   rowcountRuntimeErrorcommitr  rollbackreversedr   unlinkr   r@   r   )r0   rc   stagedr%  rb   	committedr   assetsunique_pathsrW   rA   shared
media_filestaged_pathr#  originalcleanup_failures_r  s                      r1   delete_postzAnalyzeRepository.delete_post  s   *,#%]]#DLL1DI6./|| \O (*  $':7)%DEE..tW=;=#E33E:D 
 Wuyy1B'CUYYE_`" hj"$ %F (+LTYYK)XYY).L& $ #'"<"<T*=MtT_O`"aJ ++DO1L,M,U,U,WY[\ #b(D;;=%,,TYY7 <<>(+EdV)LMM"&..1TYYK?STXT^T^T`TdTdSe1f"gKLL-MM4"56 ) ilopwlxkz{dgjkrgsfuv,,'EGW``a<&)=gY'GHH 	 

s t ')$NA{F""$ %
 TW[W`W`aqWrrss7|T+./"%f+*
 	
#   MMO19&1A-+&--/8I'//9 2B  

s ]|  F '';+;+;*<Bse(DEEFsS   NI*LN9N<M3M3M33M66NNN	O  OOc                p    | j                   5  t        | j                        cd d d        S # 1 sw Y   y xY wr   )r*   r   r+   rn   s    r1   deleted_accountsz"AnalyzeRepository.deleted_accounts  s    ]](6 ]]s   ,5r   )r&   z
str | Pathr+   zstr | Path | NonereturnNone)rA   r   r>  r?  )rA   r   rG   r   r>  r   )rW   dict[str, Any]r>  r   )rb   r   rc   r_   r>  list[dict[str, Any]])r>  r@  )
rr   r_   rs   r_   rt   r   ru   r@   r>  r@  )rK   )ru   r@   r>  r@  )r   objectr>  r@   )r   rB  r   rB  r>  rA  )r   rB  r>  r   )r   rB  r>  r@  )
r   r_   rr   r_   rs   r_   r   r@   r>  r@  )rc   r_   r>  zdict[str, Any] | None)rc   r_   r   r_   r>  rA  )r   r@  r>  r@  )r   r_   r>  r@  )rc   r_   r>  r@  )r>  rA  )__name__
__module____qualname__r2   staticmethodr.   rH   classmethodr\   rf   ro   rw   r   r   r   r   r   r   r   r   r   r	  r  r  r  r   r  r   r  r;  r=  r   r3   r1   r!   r!   )   s   8 
X 
X    +  %   	
   
"'R 0 0.,

 =>PRcj B	 8; F2@p
ZY]E
jAK
Z7r3   r!   )-
__future__r   r<   r:   r(   r(  pathlibr   r   urllib.parser   r   typingr   r	   __file__r%   parentsST_ROOTr@   rA   insertShared.storage.sort_storager   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   r   r3   r1   <module>rQ     s    "  
   ' '  
x.
 
 
"
*
*1
-w<sxxHHOOAs7|$     2h7 h7r3   