
    uj=                   X   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	Z	d dl
m
Z
mZ d dlmZmZ d dlmZmZ dZ ee      j)                  d       ee      j)                  d       ee      j)                  d	       ee      j)                  d
       ee      j)                  d       ee      j)                  d       ee      j)                  d      fZdZ ed      dz  ez  Z ed      dz  dz  Z ej2                  d      ZdZ eh d      ZdZdZdddZ dedfdZ!dgdZ"	 	 	 	 	 	 	 	 	 	 dhdZ#didZ$dd	 	 	 	 	 	 	 	 	 djdZ%dddZ&ddd Z'dgd!Z(dkd"Z)dld#Z*ddd$Z+dmd%Z,dnd&Z-dnd'Z.dod(Z/dpd)Z0dqd*Z1drd+Z2dsd,Z3d-d.	 	 	 	 	 	 	 dtd/Z4dud0Z5d1d2dvd3Z6dwd4Z7ddd5dd dd6	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dxd7Z8d ddd5d5d8	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dyd9Z9d5d dd5d5d5dddddd:	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dzd;Z:dd<d=	 	 	 	 	 	 	 	 	 d{d>Z;d|d?Z<d5d<d@	 	 	 	 	 	 	 	 	 d}dAZ=d5d5d5d5ddd5dB	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d~dCZ>dd5dd ddD	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddEZ?d dd5d5dF	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddGZ@dd dd5d5d5d5d5dd5d5d d5d<d5d d5dd5dddH	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddIZAddJZBdddKZCdddLZDd d d d d dd5d5d5d5d5dd5d5d5d dMdN	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddPZEdQdRd<d5dS	 	 	 	 	 	 	 	 	 	 	 ddTZFdQdRdOd-dU	 	 	 	 	 	 	 	 	 	 	 	 	 ddVZGd-dW	 	 	 	 	 	 	 ddXZHdddYZI eh dZ      ZJdgd[ZKd-d\dd]ZLdd^ZMddd_ZNddd`ZOddaZPddbZQeRdck(  r eS eQ             y)    )annotationsN)datetimetimezone)PathPurePosixPath)AnyMapping   zschema_sqlite_v1.sqlzschema_sqlite_v2.sqlzschema_sqlite_v3.sqlzschema_sqlite_v4.sqlzschema_sqlite_v5.sqlzschema_sqlite_v6.sqlzschema_sqlite_v7.sqlzsort_local.sqlite3Shareddatazsort_database_selection.jsonu   ^[0-9A-Za-z가-힣._-]+$STDOWN_INSTAGRAM>   BULK_ALL
TOP_SORTEDAUTO_SEEN_JPGBULK_FILTEREDCACHE8701_CDPMANUAL_SINGLETRANSCRIPT_REQUEST)z.jpgz.jpegz.pngz.webpz.avifz.gif)z.mp4c                    t        |       j                         j                         }|j                  dk7  rt	        d|       |j
                  dz  S )zEReturn the fixed sibling _StDown directory for the supplied _St root._Stz)st_root must point to the _St directory: _StDown)r   
expanduserresolvename
ValueErrorparentst_rootroots     %D:\_St\Shared\storage\sort_storage.pyderive_stdown_rootr!   -   sK    =##%--/DyyEDTFKLL;;""    c                    t        j                  ddt        | xs d      j                               j                  d      }|d d xs |S )Nz[^0-9A-Za-z._-]+_ z._x   )resubstrstrip)valuefallbacktexts      r    safe_media_componentr.   7   sC    66%sC,<,B,B,DEKKDQD:!!r"   c                    t        | xs d      j                         j                         }|r|j                  d      sd|z   }t	        t
              t	        t              z  }||vrt        d|       |S )Nr%   .zunsupported media extension: )r)   r*   lower
startswithsetIMAGE_EXTENSIONSVIDEO_EXTENSIONSr   )r+   	extensionalloweds      r    normalize_media_extensionr8   <   sr    EKR &&(..0I--c2)O	"#c*:&;;G8	BCCr"   c                x    t        |d      }t        |d      }t        |      }t        |       dz  |z  | | z  S )N	instagrampost)r.   r8   r!   )r   account_name	shortcoder6   accountcodeexts          r    build_instagram_media_pathrA   F   sH     #<=G	62D
#I
.Cg&4w>D6#OOr"   c                   t        |d      }t        |       dz  }||z  }|j                  dd       || dz  || dz  || dz  |dz  g}|j                  |j	                  d             |D ]#  }	 |j                         r|j                          % dt        j                  j                  |       }d	| d
| d| dt        j                  |d       d| d| d}|dz  }	|	j                         r|	j                  dd      |k7  r5|	j                  d      }
|
j                  |d       |
j!                  |	       |	S # t        $ r Y w xY w)zLCreate one minimal account index that opens the account view in Analyze8780.r:   Tparentsexist_okz.jsonz.htmlzecharts.min.jsz*.md5zhttp://127.0.0.1:8780/?account=z<!-- D:/_StDown/instagram/zq/index.htm | Analyze8780 account redirect -->
<!doctype html>
<html lang="ko"><head><meta charset="utf-8"><title>uA    · Analyze8780</title><meta http-equiv="refresh" content="0;url=z("></head><body><script>location.replace(Fensure_asciiz);</script><a href="z">u&    Analyze8780 열기</a></body></html>
z	index.htmutf-8replace)encodingerrorsz.htm.tmprJ   )r.   r!   mkdirextendglobis_fileunlinkOSErrorurllibparsequotejsondumps	read_textwith_suffix
write_textrI   )r   r<   r>   instagram_rootfolderretiredlegacy_pathurlhtmlpathtemps              r    ensure_instagram_account_indexrc   R   s   "<=G'0;>Ng%F
LLL- 	G9E**G9E**G9E""!!	G NN6;;w'(	""$""$  ,FLL,>,>w,G+H
IC
$WI .  88;u =$$(JJs$G#H IEWI &	 	 KD<<>T^^WY^OSWW
+w/TK'  		s   4 E	EEIMAGE)
asset_kindc                  t        |d      }t        |d      }t        |       dz  |z  }|j                         sy t        |xs d      j	                         j                         }|dv rt        D cg c]  }| | 
 }	}nt        D cg c]  }| | 
 }	}|	D ]9  }
||
z  }|j                         s|j                         j                  dkD  s7|c S  y c c}w c c}w )Nr:   r;   rd   >   MP4VIDEOr   )r.   r!   is_dirr)   r*   upperr5   r4   rP   statst_size)r   r<   r=   re   r>   r?   r\   kindr@   namesr   	candidates               r    find_instagram_media_filerp   {   s     #<=G	62D(;6@F==?z$W%++-335D+;<+;CD6#+;<+;<+;CD6#+;<TM	9>>#3#;#;a#?   =<s   2C
Cc                \    t        |       j                         j                         dz  dz  S )Nr   r   )r   r   r   r   s    r    database_directoryrs      s(    =##%--/(:VCCr"   c                ^    t        |       j                         j                         t        z  S N)r   r   r   DATABASE_SELECTION_RELATIVErr   s    r    database_selection_pathrw      s$    =##%--/2MMMr"   c                |   t        | xs d      j                         }|st        d      d|v sd|v st        |      j                  |k7  rt        d      |}t
        j                  |      st        d      |j                         j                  d      s|dz  }|dv s|j                  d	      rt        d
      |S )Nr%   zdatabase filename required/\z)database filename must not contain a pathz1database filename contains unsupported charactersz.sqlite3>   r0   ..r0   zdatabase filename is invalid)
r)   r*   r   r   r   _DATABASE_FILENAME_RE	fullmatchr1   endswithr2   )r+   rawr   s      r    normalize_database_filenamer      s    
ekr

 
 
"C566
czTS[DINNc$9DEED **40LMM::<  ,
{dooc2788Kr"   c                    t        |       }	 t        j                  |j                  d            }t	        |j                  d      xs t              S # t        $ r	 t        cY S t        $ r	 t        cY S w xY w)NrH   rL   filename)	rw   rV   loadsrX   r   getDEFAULT_DB_FILENAMEFileNotFoundError	Exception)r   ra   payloads      r    read_database_selectionr      sg    "7+D#**T^^W^=>*7;;z+B+YFYZZ #"" #""#s   AA A6%A65A6c                   t        |       j                         j                         }t        |      }t	        |      }|j
                  j                  dd       |j                  |j                  dz         }|j                  t        j                  d|idd      dz   d	
       |j                  |       t        |      |z  S )NTrC   z.tmpr   F   rG   indent
rH   rL   )r   r   r   r   rw   r   rM   rY   suffixrZ   rV   rW   rI   rs   )r   r   r   r   ra   rb   s         r    write_database_selectionr      s    =##%--/D&x0D"4(DKKdT2DKK&01DOODJJ
D1aPSWWbiOjLLd#d**r"   c                ~    t        |       j                         j                         }t        |      t	        |      z  S ru   )r   r   r   rs   r   r   s     r    default_database_pathr      s3    =##%--/Dd#&=d&CCCr"   c                f   t        |       j                         j                         }t        |      }|j	                  dd       t        |      }t        d |j                  d      D        t        j                        }t        |vr	|st        g}|t        ||z  j                               |dS )NTrC   c              3  V   K   | ]!  }|j                         s|j                   # y wru   )rP   r   ).0ra   s     r    	<genexpr>z&list_database_files.<locals>.<genexpr>   s     X*E$DII*Es   ))z	*.sqlite3)key)active_filenameactive_pathfiles)r   r   r   rs   rM   r   sortedrO   r)   casefoldr   )r   r   	directoryactiver   s        r    list_database_filesr      s    =##%--/D"4(IOOD4O0$T*FX)..*EX^a^j^jkE%'$%%c9v;M:V:V:X6Ydijjr"   c                @   t        |       j                         j                         }t        |      }t	        |      |z  }|j                         st        d|       t        ||       t        ||       i t        |      t        |j                               |dS )Nzdatabase file not found: db_pathr   )r   r   r   r   rs   rP   r   initialize_databaser   r   r)   r   r   r   r   targets        r    open_database_filer      s    =##%--/D&x0D%,F>>4TF;<<%T4(\!$'\C8H4IW[\\r"   c                @   t        |       j                         j                         }t        |      }t	        |      |z  }|j                         rt        d|       t        ||       t        ||       i t        |      t        |j                               |dS )Ndatabase file already exists: r   )r   r   r   r   rs   existsr   r   r   r   r)   r   s        r    create_database_filer      s    =##%--/D&x0D%,F}}9$@AA%T4(\!$'\C8H4IW[\\r"   c                H   t        |       j                         j                         }t        |      }t        |      j                         j                         }t	        |      |z  }|j                         rt        d|       t        ||       |j                  j                  dd       t        |      }t        j                  |d      }	 |j                  |       |j                          |j                          |j                          t        ||       t%        ||       i t'        |      t)        |j                               |dS # t         $ rD |j                          |j                          	 |j#                  d        # t         $ r Y  w xY ww xY w)Nr   TrC         $@timeout)
missing_okr   )r   r   r   r   rs   r   r   r   r   rM   connect_databasesqlite3connectbackupcommitcloser   rQ   r   r   r)   )	r   source_db_pathr   r   r   sourcer   srcdsts	            r    save_database_asr      sa   =##%--/D&x0D.!,,.668F%,F}}9$@AA%
MMt4
6
"C
//&$
/C

