+
    i6                     J   R t ^ RIt^ RIt^ RIHtHt ^ RIHtHtHtH	t	H
t
  ^ RItRtRR^
R^/RR^R^/R	R^(R^//tR
t]! 0 RkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkR kR!kR"kR#kR$kR%kR&kR'kR(kR)kR*kR+kR,kR-kR.kR/kR0kR1kR2kR3kR4kR5kR6k4      tR7R8R90R:R8R90R80 R]mR90 R^mR;R<0R<R;0R=R>0R>R=0R?R@RA0RBRCRD0RERF0RFRE0/tRG RH ltR_RI RJ lltRK RL ltRM RN ltRO RP ltRQ RR ltRS RT ltR`RU RV lltRaRW RX lltR`RY RZ lltR[ R\ ltR#   ] d    Rt Li ; i)baH  Instagram Reels search via ScrapeCreators API for /last30days.

Uses ScrapeCreators REST API to search Instagram Reels by keyword, extract
engagement metrics (views, likes, comments), and fetch video transcripts.

Requires SCRAPECREATORS_API_KEY in config. 100 free credits, then PAYG.
API docs: https://scrapecreators.com/docs
N)datetimetimezone)AnyDictListOptionalSetzhttps://api.scrapecreators.comquickresults_per_pagemax_captionsdefaultdeepi  theaantoforhowisinofonandwithfrombyatthisthatitmyyourimeweyouwhataredocanitsbeornotnosoifbutaboutalljustgethashavewaswillhipraphiphophopjs
javascriptts
typescriptai
artificialintelligencemlmachinelearningreactreactjsc                F    V ^8  d   QhR\         R\        \         ,          /# )   textreturn)strr   )formats   "U/Users/bowang/.openclaw/workspace/skills/last30days-official/scripts/lib/instagram.py__annotate__rQ   :   s      C CH     c                P   \         P                  ! RRV P                  4       4      P                  4       pV Uu0 uF#  q"\        9  g   K  \        V4      ^8  g   K!  VkK%  	  pp\        V4      pV F,  pV\        9   g   K  VP                  \        V,          4       K.  	  V# u upi )zHLowercase, strip punctuation, remove stopwords, drop single-char tokens.z[^\w\s] )	resublowersplit	STOPWORDSlensetSYNONYMSupdate)rL   wordswtokensexpandedts   &     rP   	_tokenizerc   :   s    FF:sDJJL1779EDA9"4aQ!aaFD6{H=OOHQK(  O Es   B#
B#B#c                ^    V ^8  d   QhR\         R\         R\        \         ,          R\        /# )rK   queryrL   hashtagsrM   )rN   r   float)rO   s   "rP   rQ   rQ   E   s,     % %c % %S	 %U %rR   c                   \        V 4      pTpV'       d   V RRP                  V4       2p\        V4      pV'       dD   V F=  pVP                  4       pV F$  pW9   g   K  W8w  g   K  VP                  V4       K&  	  K?  	  V'       g   R# \	        W5,          4      p	V	\	        V4      ,          p
\        R\        RV
4      4      # )zCompute relevance as ratio of query tokens found in text + hashtags.

Uses ratio overlap (intersection / query_length). Hashtags provide
an Instagram-specific relevance boost. Floors at 0.1.
rT   g      ?g?g      ?)rc   joinrW   addrZ   maxmin)re   rL   rf   q_tokenscombinedt_tokenstag	tag_lowerqtoverlapratios   &&&        rP   _compute_relevanceru   E   s     H HV1SXXh/01"H C		I?rLL$   (%&Gc(m#EsCUO$$rR   c                0    V ^8  d   QhR\         R\         /# )rK   topicrM   rN   )rO   s   "rP   rQ   rQ   c   s                rR   c                   V P                  4       P                  4       p. ROpV F?  pVP                  VR,           4      '       g   K#  V\        V4      R P                  4       pKA  	  0 RmpVP	                  4       pV Uu. uF  qfV9  g   K  VNK  	  ppV'       d   RP                  V4      MTpVP                  R4      # u upi )zExtract core subject from verbose query for Instagram search.

