
    |]1j                       S r SSKJr  SSKrSSKJrJrJrJr  SSKJ	r	  SSK
Jr  SSKJr  \	" \5      R                  5       R                   S   r\S	-  S
-  r\4S&S jjr\SS4     S'S jjr\4S(S jjr\4   S)S jjrSSS\4     S*S jjr\S:X  a  \" S\ 35        \" S\R5                  5        S\R7                  5       R8                   S35        \" 5       r\" S\" \5       35        \" 5         \" S5        \" \" SSS5      5      r\ HJ  r \ S   RC                  \" S5      5      r"\" S\"RG                  S5       S \ S!    S\ S"    S#\ S$    S%3	5        ML     gg)+z<Parse macro-book.ics and return events in a structured form.    )annotationsN)datedatetime	timedeltatimezone)Path)ZoneInfo)Calendar   z07-calendarzmacro-book.icsc                   [        U 5      nUR                  5       (       d  [        SU 35      e[        US5       n[        R
                  " UR                  5       R                  S5      5      nS S S 5        U$ ! , (       d  f       W$ = f)NzNo .ics at rbzutf-8)r   existsFileNotFoundErroropenr
   	from_icalreaddecode)ics_pathpfcals       7/home/rpi/Obsidian-Macro/scripts/data/calendar_parse.pyload_calendarr      si    XA88::+aS 122	a! **1668??7+CD 