3

 					%T4(\!$'\C8H4IW[\\  					MMTM* 	  		s0   !E )F!>FF!	FF!FF!c                n   t        |       j                         j                         }|j                  j	                  dd       t        j                  |d      }t
        j                  |_        |j                  d       |j                  d       |j                  d       |j                  d       |S )	NTrC   r   r   zPRAGMA foreign_keys = ONzPRAGMA busy_timeout = 10000zPRAGMA journal_mode = WALzPRAGMA synchronous = NORMAL)
r   r   r   r   rM   r   r   Rowrow_factoryexecute)r   ra   conns      r    r   r     s    =##%--/DKKdT2??4.D{{DLL+,LL./LL,-LL./Kr"   c                j    | j                  d| d      D ch c]  }t        |d          c}S c c}w )NzPRAGMA table_info()r   )r   r)   )r   
table_namerows      r    _table_columnsr     s9    (,7I*UV5W(XY(XCF(XYYYs   0c                V    |t        | |      vr| j                  d| d| d|        y y )NzALTER TABLE z ADD COLUMN  )r   r   )r   r   column_name
definitions       r    _ensure_columnr     s5    .z::|J<|K=*VW ;r"   c                r   t         D ]#  }| j                  |j                  d             % t        | ddd       t        | ddd       t        | ddd	       t        | d
dd	       dD ]:  }t        | |dd	       t        | |dd       t        | |dd       t        | |dd       < d}| j	                  d|       y )NrH   rL   social_accounts
deleted_atTEXTpostsmedia_assetsfolder_namezTEXT NOT NULL DEFAULT ''media_saved_events)post_stat_latestpost_stat_historypost_stat_10msort_by
sort_valuezINTEGER NOT NULL DEFAULT 0source_kindzTEXT NOT NULL DEFAULT 'LOCAL'views_available))   initial_storage_foundation)r   unified_media_saved_flow)   $analyze8780_repository_and_10m_stats)   &collection_account_queue_sqlite_source)   ,original_filename_and_account_folder_display)   -observation_sort_mode_and_hourly_central_sync)r
   +views_availability_and_central_hour_historyzDINSERT OR IGNORE INTO schema_migrations(version, name) VALUES (?, ?))SCHEMA_FILESexecutescriptrX   r   executemany)r   schema_filer   
migrationss       r    _apply_schemar     s    #;00'0BC $4*L&A4,748RS4-}>XYP
tZ4NOtZ7STtZ8WXtZ):<XY	 Q
J 	Nr"   Tcreate_storage_dirsc               ^   t        |      }|dz  }|r|j                  dd       t        |       }	 t        |       |j	                  dt
        t        |      f       |j	                  d       |j	                  d       |j                          |j	                  d      j                         d   }|j	                  d	      j                         d   }|j	                  d
      j                         d   }|j	                  d      j                         d   }	t        t        |       j                         j                               t        |      t        |	      t        |      t        |      j                         t        |      d|j                          S # |j                          w xY w)Nr:   TrC   a"  
            INSERT INTO storage_roots(root_code, root_path, is_default)
            VALUES (?, ?, 1)
            ON CONFLICT(root_code) DO UPDATE SET
                root_path = excluded.root_path,
                is_default = 1,
                updated_at = CURRENT_TIMESTAMP
            z6INSERT OR IGNORE INTO collector_profile(id) VALUES (1)z3INSERT OR IGNORE INTO device_profile(id) VALUES (1)zTSELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'r   zPRAGMA journal_modezPRAGMA foreign_keyszPRAGMA user_version)r   storage_rootschema_versiontable_countjournal_modeforeign_keys)r!   rM   r   r   r   DEFAULT_STORAGE_CODEr)   r   fetchoner   r   r   intr1   r   )
r   r   r   stdown_rootr[   r   r   r   r   user_versions
             r    r   r   5  sk    %W-K ;.NTD9G$D d "3~#67
	
 	MNJKllb

(*Q ||$9:CCEaH||$9:CCEaH||$9:CCEaH4=335==?@/!,/{+-335-
 	



s   EF F,c                    t        | xs d      j                         j                         }|t        vr/dj	                  t        t                    }t        d| d|       |S )Nr%   z, zunsupported source_mode=z
; allowed=)r)   r*   rj   SOURCE_MODESjoinr   r   )source_mode
normalizedr7   s      r    normalize_source_moder   d  s]    [&B'--/557J%))F<013K?*WIVWWr"   pfallback_kindc                  t        | xs d      j                         }|syt        j                  j	                  |d      }ddddd}|D ]2  }t        |xs d      j                         }|s$|j                  d      rd	|z   }	 t        j                  j                  |      }t        |j                  xs d      j                         }	|	d
k7  r|	j                  d      st        |j                  xs d      j                  d      D 
cg c]$  }
|
st        j                  j                  |
      & }}
t        |      dk  r|j                  |d   j                               }|r|d   |k7  r*d| d| dc S  |j                  t        |xs d      j                         j                         d      }d| d| dS # t        $ r Y w xY wc c}
w )zGReturn a real Instagram post permalink, never a feed/profile scope URL.r%   z-_)safer   reeltv)r   r  reelsr  ry   zhttps://www.instagram.cominstagram.comz.instagram.comr   r   r   https://www.instagram.com/)r)   r*   rS   rT   rU   r2   urlparser   hostnamer1   r~   ra   splitunquotelenr   )r=   r   candidate_urlsr?   canonical_codekind_mapro   r   parsedhostpartpartsrm   r,   s                 r    canonical_instagram_post_urlr  l  s   yB%%'D\\''4'8N&6FH#	)/r"((*>>#-3C	\\**3/F 6??(b)//1?"4==9I+J8;FKK<M28N8T8TUX8Yb8Y]a%%d+8Ybu:>||E!HNN,-uQx4'+D6>2B!DD' $( ||C 45;;=CCEsKH'z>2B!DD  		
 cs   GG!G	GGc                   t        | xs d      j                  dd      j                         }|st        d      t	        |      }|j                         sd|j                  v rt        d|       |j                         S )Nr%   rz   ry   zrelative_path is requiredr{   z;relative_path must stay below the configured storage root: )r)   rI   r*   r   r   is_absoluter  as_posix)relative_pathr   ra   s      r    normalize_relative_pathr    sx    
m!r
"
*
*4
5
;
;
=C455DTTZZ/VWZV[\]]==?r"   r%   )	batch_key
account_idr   filter_daysrequested_countmetadatac                  t        |      }t        |xs t        j                               }	t	        |       }
	 |
j                  d|	||t        |xs d      |t        dt        |            t        j                  t        |xs i       dd      f      }|
j                          t        |j                        |
j                          S # |
j                          w xY w)Nz
            INSERT INTO download_batches(
                batch_key, source_mode, account_id, sort_by, filter_days,
                requested_count, metadata_json
            ) VALUES (?, ?, ?, ?, ?, ?, ?)
            r%   r   FTrG   	sort_keys)r   r)   uuiduuid4r   r   maxr   rV   rW   dictr   	lastrowidr   )r   r   r  r  r   r  r  r  moder   r   cursors               r    create_download_batchr)    s     !-D
i'4::<
(CG$D GMr"As?+,

4B/etT
" 	6##$



s   B C
 
C)media_indexbatch_idrank_no
source_urlexpected_file_namec                  t        |      }	t        |xs d      j                         j                         }
|
st	        d      t        |       }	 |j                  d|t        |      |	|
t        dt        |            |t        |xs d      t        |xs d      f      }|j                          t        |j                        |j                          S # |j                          w xY w)Nr%   asset_kind is requiredz
            INSERT INTO download_jobs(
                batch_id, post_id, source_mode, asset_kind, media_index,
                rank_no, source_url, expected_file_name
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            r   )r   r)   r*   rj   r   r   r   r   r$  r   r&  r   )r   post_idr   re   r*  r+  r,  r-  r.  r'  rm   r   r(  s                r    create_download_jobr2    s     !-DzR &&(..0D122G$D GAs;'(J$"%&,"-	
$ 	6##$



s   A4C C')r   r*  r,  md5sha256r-  storage_root_iddownload_job_id
event_uuidcompleted_atr   c                  t        |      }t        |xs d      j                         j                         }|st	        d      t        |      }t        |xs d      j                         }|st	        d      t        |      j                  }t        |      dv rdn|j                  }t        |xs |xs d      j                         }t        dt        |            }t        dt        |            }t        |xs t        j                               }|xs d}t        |       }	 |j                  d       |j                  d	|f      j                         }|r@|j!                          t        |d
         t        |d         ||dd|j#                          S d}||j                  dt        |      f      j                         }|st	        d|       t        |      |||f} t        |d         t        |d         t        |d         t        |d         f}!|!| k7  rt	        d| d|!      |j                  dt        |      f      j                         }"|"st	        d|       |1|j                  d      j                         }#|#rt        |#d
         nd}|j                  dt        |      ||t        |xs d      |||||t        |