Strips meta/research words to keep only the core product/concept name.
rT   Nz?!.)zwhat are the bestzwhat is the bestzwhat are the latestzwhat are people saying aboutzwhat do people think aboutzhow do i usez
how to usezhow tozwhat arezwhat isztips forzbest practices for>   newtopbestgoodnewsgreatviraladvicekillerlatestpromptr]   awesomehottestmethodspopularpromptsupdatesfeaturestrending	practices	prompting
approaches
strategiesrecommendations)rW   strip
startswithrZ   rX   ri   rstrip)	rw   rL   prefixespnoiser^   r_   filteredresults	   &        rP   _extract_core_subjectr   c   s    
 ;;= DH ??1s7##A=&&(D 
E JJLE 35aUN5H3#+SXXhF== 4s    CCc                $    V ^8  d   QhR\         /# )rK   msgrx   )rO   s   "rP   rQ   rQ      s      c rR   c                    \         P                  P                  4       '       dD   \         P                  P                  RV  R24       \         P                  P	                  4        R# R# )zGLog to stderr (only in interactive terminals; spinner handles non-TTY).z[Instagram] 
N)sysstderrisattywriteflush)r   s   &rP   _logr      sE    
zz

<uB/0

 rR   c                R    V ^8  d   QhR\         R\        \         \         3,          /# )rK   tokenrM   )rN   r   )rO   s   "rP   rQ   rQ      s"      s tCH~ rR   c                    RV RR/# )z%Build ScrapeCreators request headers.z	x-api-keyzContent-Typezapplication/json )r   s   &rP   _sc_headersr      s     	U* rR   c                h    V ^8  d   QhR\         \        \        3,          R\        \        ,          /# )rK   itemrM   )r   rN   r   r   )rO   s   "rP   rQ   rQ      s&      d38n # rR   c                   V P                  R4      pV'       g   R# \        V\        4      '       d9    \        P                  ! VP                  RR4      4      pVP                  R4      #  \        P                  ! \        V4      \        P                  R7      pVP                  R4      #   \        \        3 d     Mi ; i\        T4      ^
8  g   Kj  TR,          #   \        \        \        3 d     R# i ; i)zParse date from ScrapeCreators Instagram item to YYYY-MM-DD.

Handles taken_at as ISO string (e.g. "2026-02-26T16:00:00.000Z")
or unix timestamp.
taken_atNZz+00:00z%Y-%m-%d:N
   N)tz)r5   
isinstancerN   r   fromisoformatreplacestrftime
ValueError	TypeErrorrZ   fromtimestampintr   utcOSError)r   r@   dts   &  rP   _parse_dater      s     
*	B "c	''