J 
Js   4A99
Bc           
        [        U 5      n/ nUR                  S5       GH  n[        UR                  SS5      5      nUR                  S5      R                  nUR                  S5      R                  n[        U[        5      (       a@  [        U[        5      (       d+  [        UR                  UR                  UR                  5      n[        U[        5      (       a@  [        U[        5      (       d+  [        UR                  UR                  UR                  5      nUR                  c  UR                  [        R                  S9nUR                  c  UR                  [        R                  S9nUR                  S5      n	U	b?  [        U	S	5      (       a"  S
R!                  S U	R"                   5       5      O
[        U	5      n
OSn
SnU
(       a  U
R%                  S
5      O/  H:  nUR'                  S5      (       d  M   [)        UR%                  SS5      S   5      nM<     UcZ  UR-                  5       nUR'                  S5      (       a  SnO1UR'                  S5      (       a  SnOUR'                  S5      (       a  Sn[        UR                  SS5      5      nUR%                  SS5      S   nUR/                  UUUUUU
S.5        GM     Uc  Ub  U=(       d+    [        R0                  R                  [        R                  S9nU=(       d+    [        R2                  R                  [        R                  S9nU Vs/ s H  nUUS   s=::  a  U:  d  M  O  M  UPM     nnUR5                  S S9  U$ ! [*         a     GM  f = fs  snf )zReturn list of events with UTC start/end, summary, tier, categories.

window_start/window_end: filter to events whose DTSTART is in [start, end).
If None, no filtering.
VEVENTSUMMARY DTSTARTDTENDNtzinfo
CATEGORIEScats,c              3  @   #    U  H  oR                  5       v   M     g 7fNstrip.0cs     r   	<genexpr>parse_events.<locals>.<genexpr>4   s     =9a		9   tier--   [T1][T2]r   [STRUCTURAL]
structuralUID@r   )idsummarydtstart_utc	dtend_utctiercategories_rawr:   c                    U S   $ )Nr:    )es    r   <lambda>parse_events.<locals>.<lambda>V   s	    1]+    )key)r   walkstrgetdt
isinstancer   r   yearmonthdayr!   replacer   utchasattrjoinr#   split
startswithint
ValueErrorr(   appendminmaxsort)r   window_start
window_endr   out	componentr9   dtstartdtendr#   cats_strr<   r+   smuidev_idwswer@   s                      r   parse_eventsre      s    
!C
CXXh'	immIr23--	*--g&))gt$$Z-J-Jw||W]]GKKHGeT"":eX+F+FUZZeii@E>>!ooX\\o:G<<MMM6E }}\*AHvAVAVsxx=499==\_`d\eHH)1(..%r9A||G$$qwwsAq12D : <B}}V$$v&&~..#)--r*+		#q!!$

"&
 	Q (` :#9FX\\111FD8<<//x||/D=#Qq'7!<"!<q!<q#=HH+H,J7 " 2 >s$   ?M3=NNN3
NNc                    [        S5      n[        U R                  U R                  U R                  US9R                  [        R                  5      nU[        SS9-   n[        X4US9$ )zCReturn events whose start falls on the given date in Europe/Zurich.Europe/Zurichr    r1   )daysrY   rZ   r   )
r	   r   rJ   rK   rL   
astimezoner   rN   r   re   )dr   tz	day_startday_ends        r   events_for_datero   Z   sS    	/	"B!%%;FFx||TI)++GYXVVrC   c                    [        XUS9$ )Nri   )re   ri   s      r   events_in_windowrq   b   s    \S[\\rC   F   2   c           	     P   U=(       d$    [         R                  " [        R                  5      nU[	        US9-
  nU[	        U S9-
  n[        U5      n/ nUR                  S5       GH  n	U	R                  S5      R                  n
[        U
[        5      (       a@  [        U
[         5      (       d+  [        U
R                  U
R                  U
R                  5      n
U
R                  c  U
R                  [        R                  S9n
Xjs=::  a  U::  d  M  O  M  [!        U	R                  SS5      5      nU	R                  S5      R                  n[        U[        5      (       a@  [        U[         5      (       d+  [        UR                  UR                  UR                  5      nUR                  c  UR                  [        R                  S9nU	R                  S	5      nUb3  [#        US
5      (       a"  SR%                  S UR&                   5       5      OSnSnU(       a  UR)                  S5      O/  H:  nUR+                  S5      (       d  M   [-        UR)                  SS5      S   5      nM<     UcZ  UR1                  5       nUR+                  S5      (       a  SnO1UR+                  S5      (       a  SnOUR+                  S5      (       a  Sn[!        U	R                  SS5      5      nUR)                  SS5      S   nUR3                  UUUU
US.5        GM     U$ ! [.         a     M  f = f)u   Return events that ended in the [since, lookback] minutes before now.

Default window: events ending 50-70 min ago — i.e. ~1h post-event, with a
20-minute wide window so the alerter catches the event on its 5-min cron
even if a few ticks were missed.
)minutesr   r   Nr    r   r   r   r"   r#   r$   c              3  @   #    U  H  oR                  5       v   M     g 7fr&   r'   r)   s     r   r,   (events_recently_ended.<locals>.<genexpr>   s      >IqIr.   r/   r0   r1   r2   r3   r   r4   r5   r6   r7   r   )r8   r9   r:   r;   r<   )r   nowr   rN   r   r   rE   rG   rH   rI   r   rJ   rK   rL   r!   rM   rF   rO   rP   r#   rQ   rR   rS   rT   r(   rU   )lookback_minutessince_minutesrx   r   n
end_windowstart_windowr   r[   r\   r^   r9   r]   r#   r_   r<   r+   r`   ra   rb   s                       r   events_recently_endedr~   g   s    
	*X\\*AY}55Jy)9::L

!C
CXXh'	g&))eT"":eX+F+FUZZeii@E<<MMM6E.J..)--	267GmmI.11G'4((GX1N1N"7<<L~~%!///>==.D+f0E0E  >DII >>KM D-5hnnS)2=<<(("1773?1#56 > |]]_==((D]]6**D]]>22'DimmE2./CIIc1%a(EJJ"&" E (R J) & s   
L
L%$L%__main__zICS: z
  exists: z, size: z byteszTotal events: zToday (2026-06-16) in Zurich:i        r:   rg   z  z%H:%M %Zz  Tr<   r9   z  (r8   ))r   
Path | strreturnr
   )r   r   rY   datetime | NonerZ   r   r   
list[dict])rk   r   r   r   r   r   )rY   r   rZ   r   r   r   r   r   )
ry   rS   rz   rS   rx   r   r   r   r   r   )$__doc__
__future__r   sysr   r   r   r   pathlibr   zoneinfor	   	icalendarr
   __file__resolveparentsVAULTICS_PATHr   re   ro   rq   r~   __name__printr   statst_sizeeventslentodayr@   rj   zurichstrftimer?   rC   r   <module>r      s   B " 
 8 8   X ((+= #33 *2  )115/3?.?,?8B?D 5= W -5])]9C]
 35215197.7$.7>H7t z	E(
	Jx()(--/2I2I1J&
QR^F	N3v;-
()	G	
)*Dq"-.E=!,,Xo-FG6??:./s1V9+R)~SQRSWQXPYYZ[\  rC   