xs d      t        |xs d      |f       |j                  dt        |      ||f      j                         }$t        |$d
         }%t%        |xs i       }&|j                  d||t        |      |%|"d   t        |"d         ||||	||||t        |
xs d      t        |xs d      |t'        j(                  |&dd      f      }'t        |'j*                        }(||j                  d |t        |      f       |r|d!   nd})|)|j                  d"t        |)      f      j                         }*|*rt        |*d#   xs d      nd}+|*rt        |*d$   xs d      nd},|*rt        |*d%   xs d      nd}-|-dk(  r(|+dk  s|,|+k\  r|j                  d&|t        |)      f       n|j                  d't        |)      f       |j                  d(t        |      f       |j                  d)|%f       |t        |      t        |"d         ||||	||t        |
xs d      t        |xs d      |d*}.|j                  d+|(t'        j(                  |.dd      f       |j!                          |(|%||||dd,|j#                          S # t,        $ r |j/                           w xY w# |j#                          w xY w)-zRecord the common MEDIA_SAVED result for every download entry path.

    The server sync payload intentionally excludes the local relative path. The
    local event retains only a path relative to the configured storage root.
    r%   r0  zfile_name is required)r%   r0   r:   r   NBEGIN IMMEDIATEz@SELECT id, asset_id FROM media_saved_events WHERE event_uuid = ?idasset_idT)event_idr<  r7  r   
idempotentz
                SELECT id, batch_id, post_id, source_mode, asset_kind, media_index
                FROM download_jobs WHERE id = ?
                zdownload_job_id not found: r1  r   re   r*  z download job mismatch: expected=z actual=z8SELECT id, account_id, shortcode FROM posts WHERE id = ?post_id not found: zESELECT id FROM storage_roots WHERE is_default = 1 ORDER BY id LIMIT 1a0  
            INSERT INTO media_assets(
                post_id, asset_kind, media_index, source_url, storage_root_id,
                relative_path, file_name, folder_name, file_size, md5, sha256,
                local_status, verified_at
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'AVAILABLE', COALESCE(?, CURRENT_TIMESTAMP))
            ON CONFLICT(post_id, asset_kind, media_index) DO UPDATE SET
                source_url = CASE WHEN excluded.source_url <> '' THEN excluded.source_url ELSE media_assets.source_url END,
                storage_root_id = COALESCE(excluded.storage_root_id, media_assets.storage_root_id),
                relative_path = excluded.relative_path,
                file_name = excluded.file_name,
                folder_name = excluded.folder_name,
                file_size = excluded.file_size,
                md5 = excluded.md5,
                sha256 = excluded.sha256,
                local_status = 'AVAILABLE',
                verified_at = excluded.verified_at,
                updated_at = CURRENT_TIMESTAMP
            zTSELECT id FROM media_assets WHERE post_id = ? AND asset_kind = ? AND media_index = ?a  
            INSERT INTO media_saved_events(
                event_uuid, download_job_id, post_id, asset_id, account_id,
                shortcode, source_mode, asset_kind, media_index, rank_no,
                relative_path, file_name, folder_name, file_size, md5, sha256,
                completed_at, payload_json
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, CURRENT_TIMESTAMP), ?)
            r  r=   Fr   z
                UPDATE download_jobs
                SET job_status = 'COMPLETE', completed_at = COALESCE(?, CURRENT_TIMESTAMP),
                    last_error = '', updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
                r+  a  
                    SELECT b.requested_count,
                           COUNT(j.id) AS total_jobs,
                           SUM(CASE WHEN j.job_status <> 'COMPLETE' THEN 1 ELSE 0 END) AS remaining_jobs
                    FROM download_batches b
                    LEFT JOIN download_jobs j ON j.batch_id = b.id
                    WHERE b.id = ?
                    GROUP BY b.id, b.requested_count
                    r  
total_jobsremaining_jobsa+  
                        UPDATE download_batches
                        SET batch_status = 'COMPLETE',
                            completed_at = COALESCE(?, CURRENT_TIMESTAMP),
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = ?
                        z
                        UPDATE download_batches
                        SET batch_status = 'RUNNING', completed_at = NULL,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = ?
                        z]UPDATE posts SET media_state = 'MEDIA_AVAILABLE', updated_at = CURRENT_TIMESTAMP WHERE id = ?z
            INSERT INTO p2p_inventory(asset_id, available, updated_at)
            VALUES (?, 1, CURRENT_TIMESTAMP)
            ON CONFLICT(asset_id) DO UPDATE SET available = 1, updated_at = CURRENT_TIMESTAMP
            )client_event_idr1  r=   r   re   r*  r,  	file_name	file_sizer3  r4  r8  z
            INSERT INTO sync_queue(entity_type, entity_local_id, operation, payload_json)
            VALUES ('MEDIA_SAVED', ?, 'UPSERT', ?)
            )r=  r<  r7  r   r   rC  r>  )r   r)   r*   rj   r   r  r   r   r   r$  r   r"  r#  r   r   r   r   r   r%  rV   rW   r&  r   rollback)/r   r1  r   re   r  rC  r   rD  r*  r,  r3  r4  r-  r5  r6  r7  r8  r   r'  rm   safe_relative_pathsafe_file_namerelative_parentderived_folder_namesafe_folder_namesizeindex	event_keycompleted_valuer   existingjob_rowexpectedactualr;   default_rootassetr<  local_payloadevent_cursorr=  r+  batch_progress	requestedr@  	remainingserver_payloads/                                                  r    record_media_savedr[    s   4 !-DzR &&(..0D1220?b)//1N011#$67>>O #O 4	 A"G[G[;L*=LMSSUq#i.!D3{#$EJ.$**,/I"*dOG$D_&'<<NL
 (* 	 KKM/ 45'#"n 	

_ &ll _%' hj   #>>O!PQQGdD%8HGI&'GM*+GL)*GM*+	F ! 6xl(6*U  ||F\O
 (* 	 27)<=="<<Whj  :Fc,t"454O( GJ$"%" CI2FLb!)"	
F b\4'
 (* 	 uT{#W]+|| G\"D%&" CI2FLb!

=uM%
< |--.&LL !#o"67 /6wz*4H#!% ]$" (*  LZC/@ A FQG_`	GUS!=!BC[\
JXC/? @ EAF^_	>yA~y9PLL )#h-8	 LL X( 	k\O	
 	
 K	
  )7|T+./ 'syb>&,B'+
 	 tzz.uPTUV	
 	  #+'
 	

	   	

s    'A#U N-U U44U7 7V	F)	root_code
is_defaultc               z   t        |      j                         j                         }t        |xs d      j	                         }|sQt        j                  t        |      j                  d            j                         d d j                         }d| }t        |       }	 |r|j                  d       |j                  d|t        |      |rdndf       |j                  d	|f      j                         }|j                          t        |d
         |j                          S # |j                          w xY w)Nr%   rH      LOCAL_DOWNLOAD_z<UPDATE storage_roots SET is_default = 0 WHERE is_default = 1a4  
            INSERT INTO storage_roots(root_code, root_path, is_default)
            VALUES (?, ?, ?)
            ON CONFLICT(root_code) DO UPDATE SET
                root_path = excluded.root_path,
                is_default = excluded.is_default,
                updated_at = CURRENT_TIMESTAMP
            r   r   z0SELECT id FROM storage_roots WHERE root_code = ?r;  )r   r   r   r)   r*   hashlibr4  encode	hexdigestrj   r   r   r   r   r   r   )	r   	root_pathr\  r]  resolvedr?   digestr   r   s	            r    ensure_storage_rootrg    s    I))+335HyB%%'DH 4 4W =>HHJ3BOUUW )G$DLLWX 3x=z!q9
	
 llMPTwW``b3t9~



s   $A3D( (D:c                F    	 | j                  |       y# t        $ r Y yw xY w)NTF)relative_tor   )ra   r   s     r    _is_relative_torj    s*     s    	  )account_pathaccount_folder_mergec               T   t        |      j                         j                         }|j                         st	        t        |            t        |       }	 |j                  d      j                         }|j                          |rt        t        |d               j                         j                         }t        ||      rRt        |d         t        |      |j                  |      j                         |j                  j                  xs dddS |j                  }|}	t        |xs d      j!                  dd	      j#                  d	      D 
cg c]  }
|
s|
	 }}
|sU|rS|}d
}t%        |      D ]=  }|j                  j'                         |j'                         k7  rd} n|j                  }? |r|}	t)        | |	      }|t        |	      |j                  |	      j                         |j                  j                  xs dddS # |j                          w xY wc c}
w )NzPSELECT id, root_path FROM storage_roots WHERE is_default = 1 ORDER BY id LIMIT 1rd  r;  r:   STDOWN_DEFAULT)r5  storage_root_pathr  r   storage_layoutr%   rz   ry   TF)rd  LOCAL_DOWNLOAD_ROOT)r   r   r   rP   r   r)   r   r   r   r   rj  r   ri  r  r   r   rI   r
  reversedr   rg  )r   	file_pathrk  rl  filer   defaultrS  r   r   r  account_partsprobematchedrQ  root_ids                   r    resolve_download_storagerz    s    	?%%'//1D<<>D	**G$D,,^