3(ABB;;z**##CG={{:&& I& 		 r7b=c7N 	7+ s#   6B+ +?C +B?>B?C76C7c                F    V ^8  d   QhR\         R\        \         ,          /# )rK   caption_textrM   )rN   r   )rO   s   "rP   rQ   rQ      s     / /C /DI /rR   c                D    V '       g   . # \         P                  ! RV 4      # )z-Extract hashtags from Instagram caption text.z#(\w+))rU   findall)r   s   &rP   _extract_hashtagsr      s    	::i..rR   c                    V ^8  d   QhR\         R\         R\         R\         R\         R\        \         \        3,          /# rK   rw   	from_dateto_datedepthr   rM   rN   r   r   )rO   s   "rP   rQ   rQ      sT     ~ ~~~ ~ 	~
 ~ 
#s(^~rR   c                   V'       g   R. RR/# \         '       g   R. RR/# \        P                  V\        R,          4      p\        V 4      p\	        RV RV RVR	,           R
24        \         P                  ! \
         R2RV/\        V4      ^R7      pVP                  4        VP                  4       pTP                  R4      ;'       g5    TP                  R4      ;'       g    TP                  R4      ;'       g    . p
T
RTR	,           p
. pT
 EFG  p\        T\        4      '       g   K  \        TP                  RTP                  RR4      4      4      pTP                  RTP                  RR4      4      pTP                  RR4      p\        T\        4      '       d   TP                  RR4      pM;\        T\        4      '       d   TpM"TP                  RTP                  RR4      4      pTP                  R4      ;'       g5    TP                  R4      ;'       g    TP                  R4      ;'       g    ^ pTP                  R4      ;'       g    ^ pTP                  R4      ;'       g    ^ pTP                  R 4      ;'       g    TP                  R!4      ;'       g    / pTP                  R"R4      pTP                  R#4      p\        T4      p\!        T4      p\#        TTT4      pTP                  R$R4      pT'       g   T'       d   R%T 2pTP%                  R&TRTR$TR'TR(TR)R*TR+TR,T/R-TR.TR/TR0T'       d   R1TR2,           2MR1T 2R3R/4       EKJ  	  T Uu. uF2  pTR(,          '       g   K  TTR(,          u;8:  d
   T8:  g   K,  M K0  TNK4  	  pp\'        T4      \'        T4      ,
          pT'       d   TpT'       d   \	        R4T R524       M\	        R6\'        T4       24       TP)                  R7 R8R97       \	        R:\'        T4       R;24       RT/#   \         d7   p	\	        RT	 24       R. R\        T	4      P                   RT	 2/u Rp	?	# Rp	?	ii ; iu upi )<a  Search Instagram Reels via ScrapeCreators API.

Args:
    topic: Search topic
    from_date: Start date (YYYY-MM-DD)
    to_date: End date (YYYY-MM-DD)
    depth: 'quick', 'default', or 'deep'
    token: ScrapeCreators API key

Returns:
    Dict with 'items' list and optional 'error'.
itemserrorz$No SCRAPECREATORS_API_KEY configuredzrequests library not installedr   zSearching Instagram for 'z	' (depth=z, count=r
   )z/v1/instagram/reels/searchre   paramsheaderstimeoutzScrapeCreators error: : Nreelsdataidpk 	shortcodecodecaptionrL   descvideo_play_countvideo_view_count
play_count
like_countcomment_countowneruserusernamevideo_durationurlzhttps://www.instagram.com/reel/video_idauthor_namedate
engagementviewslikescommentsrf   duration	relevancewhy_relevantzInstagram: :N<   Ncaption_snippetz	Filtered z reels outside date rangez(No reels within date range, keeping all c                 "    V R ,          R,          # )r   r   r   )xs   &rP   <lambda>"search_instagram.<locals>.<lambda>7  s    Q|_W5rR   T)keyreversezFound z Instagram reels)	_requestsDEPTH_CONFIGr5   r   r   SCRAPECREATORS_BASEr   raise_for_statusjson	Exceptiontype__name__r   dictrN   r   r   ru   appendrZ   sort)rw   r   r   r   r   config
core_topicrespr   e	raw_itemsr   rawreel_pkr   caption_objrL   r   r   r   r   r   r   date_strrf   r   r   r"   in_rangeout_of_ranges   &&&&&                         rP   search_instagramr     s<   & W&LMM9W&FGGe\)%<=F&u-J$ZL	%PbIcHdde	fgB}}"##=>Z(&	
 	yy{ !PPTXXg%6PP$((6:JPPbI 56"456I E#t$$ cggdCGGD"$567GGK)<=	 ggi,k4((??62.DS))D77637762#67D WW/0mmCGG<N4OmmSVSZSZ[gShmmlm
WW\*//a
055A  99CGGFO99rii
B/ 77+, s# %T* 'z4B	 ggeR y3I;?CD3;HM
 k$s)5[Q[P\C]r
 	W | !T5aAfII)qy2SG2S2S5HTu:H-L9\N*CDE7E
|DE 
JJ5tJD6#e*-	./Uo  B%aS)*Wa)9)9(:"QC&@AABT Us7   *AP! #Q%9Q%Q%Q%!Q",+QQ"Q"c          
          V ^8  d   QhR\         \        \        \        3,          ,          R\        R\        R\        \        \        3,          /# )rK   video_itemsr   r   rM   )r   r   rN   r   )rO   s   "rP   rQ   rQ   =  sK     H Hd38n%HH H 
#s(^	HrR   c                   \         P                  V\         R,          4      pVR,          pV '       d   V'       d   \        '       g   / # V RV p\        R\	        V4       R24       / pV Fo  pVR,          pVP                  RR4      p	V	'       g   K(  V	P                  4       p
\	        V
4      \        8  d    R	P                  V
R\         4      R
,           p	WV&   Kq  	  V EF#  pVR,          pVP                  RR4      pV'       g   K)   \        P                  ! \         R2RV/\        V4      ^R7      pVP                  ^8X  d   VP                  4       pVP                  R4      ;'       g    . pV'       d   \        V\        4      '       dn   R	P                  R V 4       4      pV'       dK   VP                  4       p
\	        V
4      \        8  d    R	P                  V
R\         4      R
,           pWV&   EK  EK  EK   EK#  EK&  	  \        R VP!                  4        4       4      p\        RV R\	        V4       R24       V#   \         d   p\        RT RT 24        Rp?EK  Rp?ii ; i)a  Fetch transcripts for top N Instagram reels via ScrapeCreators.

Strategy:
1. Use the 'text' field (caption) as baseline
2. For top N, call /v2/instagram/media/transcript for spoken-word captions

Args:
    video_items: Items from search_instagram()
    token: ScrapeCreators API key
    depth: Depth level for caption limit

Returns:
    Dict mapping video_id -> caption text (truncated to 500 words)
r   r   NzEnriching captions for z reelsr   rL   r   rT   z...r   z/v2/instagram/media/transcriptr   transcriptsc              3      "   T FH  p\        V\        4      '       g   K  VP                  R 4      '       g   K4  VP                  R R4      x  KJ  	  R# 5i)rL   r   N)r   r   r5   ).0rb   s   & rP   	<genexpr>!fetch_captions.<locals>.<genexpr>w  s@      /3>a%a. *3455= *fb));s   AAAzTranscript fetch failed for r   c              3   8   "   T F  q'       g   K  ^x  K  	  R# 5i)   Nr   )r  vs   & rP   r  r    s     0*Aaaa*s   	
zGot captions for /)r   r5   r   r   rZ   rX   CAPTION_MAX_WORDSri   r   r   status_coder   r   listr   sumvalues)r  r   r   r  r   	top_itemscaptionsr   vidrL   r^   r   r  r   r  transcript_textr  gots   &&&               rP   fetch_captionsr#  =  s5   & e\)%<=F.)Le99	M\*I"3y>"2&	9:H :xx#4JJLE5z--xx&8'8 9:UB SM  :hhub!	<==&''EFs|#E*	D 3&yy{"hh}5;;:k4#@#@&)hh /3>/ 'O ' / 5 5 7u:(99.1hhu=O>O7P.QTY.YO(7	 ' $A; ' : 0*0
0CSE3y>"2&	9:O  	</uBqc:;;	<s,   	A$I.
I95I/AII,I''I,c                    V ^8  d   QhR\         R\         R\         R\         R\         R\        \         \        3,          /# r   r   )rO   s   "rP   rQ   rQ     sT     $A $A$A$A $A 	$A
 $A 