(* 	 	

C 456AACKKM4.#&wt}#5%(%6!%!1!1,!?!H!H!J#{{//>;"2  [[FD&),*<"&=&E&EdC&P&V&VWZ&[d&[d_cT&[MdM /Hzz""$(9(9(;;LLE	 0
 D!'T:G" Y))$/88:{{''6;/ 9 	

 es   H H% H%H")post_urlcaptionthumbnail_url	video_urlpublished_atstatsr   c       	           t        |xs d      j                         }
t        |xs d      j                         j                  d      }|
st        d      |st        d      t        |	xs d      j                         j	                         }|dvr!t        |xs d      j                         rdnd}t        |
||      }t        |       }	 |j                  d	       |j                  d
|d| df       |j                  d|f      j                         }t        |d         }|j                  d||
|t        |xs d      |t        |xs d      t        |xs d      f       |j                  d|
f      j                         }t        |d         }t        |xs i       }|rt        |j                  d      xs |j                  d      xs d      j                         xs d }t        |j                  d      xs d      t        |j                  d      xs d      t        |j                  d      xs d      t        |j                  d      xs d      f}|j                  d|g||       |j                  d|g||       |j                          ||d|j                          S # t        $ r |j                           w xY w# |j                          w xY w)Nr%   @shortcode is requiredzowner_username is required>   r   r  r  r   r   r:  ai  
            INSERT INTO social_accounts(platform, username, profile_url)
            VALUES ('instagram', ?, ?)
            ON CONFLICT(platform, username) DO UPDATE SET
                profile_url = CASE WHEN excluded.profile_url <> '' THEN excluded.profile_url ELSE social_accounts.profile_url END,
                updated_at = CURRENT_TIMESTAMP
            r  ry   zLSELECT id FROM social_accounts WHERE platform = 'instagram' AND username = ?r;  a4  
            INSERT INTO posts(
                account_id, platform, shortcode, post_url, caption, published_at,
                thumbnail_url, video_url, source_url_observed_at
            ) VALUES (?, 'instagram', ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
            ON CONFLICT(platform, shortcode) DO UPDATE SET
                account_id = excluded.account_id,
                post_url = CASE WHEN excluded.post_url <> '' THEN excluded.post_url ELSE posts.post_url END,
                caption = CASE WHEN excluded.caption <> '' THEN excluded.caption ELSE posts.caption END,
                published_at = COALESCE(excluded.published_at, posts.published_at),
                thumbnail_url = CASE WHEN excluded.thumbnail_url <> '' THEN excluded.thumbnail_url ELSE posts.thumbnail_url END,
                video_url = CASE WHEN excluded.video_url <> '' THEN excluded.video_url ELSE posts.video_url END,
                source_url_observed_at = CURRENT_TIMESTAMP,
                last_observed_at = CURRENT_TIMESTAMP,
                updated_at = CURRENT_TIMESTAMP
            zCSELECT id FROM posts WHERE platform = 'instagram' AND shortcode = ?captured_atcollected_atviewsr   likescommentsrepostsa  
                INSERT INTO post_stat_latest(post_id, views, likes, comments, reposts, collected_at)
                VALUES (?, ?, ?, ?, ?, COALESCE(?, CURRENT_TIMESTAMP))
                ON CONFLICT(post_id) DO UPDATE SET
                    views = excluded.views,
                    likes = excluded.likes,
                    comments = excluded.comments,
                    reposts = excluded.reposts,
                    collected_at = excluded.collected_at
                z
                INSERT OR IGNORE INTO post_stat_history(
                    post_id, views, likes, comments, reposts, collected_at
                ) VALUES (?, ?, ?, ?, ?, COALESCE(?, CURRENT_TIMESTAMP))
                )r  r1  )r)   r*   lstripr   r1   r  r   r   r   r   r%  r   r   r   r   rE  )r   r=   owner_usernamer{  r|  r}  r~  r  r  r   r?   owner	kind_hintr_   r   r>   r  r;   r1  valuesr  metric_valuess                         r    upsert_download_postr  Q  s    yB%%'D$"%++-44S9E011566M'R(..0668I%!)/r288:F	
&tXY
OCG$DV&' 0q9:		
 ,,ZH
 (* 	 '
" GMr"M'R(IO$#	
6 ||QG
 (* 	 d4j/ekr"vzz-8\FJJ~<V\Z\]ccemimLFJJw',1-FJJw',1-FJJz*/a0FJJy).Q/	M LL	 7=7,7 LL
 7=7,7 	(W=
 	

	   	

s   GJ4 4KK K$)r  r   r  r  r  c                  t        |xs d      j                         }|st        d      t        |      }	t	        |       }
	 |
j                  d||	|t        |xs d      |t        dt        |            t        j                  t        |xs i       dd      f       |
j                  d|f      j                         }|
j                          t        |d	         |
j                          S # |
j                          w xY w)
Nr%   zbatch_key is requireda  
            INSERT INTO download_batches(
                batch_key, source_mode, account_id, sort_by, filter_days,
                requested_count, batch_status, metadata_json
            ) VALUES (?, ?, ?, ?, ?, ?, 'RUNNING', ?)
            ON CONFLICT(batch_key) DO UPDATE SET
                account_id = COALESCE(excluded.account_id, download_batches.account_id),
                sort_by = CASE WHEN excluded.sort_by <> '' THEN excluded.sort_by ELSE download_batches.sort_by END,
                filter_days = COALESCE(excluded.filter_days, download_batches.filter_days),
                requested_count = MAX(download_batches.requested_count, excluded.requested_count),
                batch_status = CASE WHEN download_batches.batch_status = 'COMPLETE' THEN 'COMPLETE' ELSE 'RUNNING' END,
                metadata_json = excluded.metadata_json,
                updated_at = CURRENT_TIMESTAMP
            r   FTr   z3SELECT id FROM download_batches WHERE batch_key = ?r;  )r)   r*   r   r   r   r   r$  r   rV   rW   r%  r   r   r   )r   r  r   r  r   r  r  r  r   r'  r   r   s               r    ensure_download_batchr    s     io2

$
$
&C011 -DG$D GMr"As?+,

4B/etT	
2 llPSVRXYbbd3t9~



s   BC- -C?)r*  r,  r-  r.  c               j   t        |      }	t        |xs d      j                         j                         }
|
st	        d      t        |       }	 |j                  dt        |      t        |      |	|
t        dt        |            |t        |xs d      t        |xs d      f       |j                  dt        |      t        |      |
t        dt        |            f      j                         }|j                          t        |d         |j                          S # |j                          w xY w)Nr%   r0  a|  
            INSERT INTO download_jobs(
                batch_id, post_id, source_mode, asset_kind, media_index,
                rank_no, source_url, expected_file_name, job_status
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'DOWNLOADING')
            ON CONFLICT(batch_id, post_id, asset_kind, media_index) DO UPDATE SET
                rank_no = COALESCE(excluded.rank_no, download_jobs.rank_no),
                source_url = CASE WHEN excluded.source_url <> '' THEN excluded.source_url ELSE download_jobs.source_url END,
                expected_file_name = CASE WHEN excluded.expected_file_name <> '' THEN excluded.expected_file_name ELSE download_jobs.expected_file_name END,
                job_status = CASE WHEN download_jobs.job_status = 'COMPLETE' THEN 'COMPLETE' ELSE 'DOWNLOADING' END,
                last_error = '',
                updated_at = CURRENT_TIMESTAMP
            r   z
            SELECT id FROM download_jobs
            WHERE batch_id = ? AND post_id = ? AND asset_kind = ? AND media_index = ?
            r;  )r   r)   r*   rj   r   r   r   r   r$  r   r   r   )r   r+  r1  r   re   r*  r,  r-  r.  r'  rm   r   r   s                r    ensure_download_jobr    s    !-DzR &&(..0D122G$D$ HGAs;'(J$"%&,"-		
2 ll ]CL$As;7G0HI
 (* 	 	3t9~



s   B?D   D2)r   r*  r,  r-  r{  r|  r}  r~  r  r3  r4  rD  rk  rl  r  r  r   r  r7  r  r   c                &   t        |       j                         j                         }|r't        |      j                         j                         n
t        |      }t	        ||       t        |      }t        |xs t        j                               }t        ||||
|||||t        |xs d      j                         j                         dk(  rdnd
      }t        ||||      } t        |xs d|       }!t        ||!||d   ||t        d	t        |xs d
            t        |xs d      | d   d      }"t!        ||"|d   |||||	t        |      j"                  	      }#t%        |xs i       }$|$j'                  |!| d   d       	 t)        |fi d|d   d|d|d| d   dt        |      j"                  d| d   d|d|d|d|d|d|	d| d   d|#d|d|$}%i |%t        |      |d   |d   |"|#| d   | d   t        |      j"                  | d   | d   d!
S # t*        $ rd}&t-        |      }'	 |'j/                  d t        |&      |#f       |'j1                          |'j3                           # |'j3                          w xY wd }&~&ww xY w)"Nr%   rh   r  r   )	r=   r  r{  r|  r}  r~  r  r  r   )rs  rk  rl  zsingle-r  r   r   rp  )rk  rp  )r  r   r  r   r  r  r  r1  )r+  r1  r   re   r*  r,  r-  r.  )r  rp  r   re   r  rC  r   rD  r*  r,  r3  r4  r-  r5  r6  r7  r   z
                UPDATE download_jobs
                SET job_status = 'FAILED', last_error = ?, updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
                )
r   r  r1  r+  job_idr  r   rC  r5  rp  )r   r   r   r   r   r   r)   r"  r#  r  r*   rj   rz  r  r$  r   r  r   r%  updater[  r   r   r   r   r   )(r   rs  r   r   r=   r  re   r*  r,  r-  r{  r|  r}  r~  r  r3  r4  rD  rk  rl  r  r  r   r  r7  r  r   r   resolved_db_pathr'  rM  contextstorageeffective_batch_keyr+  r  rU  resultexcr   s(                                           r    record_downloaded_filer  +  s<   < =##%--/D?FtG}//199;LabfLg($/ -DJ.$**,/I"%#! #J$4" 5 ; ; = C C E PfVYG '!1	G i@WYK+@A$%<(As?#7a89 23%&67
H !	"	?//
F B'M,%&67	
"#
I&
 
 "	

 "/2
 9o**
  .
  
 $
 
 
 
 "
 $$56
 #
  !!
" "#
D
'(l+9% 1}-)_))"#45!"23   (	LL
 S6" KKMJJL JJLs1   AH# #	J,J8-I6%J6JJJc                   t        | t              r| }nqt        | xs d      j                         }|s$t        j                  t
        j                        }n.|j                  d      r|d d dz   }t        j                  |      }|j                   |j                  t
        j                        }|j                  t
        j                        S )Nr%   Z+00:00)tzinfo)
isinstancer   r)   r*   nowr   utcr~   fromisoformatr  rI   
astimezone)r+   dtr   s      r    _parse_observed_atr    s    %"%+2$$&hll+B||C #2h)'',B	yyZZx||Z,==&&r"   c                    t        |       }|j                  dz  dz  }|j                  |dd      j                         j                  dd      S )N
   r   )minutesecondmicrosecondr  r  )r  r  rI   	isoformat)r+   r  r  s      r    ten_minute_bucketr    sK    	E	"Bii2o#F::VA1:=GGIQQRZ\_``r"   c                T    t        |       j                         j                  dd      S )Nr  r  )r  r  rI   )r+   s    r    _iso_utcr    s#    e$..0883GGr"   LOCAL)r  r   r  r  r  observed_atplatform_account_iddisplay_nameprofile_urlr{  r|  r  r}  r~  r   r   r   r  c                  t        |xs d      j                         j                  d      }t        |xs d      j                         }|st        d      |st        d      t	        |      }t        |      }t        d ||||fD              }t        |xs d      rdnd}t        |xs d      j                         }t        dt        |xs d            }t        |xs d      j                         j                         xs d}t        |       }	 |j                  d	       |j                  d
|f      j                         }|j                  d|f      j                         }|s|r-|j                          dd||d|rdndd|j                          S |j                  d|f      j                         } | | d   |d   }!|}"|s0t        | d   xs d      rt        dt        | d   xs d            }!d}"t        | d   xs d      t        | d   xs d      t        | d   xs d      t        | d   xs d      t        | d   xs d      f|!|"|d   |d   |d   fk(  }#t        |xs d      j                         }$|$r-t        ||$t        |xs d      j                         rdnd      nd}%t!        t        | d   xs d      j                         j#                         |j#                         k7  t        | d   xs d      dk7  | d   d u| d   d ut%        t        |	xs d      j                               xr" t        | d   xs d      t        |	xs d      k7  t%        t        |
xs d      j                               xr" t        | d    xs d      t        |
xs d      k7  t%        t        |xs d      j                               xr" t        | d!   xs d      t        |xs d      k7  t%        |%      xr6 t        || d"   t        | d#   xs d      j                         rdnd      |%k7  t%        t        |xs d            xr" t        | d$   xs d      t        |xs d      k7  |d uxr" t        | d%   xs d      t        |xs d      k7  t%        t        |xs d      j                               xr" t        | d&   xs d      t        |xs d      k7  t%        t        |xs d      j                               xr" t        | d#   xs d      t        |xs d      k7  f      }&|#rH|&sF|j                          t        | d'         t        | d(         |||"|||d)ddd*|j                          S |j                  d+t        |	xs d      |t        |
xs d      t        |xs d      xs d,| d-f       t        |j                  d.|f      j                         d/         }'|j                  d0|f      j                         }(|(rnt        |xs d      j                         sQt        |xs d      j                         s4t        ||(d"   t        |(d#   xs d      j                         rdnd      })n-t        ||t        |xs d      j                         rdnd      })|j                  d1|'||)t        |xs d      |t        |xs d      t        |xs d      ||f	       t        |j                  d2|f      j                         d/         }*|j                  d3|*f      j                         }+|d   }!|}"|+2|s0t        |+d   xs d      rt        dt        |+d   xs d            }!d}"|!|d   |d   |d   f},|+d uxrk t        |+d   xs d      t        |+d   xs d      t        |+d   xs d      t        |+d   xs d      t        |+d   xs d      f|,d   |"|,d   |,d   |,d   fk(  }-|-rS|j                  d4|'f       |j                  d5|*f       |j                          |'|*|||"|||d)dd6
|j                          S |j                  d7|*|,d   |"|,d   |,d   |,d   ||||f
       |j                  d8|*|,d   |"|,d   |,d   |,d   ||||f
       |j                  d9|*|||,d   |"|,d   |,d   |,d   |||f       |j                  d4|'f       |j                  d5|*f       |j                          |'|*|||"|||dd)d6
|j                          S # t&        $ r |j)                           w xY w# |j                          w xY w):Nr%   r  zusername is requiredr  c              3  N   K   | ]  }t        d t        |xs d               yw)r   N)r$  r   )r   vs     r    r   z%upsert_observation.<locals>.<genexpr>  s"     S1RAC3qvA;'1Rs   #%r   r   r  r:  z`SELECT 1 FROM deletion_events WHERE entity_type='ACCOUNT' AND lower(entity_key)=lower(?) LIMIT 1zOSELECT 1 FROM deletion_events WHERE entity_type='POST' AND entity_key=? LIMIT 1TACCOUNTPOST)r  r1  	bucket_atr  ignored_deleteddeleted_entitya{  
            SELECT
                p.id AS post_id, p.account_id, p.post_url, p.caption, p.published_at,
                p.thumbnail_url, p.video_url, p.deleted_at AS post_deleted_at,
                a.username, a.platform_account_id, a.display_name, a.profile_url,
                a.active, a.deleted_at AS account_deleted_at,
                s.views, s.views_available, s.likes, s.comments, s.reposts
            FROM posts p
            JOIN social_accounts a ON a.id=p.account_id
            LEFT JOIN post_stat_latest s ON s.post_id=p.id
            WHERE p.platform='instagram' AND p.shortcode=?
            LIMIT 1
            r  r   r  r  r  r   r   r  r   r   usernamer   account_deleted_atpost_deleted_atr  r  r  r{  r~  r|  r  r}  r  r1  F)r  r1  r  r  r   r   r   r   savedskipped_unchangedskipped_all_writesa*  
            INSERT INTO social_accounts(
                platform, platform_account_id, username, display_name, profile_url, active, deleted_at
            ) VALUES ('instagram', ?, ?, ?, ?, 1, NULL)
            ON CONFLICT(platform, username) DO UPDATE SET
                platform_account_id = CASE WHEN excluded.platform_account_id <> '' THEN excluded.platform_account_id ELSE social_accounts.platform_account_id END,
                display_name = CASE WHEN excluded.display_name <> '' THEN excluded.display_name ELSE social_accounts.display_name END,
                profile_url = CASE WHEN excluded.profile_url <> '' THEN excluded.profile_url ELSE social_accounts.profile_url END,
                active = 1,
                deleted_at = NULL,
                updated_at = CURRENT_TIMESTAMP
            r  ry   zHSELECT id FROM social_accounts WHERE platform='instagram' AND username=?r;  zPSELECT post_url, video_url FROM posts WHERE platform='instagram' AND shortcode=?a  
            INSERT INTO posts(
                account_id, platform, shortcode, post_url, caption, published_at,
                thumbnail_url, video_url, source_url_observed_at, last_observed_at, deleted_at
            ) VALUES (?, 'instagram', ?, ?, ?, ?, ?, ?, ?, ?, NULL)
            ON CONFLICT(platform, shortcode) DO UPDATE SET
                account_id = excluded.account_id,
                post_url = CASE WHEN excluded.post_url <> '' THEN excluded.post_url ELSE posts.post_url END,
                caption = CASE WHEN excluded.caption <> '' THEN excluded.caption ELSE posts.caption END,
                published_at = COALESCE(excluded.published_at, posts.published_at),
                thumbnail_url = CASE WHEN excluded.thumbnail_url <> '' THEN excluded.thumbnail_url ELSE posts.thumbnail_url END,
                video_url = CASE WHEN excluded.video_url <> '' THEN excluded.video_url ELSE posts.video_url END,
                source_url_observed_at = excluded.source_url_observed_at,
                last_observed_at = excluded.last_observed_at,
                deleted_at = NULL,
                updated_at = CURRENT_TIMESTAMP
            z?SELECT id FROM posts WHERE platform='instagram' AND shortcode=?z
            SELECT views, views_available, likes, comments, reposts
            FROM post_stat_latest
            WHERE post_id=?
            zMDELETE FROM deletion_events WHERE entity_type='ACCOUNT' AND entity_local_id=?zJDELETE FROM deletion_events WHERE entity_type='POST' AND entity_local_id=?)
r  r1  r  r  r   r   r   r   r  r  a=  
            INSERT INTO post_stat_latest(post_id, views, views_available, likes, comments, reposts, collected_at, sort_by, sort_value, source_kind)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ON CONFLICT(post_id) DO UPDATE SET
                views=excluded.views, views_available=excluded.views_available, likes=excluded.likes, comments=excluded.comments,
                reposts=excluded.reposts, collected_at=excluded.collected_at,
                sort_by=excluded.sort_by, sort_value=excluded.sort_value, source_kind=excluded.source_kind
            a  
            INSERT INTO post_stat_history(post_id, views, views_available, likes, comments, reposts, collected_at, sort_by, sort_value, source_kind)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ON CONFLICT(post_id, collected_at) DO UPDATE SET
                views=excluded.views, views_available=excluded.views_available, likes=excluded.likes, comments=excluded.comments, reposts=excluded.reposts,
                sort_by=excluded.sort_by, sort_value=excluded.sort_value, source_kind=excluded.source_kind
            a  
            INSERT INTO post_stat_10m(
                post_id, bucket_at, observed_at, views, views_available, likes, comments, reposts, sample_count, sort_by, sort_value, source_kind
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?)
            ON CONFLICT(post_id, bucket_at) DO UPDATE SET
                observed_at=excluded.observed_at, views=excluded.views, views_available=excluded.views_available, likes=excluded.likes,
                comments=excluded.comments, reposts=excluded.reposts, sort_by=excluded.sort_by,
                sort_value=excluded.sort_value, source_kind=excluded.source_kind,
                sample_count=post_stat_10m.sample_count + 1, updated_at=CURRENT_TIMESTAMP
            )r)   r*   r  r   r  r  tupler   r$  rj   r   r   r   r   r   r  anyr1   boolr   rE  ).r   r  r=   r  r   r  r  r  r  r  r  r  r{  r|  r  r}  r~  r   r   r   r  r?   observedbucketmetricsviews_available_flag