#s(^$ArR   c                    \        WW#V4      pVP                  R. 4      pV'       g   V# \        WdV4      pV F+  pVR,          p	VP                  V	4      p
V
'       g   K'  WR&   K-  	  RVRVP                  R4      /# )aK  Full Instagram search: find reels, then fetch captions for top results.

Args:
    topic: Search topic
    from_date: Start date (YYYY-MM-DD)
    to_date: End date (YYYY-MM-DD)
    depth: 'quick', 'default', or 'deep'
    token: ScrapeCreators API key

Returns:
    Dict with 'items' list. Each item has a 'caption_snippet' field.
r   r   r   r   )r  r5   r#  )rw   r   r   r   r   search_resultr   r  r   r   r   s   &&&&&      rP   search_and_enrichr'    s    ( %UwuMMgr*E eE2H :,,s#7&-"#	  UG]%6%6w%?@@rR   c                    V ^8  d   QhR\         \        \        3,          R\        \         \        \        3,          ,          /# )rK   responserM   )r   rN   r   r   )rO   s   "rP   rQ   rQ     s/     % %tCH~ %$tCH~:N %rR   c                &    V P                  R. 4      # )zpParse Instagram search response to normalized format.

Returns:
    List of item dicts ready for normalization.
r   )r5   )r)  s   &rP   parse_instagram_responser+    s     <<$$rR   >   r:   r=   r<   >   r:   r=   r;   )N)r   N)r   )__doc__rU   r   r   r   typingr   r   r   r   r   requestsr   ImportErrorr   r   r  	frozensetrY   r\   rc   ru   r   r   r   r   r   r  r#  r'  r+  r   rR   rP   <module>r1     s   
 
 ' 1 1  7  "B:"B:
"B:    	!#(*.046:<@	!%'-/57;=A     # %+ -2 48 :? 
	 	 	 	 #	 %)	 +/	 16	 8?	
 

 
 
  
 "(
 */
 17 	 
E8	E8	##<.4&<.4&<
(9j
!i[y %<  F@/~BHV$AN%}  Is   D 	D"!D"