sort_fieldsort_metric_valueobservation_sourcer   deleted_accountdeleted_postexisting_observationeffective_viewseffective_views_availableunchanged_metricsincoming_post_urlresolved_incoming_post_urlmetadata_changedr  existing_postresolved_post_urlr1  previous_stateffective_metrics	unchangeds.                                                 r    upsert_observationr    s   . B%%'..s3EyB%%'D/00011$H{+FS%'1RSSG #O$8q 91qW]#))+JAs:?34[3G4::<BBDOG$Dr&',,nH
 (* 	 ||]G
 (* 	 lKKM#'#'/>)FL 	

}  $|| G 
 (* 	   +0DW0M0Y%ajO(<%'C0DEV0W0\[\,]"%a-A'-J-Oa)P"Q,-)(16Q7():;@qA(16Q7(49:(38q9!  !:GAJPQ
T[\]T^! !$HN 3 9 9 ; %	 -+,/	R,@,F,F,H&c +- '  #(4:;AACIIKu{{}\(27a8A=$%9:$F$%67tCS,2399;<  ZEYZoEpEvtvAw{~  @S  @Y  WY  |Z  BZS+,2245  E#>RSa>b>hfh:impq}  rD  BD  nE  ;ES*+1134  B=QR_=`=fdf9gknoz  pA  A  lB  :B/0  o5QRVXlmwXx  SV  Wk  lw  Wx  W~  |~  S  SE  SE  SG  IO  MP  6Q  Uo  6oSB'(mS1Ei1P1VTV-W[^_f_ljl[m-mD(wS1En1U1[Y[-\`cdpdvtv`w-wS,"-3356  H3?STc?d?jhj;kor  tA  tG  EG  pH  <HSb)//12{s;OP[;\;b`b7cgjktkzxzg{7{$   !)9"%&:<&H"I"#7	#BC!'#+'@)"3#5")-*.N 	

u 	 $*+UC8J4KSQ\Qb`bMc  NM  jD  EJ  DK  KL  hM  N	
 VY^X`

(*T 
 ^G
 (* 	 X^!4!:!:!<SVXEYE_E_Ea <j)(+M+,F,L"(M(S(S(Uf[^! !=(+IO(<(B(B(Df#!
 	$ D"3GMr"L#m6Ir2JCPYP_]_L`(%	
0 dllMPTw

(*T  
 J
 (* 	 "!*$8!$-Ac-XiJjJonoFp!!Sw)?)D1%EFO()%,gaj'!*gajQ!- 
g&+!,/05A6g&+!,j).Q/i(-A.3
 a %a a a 
3
	 LL_blan LL\_f^h KKM("#'#<%/1%)t 	

] 	 '*,EGXYZG[]nop]q  tE  FG  tH  JR  T^  `q  sE  F
	
 	 '*,EGXYZG[]nop]q  tE  FG  tH  JR  T^  `q  sE  F		
 		 fh(9!(<>WYjklYm  pA  BC  pD  FW  XY  FZ  \f  hy  {M  N	
 	[^h]j	
 	X[bZd	
 	(W6bj  @Y  fp  @Q  bt  C  Z_  `
 	

	   	

s.   A3d Od 5J?d B;d d,,d/ /er   2   )page	page_sizeinclude_deletedsearch_patternc          
        t        dt        |xs d            }t        dt        dt        |xs d                  }|rdnd}t        |xs d      }|}g }|r|dz  }|j	                  |       t        |       }		 t        |	j                  d|       j                         d	         }
t        |	j                  d| |      j                         d	         }|	j                  d
| dg |||dz
  |z        j                         }|D cg c]  }t        |       c}||||
|dd|	j                          S c c}w # |	j                          w xY w)Nr   '  r  z1=1z#a.active=1 AND a.deleted_at IS NULLr%   z% AND a.username LIKE ? COLLATE NOCASEz2SELECT COUNT(*) AS n FROM social_accounts a WHERE na&  
            SELECT a.id, a.username, a.display_name, a.profile_url, a.active, a.deleted_at,
                   COUNT(p.id) AS post_count,
                   COALESCE(MAX(s.views), 0) AS max_views,
                   COALESCE(SUM(s.views), 0) AS total_views,
                   MAX(COALESCE(s.collected_at, p.last_observed_at, a.updated_at)) AS last_observed_at
            FROM social_accounts a
            LEFT JOIN posts p ON p.account_id=a.id AND p.deleted_at IS NULL
            LEFT JOIN post_stat_latest s ON s.post_id=p.id
            WHERE z
            GROUP BY a.id
            ORDER BY COALESCE(last_observed_at, a.updated_at) DESC, a.username COLLATE NOCASE
            LIMIT ? OFFSET ?
            r   )itemsr  r  total	total_allr  r   )r$  r   minr)   appendr   r   r   fetchallr%  r   )r   r  r  r  r  
base_wherepatternwherewhere_paramsr   r  r  rowsr   s                 r    list_accountsr    s{    q#dia.!DAs5#io2"678I)/TJ.&B'GE L88G$G$D"@M

(*S 	 DLL@H,

(*S  ||	 '  ?l>I>qI'=>
  (*! 	$ ,004Cd3i40""%+
 	

 1 	

s   :BD> D9
D> 9D> >E)r  r  r   include_media_assetsc          
        t        dt        |xs d            }t        dt        dt        |xs d                  }dddddd	d
d}|j                  t	        |xs d      |d         }d}|rd}t        |       }		 t        |	j                  dt        |      f      j                         d         }
|	j                  d| d| dt        |      ||dz
  |z  f      j                         }|D cg c]  }t        |       }}i }|r|D cg c]  }t        |d          }}|rdj                  d |D              }|	j                  d| d|      j                         }|D ]F  }t        |      }|j                  t        |j                  d            g       j                  |       H |D ]  }t        |j                  d      |j                  d      t	        |j                  d      xs d      j                         rdnd      |d<   |sc|j                  t        |d         g       |d <    ||||
|d!|	j!                          S c c}w c c}w # |	j!                          w xY w)"Nr   r  r  z
views DESCz
likes DESCzcomments DESCzreposts DESCzviews_delta DESCzviews_per_hour DESCzp.published_at DESC)r  r  r  r  views_deltaviews_per_hourr  r  r%   a  ,
                   (SELECT ma.folder_name FROM media_assets ma WHERE ma.post_id=p.id AND ma.local_status='AVAILABLE' ORDER BY ma.media_index, ma.id LIMIT 1) AS folder_name,
                   (SELECT ma.file_name FROM media_assets ma WHERE ma.post_id=p.id AND ma.local_status='AVAILABLE' ORDER BY ma.media_index, ma.id LIMIT 1) AS file_name,
                   (SELECT ma.relative_path FROM media_assets ma WHERE ma.post_id=p.id AND ma.local_status='AVAILABLE' ORDER BY ma.media_index, ma.id LIMIT 1) AS relative_path,
                   EXISTS(
                       SELECT 1 FROM media_assets ma
                       WHERE ma.post_id=p.id AND ma.local_status='AVAILABLE'
                         AND UPPER(ma.asset_kind) IN ('IMAGE','JPG','JPEG')
                   ) AS has_jpg,
                   EXISTS(
                       SELECT 1 FROM media_assets ma
                       WHERE ma.post_id=p.id AND ma.local_status='AVAILABLE'
                         AND UPPER(ma.asset_kind) IN ('VIDEO','MP4')
                   ) AS has_mp4zISELECT COUNT(*) AS n FROM posts WHERE account_id=? AND deleted_at IS NULLr  a  
            WITH ranked AS (
                SELECT t.*, ROW_NUMBER() OVER(PARTITION BY t.post_id ORDER BY t.bucket_at DESC) AS rn
                FROM post_stat_10m t
            ), recent AS (
                SELECT post_id,
                       MAX(CASE WHEN rn=1 THEN views END) AS last_views,
                       MAX(CASE WHEN rn=2 THEN views END) AS prev_views,
                       MAX(CASE WHEN rn=1 THEN bucket_at END) AS bucket_at
                FROM ranked WHERE rn <= 2 GROUP BY post_id
            )
            SELECT p.id, p.shortcode, p.post_url, p.caption, p.published_at, p.thumbnail_url,
                   p.video_url, p.media_state, p.last_observed_at,
                   COALESCE(s.views,0) AS views, COALESCE(s.views_available,0) AS views_available, COALESCE(s.likes,0) AS likes,
                   COALESCE(s.comments,0) AS comments, COALESCE(s.reposts,0) AS reposts,
                   COALESCE(recent.last_views, s.views, 0)-COALESCE(recent.prev_views, recent.last_views, s.views, 0) AS views_delta,
                   (COALESCE(recent.last_views, s.views, 0)-COALESCE(recent.prev_views, recent.last_views, s.views, 0))*6 AS views_per_hour,
                   CASE WHEN COALESCE(s.views,0)>0 THEN ROUND(COALESCE(s.likes,0)*100.0/s.views,4) ELSE 0 END AS like_rate,
                   CASE WHEN COALESCE(s.views,0)>0 THEN ROUND(COALESCE(s.comments,0)*100.0/s.views,4) ELSE 0 END AS comment_rate,
                   recent.bucket_at AS latest_bucket_at
                   z
            FROM posts p
            LEFT JOIN post_stat_latest s ON s.post_id=p.id
            LEFT JOIN recent ON recent.post_id=p.id
            WHERE p.account_id=? AND p.deleted_at IS NULL
            ORDER BY z5, p.id DESC
            LIMIT ? OFFSET ?
            r;  ,c              3      K   | ]  }d   yw?N r   r$   s     r    r   z%list_account_posts.<locals>.<genexpr>_  s     '>XX   ah  
                    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 IN (zu) AND ma.local_status='AVAILABLE'
                    ORDER BY ma.post_id, ma.media_index, ma.id
                    r1  r=   r{  r~  r  r   r   r   )r  r  r  r  r   )r$  r   r  r   r)   r   r   r   r  r%  r   
setdefaultpopr  r  r*   r   )r   r  r  r  r   r  sort_mapordermedia_columnsr   r  r  r   r  assets_by_postitempost_idsplaceholders
asset_rows	asset_rowrT  s                        r    list_account_postsr
    s    q#dia.!DAs5#io2"678I/!2D/AVH
 LLW/0(72CDEM# G$D=DLLWZ]^hZiYk

(*S  ||( "? #
 W 38 _i$(i)?@;
< (*= 	> '++dscd+:<49:EDDJEH:"xx'>X'>>!\\*
 +7 8 
 (*  ",I OE"--c%))I2F.GLSSTYZ ", D;DHH[<QSWS[S[\fSg  BE  FJ  FN  FN  OZ  F[  Fa  _a  Bb  Bh  Bh  Bjw}  ps   tD#'5'9'9#d4j/2'N^$  9uahi

5 , ;. 	

s2   ;A3I .I
 
I 
IC/I *I 

I I&)r  c          	     N   t        |       }	 |j                  dt        |      f      j                         }|s	 |j	                          y t        |      }t        |j                  d      |j                  d      t        |j                  d      xs d      j                         rdnd      |d<   |rF|j                  d	t        |      f      j                         }|D cg c]  }t        |       c}|d
<   ||j	                          S c c}w # |j	                          w xY w)Na   
            SELECT p.*, a.username, a.display_name,
                   COALESCE(s.views,0) AS views, COALESCE(s.views_available,0) AS views_available, COALESCE(s.likes,0) AS likes,
                   COALESCE(s.comments,0) AS comments, COALESCE(s.reposts,0) AS reposts,
                   s.collected_at
            FROM posts p
            LEFT JOIN social_accounts a ON a.id=p.account_id
            LEFT JOIN post_stat_latest s ON s.post_id=p.id
            WHERE p.id=? AND p.deleted_at IS NULL
            r=   r{  r~  r%   r  r   r   z
                SELECT id, asset_kind, media_index, storage_root_id, folder_name, file_name, relative_path, file_size, md5, sha256, local_status
                FROM media_assets WHERE post_id=? ORDER BY media_index, id
                r   )r   r   r   r   r   r%  r  r   r)   r*   r  )r   r1  r  r   r   r  assetsrT  s           r    get_post_detailr  w  sL    G$Dll	 \O
 (* 	  	

 Cy78MtxxXbOc  ~A  BF  BJ  BJ  KV  BW  B]  []  ~^  ~d  ~d  ~fsy  lo  pZ\\ W hj  >D#DVEDKV#DD 

 $E 	

s$   ,D BD #D5D D D$c                8   t        |       }	 |j                  dt        |      t        dt	        dt        |xs d                  f      j                         }|D cg c]  }t        |       c}|j                          S c c}w # |j                          w xY w)Nz
            SELECT bucket_at, observed_at, views, views_available, likes, comments, reposts, sample_count
            FROM post_stat_10m WHERE post_id=? ORDER BY bucket_at DESC LIMIT ?
            r   i     )r   r   r   r$  r  r  r%  r   )r   r1  limitr   r  r   s         r    get_post_statsr    s    G$D
|| \3q#dC,=">?@
 (* 	 &**TcS	T*

 +

s   AB B/B B B>   r%   r   apihomer  aboutlegaloauthr  termsdirectemailssearchexploregraphqlprivacystoriesaccountsexplorer	challenge	developerr:   c                .   t        | xs d      j                         j                  ddd      j                         j                  d      }|sy|}d|v s#|j	                  d      s|j	                  d      r*d|v r|nd|z   }	 t
        j                  j                  |      }t        |j                  xs d      j                         j                  d      }|d	k7  ryt        |j                  xs d      j                  d
      D cg c]$  }|st
        j                  j                  |      & }}|syt        |d   xs d      j                         }|j                         t        v ryt!        |      dkD  r#t        |d   xs d      j                         dvry|}nd
|v ry|j                         j                  d      j                         }|t        v ry|rt!        |      dkD  ryt#        d |D              ry|S # t        $ r Y yw xY wc c}w )a  Return a canonical Instagram username for the collection queue.

    The queue stores usernames only. A legacy profile URL is accepted only for
    migration; feed/detail scopes such as /explore/, /reels/, /p/ and /reel/
    are rejected and never become collection accounts.
    r%   u   🗑️r   r  z://zwww.zinstagram.com/zhttps://r  ry   r   >   r     c              3  $   K   | ]  }|d v 
 yw)z&abcdefghijklmnopqrstuvwxyz0123456789._Nr  )r   chs     r    r   z0normalize_collection_username.<locals>.<genexpr>  s     
R	"2==	s   )r)   r*   rI   r  r2   rS   rT   r  r   r	  r1   removeprefixra   r
  r  _COLLECTION_RESERVED_USERNAMESr  r  )	r+   r   ro   r_   r  r  r  r  firsts	            r    normalize_collection_usernamer*    s    ekr

 
 
"
*
*9b!
<
B
B
D
K
KC
PCI|s~~f-@P1Qc\czC'7	\\**3/F 6??(b)//1>>vF?"8;FKK<M28N8T8TUX8Yb8Y]a%%d+8YbE!HN#))+;;=::u:>c%(.b1779J		!((-335I22I+

R	
RR1  		
 cs   H 	H!H	HH)r  c          	     @   t        |       }	 |rdnd}|j                  d| d      j                         }|D cg c]4  }i t        |      t	        |d         t	        |d         d|d    d	d
6 c}|j                          S c c}w # |j                          w xY w)Nr%   z WHERE enabled=1 AND is_deleted=0z
            SELECT id, username, position, enabled, is_deleted, source_type, updated_at
            FROM collection_account_queue
            z7
            ORDER BY position ASC, id ASC
            enabled
is_deletedr  r  ry   )r,  r-  account_url)r   r   r  r%  r  r   )r   r  r   r  r  r   s         r    list_collection_accountsr/    s    G$D%+M|| G 
 (* 	 
 s)I/"3|#45!;C
O;LAN	 
 	


 	

s   -B 9B3B B Bc                Z   i }t        |xs g       D ]  }t        |t              r|nd|i}t        |j	                  d      xs7 |j	                  d      xs$ |j	                  d      xs |j	                  d            }|spt        |j	                  d      xs |j	                  d            rdnd}|rdnt        |j	                  d	d
            rdnd}|j	                  |      }|$|d   s|rdnd|d<   |d   rdn
|d	   r|rdnd|d	<   |d||d||<    t        |j                               }	t        |      }
t        |	d      D ]
  \  }}||d<    t        |       }	 |j                  d       |j                  d      j                         D ch c]0  }t        |d   xs d      j                         j                         2 }}|	D ]5  }|d   |v r
d|d<   d|d	<   |j                  d|d   |d   |d	   |d   f       7 |
rAdj                  d |
D              }|j                  d| dt!        t#        |
                   n|j                  d       d|	D cg c]'  }|d   |d   t        |d	         t        |d         d) c}i}|j                  dt%        j&                  |dd
      f       |j)                          t+        |       t-        |	      d|j/                          S c c}w c c}w # t0        $ r |j3                           w xY w# |j/                          w xY w)zDReplace the SIDE collection queue with a username-only ordered list.r  r>   r.  r_   r-  deletedr   r   r,  T)r  positionr,  r-  )startr2  r:  zBSELECT entity_key FROM deletion_events WHERE entity_type='ACCOUNT'
entity_keyr%   a  
                INSERT INTO collection_account_queue(username, position, enabled, is_deleted, source_type)
                VALUES (?, ?, ?, ?, 'SIDE')
                ON CONFLICT(username) DO UPDATE SET
                    position=excluded.position,
                    enabled=excluded.enabled,
                    is_deleted=excluded.is_deleted,
                    source_type='SIDE',
                    updated_at=CURRENT_TIMESTAMP
                r  c              3      K   | ]  }d   ywr  r  r  s     r    r   z.replace_collection_accounts.<locals>.<genexpr>/  s     #6ACr  zSDELETE FROM collection_account_queue WHERE source_type='SIDE' AND username NOT IN (r   z=DELETE FROM collection_account_queue WHERE source_type='SIDE'r  zmINSERT INTO sync_queue(entity_type, operation, payload_json) VALUES('COLLECTION_ACCOUNT_QUEUE', 'REPLACE', ?)Fr   )r  r  )listr  r	   r*  r   r  r  r3   	enumerater   r   r  r)   r*   r1   r   r  r   rV   rW   r   r/  r  r   r   rE  )r   r  normalized_by_usernameraw_itemr  r  r1  r,  previousr   seenr2  r   r   deleted_namesr  r   s                    r    replace_collection_accountsr=    sh   8:"%%h8xz8>T0HHZ eDHHY$7e488M;ReVZV^V^_dVe
 DHH\2Idhhy6IJ!PQ!$txx	4/H*IQq)--h7*2<*@GQQRH\"'/'=!R[I\ahAnoHY !	,
x( &. ,3356J%&D#Ja8$#Z 9 G$D6&' ||Thj
 L!'R(..0668 	 
 DJ=0%&\""#YLL	 j!4
#3T)_d<FXY	 " 88#6#66LLLefresstufTl#
 LLXY ' 'D !%Z 0 $Z 0#DO4"&tL'9":	 '

 	{ZZetDF	
 	1':S_U
 	

i
@    	

s8   $2K: 5K0BK:  ,K5AK: 0
K: :LL L*c           	     |   t        |       }	 |j                  d       |j                  dt        |      f      j                         }|st	        d|       |j                  dt        |      f       |j                  dt        |      f       |j                  dt        |d         f       |j                  dt        |      f       |j                  d	t        |      t        |d         t        |xs d
      f       t        j                  t        |      t        |d         dddd      }|j                  dt        |      |f       |j                          t        |      t        |d         dd|j                          S # t        $ r |j                           w xY w# |j                          w xY w)Nr:  z3SELECT id, username FROM social_accounts WHERE id=?zaccount_id not found: zjUPDATE social_accounts SET active=0, deleted_at=CURRENT_TIMESTAMP, updated_at=CURRENT_TIMESTAMP WHERE id=?z^UPDATE account_collection_rules SET enabled=0, updated_at=CURRENT_TIMESTAMP WHERE account_id=?zyUPDATE collection_account_queue SET enabled=0, is_deleted=1, updated_at=CURRENT_TIMESTAMP WHERE username=? COLLATE NOCASEr  zsUPDATE posts SET deleted_at=COALESCE(deleted_at,CURRENT_TIMESTAMP), updated_at=CURRENT_TIMESTAMP WHERE account_id=?a6  INSERT INTO deletion_events(entity_type, entity_local_id, entity_key, reason)
               VALUES('ACCOUNT', ?, ?, ?)
               ON CONFLICT(entity_type, entity_local_id) DO UPDATE SET
                   entity_key=excluded.entity_key, reason=excluded.reason, created_at=CURRENT_TIMESTAMP, synced_at=NULLuser_deleteT)r  r  r1  Fr   zoINSERT INTO sync_queue(entity_type, entity_local_id, operation, payload_json) VALUES('ACCOUNT', ?, 'DELETE', ?)r   r   r   r   r   r)   rV   rW   r   r   r   rE  )r   r  reasonr   r   r   s         r    soft_delete_accountrB  N  s   G$D&'llPSVWaSbRdennp5j\BCC  B  EH  IS  ET  DV  	Wux{  }G  yH  xJ  	K  Q  TW  X[  \f  Xg  Th  Sj  	k  K  NQ  R\  N]  M_  	`{ _c#j/2C8O-4PQ	
 **C
OSQ[_I]jno  D  PT  U  G  JM  NX  JY  [b  Ic  	d!*o3s:;O\`a
 	

	   	

s   E-F F&&F) )F;c           	        t        |       }	 |j                  d       |j                  dt        |      f      j                         }|st	        d|       |j                  dt        |      f       |j                  dt        |      t        |d         t        |xs d      f       t        j                  t        |      t        |d         dd	d
d      }|j                  dt        |      |f       |j                          t        |      t        |d         dd	|j                          S # t        $ r |j                           w xY w# |j                          w xY w)Nr:  z*SELECT id, shortcode FROM posts WHERE id=?r?  zVUPDATE posts SET deleted_at=CURRENT_TIMESTAMP, updated_at=CURRENT_TIMESTAMP WHERE id=?a3  INSERT INTO deletion_events(entity_type, entity_local_id, entity_key, reason)
               VALUES('POST', ?, ?, ?)
               ON CONFLICT(entity_type, entity_local_id) DO UPDATE SET
                   entity_key=excluded.entity_key, reason=excluded.reason, created_at=CURRENT_TIMESTAMP, synced_at=NULLr=   r?  T)r1  r=   r1  Fr   zlINSERT INTO sync_queue(entity_type, entity_local_id, operation, payload_json) VALUES('POST', ?, 'DELETE', ?)r@  )r   r1  rA  r   r   r   s         r    soft_delete_postrD  k  sb   G$D&'llG#g,Ybbd27)<==mpst{p|o~{ \3s;/0#f6M2NO	
 **WCKHXDYfjkz  LP  Q  D  GJ  KR  GS  U\  F]  	^w<c#k:J6KX\]
 	

	   	

s   DD4 4EE E$c                    t        |       }	 |j                  d      j                         }|D cg c]  }t        |       c}|j	                          S c c}w # |j	                          w xY w)NzSELECT entity_local_id AS account_id, entity_key AS username, created_at
               FROM deletion_events WHERE entity_type='ACCOUNT' ORDER BY created_at DESC)r   r   r  r%  r   )r   r   r  r   s       r    list_deleted_accountsrF    sb    G$D||\
 (* 	 &**TcS	T*

 +

s   #A AA A A,c            	     r   t        j                  d      } | j                  ddd       | j                  dd	       | j                  d
d       | j                         }t	        |j
                        }|j                  rt	        |j                        n
t        |      }	 t        |||j                         }t        t        j                   ddi|dd             y# t        t        j                  t        f$ r6}t        t        j                   dt#        |      dd             Y d }~yd }~ww xY w)Nz%Initialize sort local SQLite storage.)descriptionz	--st-rootTz"Absolute path to the _St directory)requiredhelpz--dbz;SQLite path. Defaults to _St/Shared/data/sort_local.sqlite3)rJ  z--no-create-storage-dirs
store_true)actionr   FAIL)overallerrorFrF   r   rN  OKr   r   r   )argparseArgumentParseradd_argument
parse_argsr   r   dbr   r   no_create_storage_dirsrR   r   Errorr   printrV   rW   r)   )parserargsr   r   r  r  s         r    mainr[    s	   $$1XYF
d9]^
%bc
2<HD4<< G#wwd477m,A',JG$$($?$? ?
 
$**i00uQ
OP W]]J/ djjVc#h?eTUs   #C" "D6 ,D11D6__main__)r   
str | Pathreturnr   )unknown)r+   objectr,   r)   r^  r)   )r+   r`  r^  r)   )
r   r]  r<   r`  r=   r`  r6   r`  r^  r   )r   r]  r<   r`  r^  r   )
r   r]  r<   r`  r=   r`  re   r)   r^  zPath | None)r   r]  r^  r)   )r   r]  r   r`  r^  r   )r   r]  r^  dict[str, Any])r   r]  r   r`  r^  ra  )r   r]  r   r]  r   r`  r^  ra  )r   r]  r^  sqlite3.Connection)r   rb  r   r)   r^  zset[str])
r   rb  r   r)   r   r)   r   r)   r^  None)r   rb  r^  rc  )r   r]  r   r]  r   r  r^  ra  )r   r)   r^  r)   )r=   r)   r  r)   r   r)   r^  r)   )r  r]  r^  r)   )r   r]  r   r)   r  
str | Noner  
int | Noner   r)   r  re  r  r   r  Mapping[str, Any] | Noner^  r   )r   r]  r1  r   r   r)   re   r)   r*  r   r+  re  r,  re  r-  r)   r.  r)   r^  r   )&r   r]  r1  r   r   r)   re   r)   r  r]  rC  r)   r   r)   rD  r   r*  r   r,  re  r3  r)   r4  r)   r-  r)   r5  re  r6  re  r7  rd  r8  rd  r   rf  r^  ra  )
r   r]  rd  r]  r\  rd  r]  r  r^  r   )ra   r   r   r   r^  r  )
r   r]  rs  r]  rk  r)   rl  r  r^  ra  )r   r]  r=   r)   r  r)   r{  r)   r|  r)   r}  r)   r~  r)   r  rd  r  rf  r   r)   r^  zdict[str, int])r   r]  r  r)   r   r)   r  re  r   r)   r  re  r  r   r  rf  r^  r   )r   r]  r+  r   r1  r   r   r)   re   r)   r*  r   r,  re  r-  r)   r.  r)   r^  r   )8r   r]  rs  r]  r   zstr | Path | Noner   r)   r=   r)   r  r)   re   r)   r*  r   r,  re  r-  r)   r{  r)   r|  r)   r}  r)   r~  r)   r  rd  r3  r)   r4  r)   rD  r   rk  r)   rl  r  r  r)   r  r   r   r)   r  re  r7  r)   r  rf  r   rf  r^  ra  )r+   str | datetime | Noner^  r   ru   )r+   rg  r^  r)   )*r   r]  r  r)   r=   r)   r  r   r   r   r  r   r  r   r  r   r  rg  r  r)   r  r)   r  r)   r{  r)   r|  r)   r  rd  r}  r)   r~  r)   r   r)   r   r   r   r)   r^  ra  )r   r]  r  r   r  r   r  r  r  r)   r^  ra  )r   r]  r  r   r  r   r  r   r   r)   r  r  r^  ra  )r   r]  r1  r   r  r  r^  zdict[str, Any] | None)r  )r   r]  r1  r   r  r   r^  list[dict[str, Any]])r   r]  r  r  r^  rh  )r   r]  r  zlist[object]r^  ra  )r?  )r   r]  r  r   rA  r)   r^  ra  )r   r]  r1  r   rA  r)   r^  ra  )r   r]  r^  rh  )r^  r   )T
__future__r   rQ  ra  rV   r'   r   urllib.parserS   r"  r   r   pathlibr   r   typingr   r	   SCHEMA_VERSION__file__	with_namer   r   DEFAULT_DB_RELATIVErv   compiler|   r   	frozensetr   r4   r5   r!   r.   r8   rA   rc   rp   rs   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r)  r2  r[  rg  rj  rz  r  r  r  r  r  r  r  r  r  r
  r  r  r(  r*  r/  r=  rB  rD  rF  r[  __name__
SystemExitr  r"   r    <module>ru     s	   "    	    ' ' N34N34N34N34N34N34N34 + 8nv-0CC "8nv58VV "

#>? ) 
 G  #"
	P	P	P 	P 		P
 
	P%\  
  0DN #+D
k]]]<	ZX
> !%	,,, 	,
 ,^ ]` E> !!")-## # 	#
 # # # # '# 	#X  '' ' 	'
 ' ' ' ' ' ' 	'd "&"&!#(,'JJ J 	J
 J J J J J J J 
J J J  J   !J" #J$ %J& &'J( )J` !  	
  	D !&33 3 	3
 3 3v #&*nn n 	n
 n n n n n $n n nl "")-.. . 	.
 . . . . '. 	.p  55 5 	5
 5 5 5 5 5 5 	5x "&
 #!&"&*(,9DD D 	D
 D D D D D D D D D D D  !D" 
#D$ %D& 'D( )D* +D, -D. /D0 1D2 3D4 5D6 $7D8 &9D: ;DP' aH )-!#+WW W 	W
 W W W W W 'W W W W W W  !W" #W$ %W& 'W( )W* +W, -Wv )*BX]00"%0690QU00 0h :;R`g!%ZZ(+Z36ZGJZZ]ZZ Z| HL!!"%!@D!!H  "+ , " 'T NR 2Vr:4	. z
TV
 r"   