o
    	cja                     @   s  d dl Z d dlZd dlmZmZmZ d dlmZmZm	Z	 d dl
mZ d dlmZmZ d dlmZ edZedd	Zd
Zede de de de d	ZedZedZdedeej fddZdedeej fddZdZdZdZdZede Z ede Z!edZ"ed Z#ed!Z$ed"Z%d#ed$e&d%e&d&e&def
d'd(Z'd)ejde(fd*d+Z)d)ejde(fd,d-Z*d)ejdee&e&f fd.d/Z+d0edee& fd1d2Z,d3e&d4e&d5e&d6e&def
d7d8Z-d9edee	eee&e&e&e&ejf f  fd:d;Z.d<edeee& ee& ee& f fd=d>Z/d?ed@ee& dAee& dBee& dee&e&e&f f
dCdDZ0d?edefdEdFZ1d?edGe&dHe(dIe&dJe&defdKdLZ2d?edMe&dHe(dIe&dJe&defdNdOZ3d?edPe&dHe(dIe&dJe&de	eef fdQdRZ4d?edSe&dTe&dHe(dIe&dJe&de	eef fdUdVZ5dWed?ed3e&d4e&d5e&d6e&defdXdYZ6dZedefd[d\Z7dZede	eeeeee&e&e&e&f  f ef fd]d^Z8eG d_d` d`eZ9dS )a    N)datetime	timedeltatime)OptionalTupleUnion)Plugin)attext)register_pluginu|   (?:(\d+)年)?(?:(\d+)月)?(?:(\d+)(?:日|天))?(?:(\d+)(?:小時|小时|時|时))?(?:(\d+)(?:分鐘|分钟|分))?(?:後|后)   )minutesu   (?:日|號|号)u   (?:\d+年\d+月\d+u   |\d+年\d+月|\d+年\d+u   |\d+年|\d+月\d+u   |\d+月|\d+u   )(?!后|後)zE(?<![0-9])(?P<y>[12][0-9]{3})-(?P<mo>\d{1,2})-(?P<d>\d{1,2})(?![0-9])u3   (?<![0-9])([0-1]?\d|2[0-3])[:：]([0-5]\d)(?![0-9])sreturnc                 C   sL   g }t | }t| }|r|| |r|| |sdS t|dd dS )uI   在全文取最先出现的公历「中文片段」或「YYYY-MM-DD」。Nc                 S   s   |   S )N)start)m r   0/home/dore/onebot/Bot_Ero/plugins/group_alarm.py<lambda>(   s    z+_find_first_absolute_date.<locals>.<lambda>)key)_ISO_DATE_REsearch_ABS_DATE_REappendmin)r   candsm1m2r   r   r   _find_first_absolute_date   s   



r   restc                 C   s$   |   }t|}|r|S t|S )u^   与循环前缀互斥时：判断 rest 是否以公历绝对日期（中文或 ISO）开头。)stripr   matchr   )r   tr   r   r   r   _abs_at_line_start+   s
   

r#               u   ^每月(\d{1,2})u   ^每年(\d{1,2})月(\d{1,2})u&   ^每星期([一二三四五六日天])u@   ^每(?:周|週)(周天|周日|週日|[一二三四五六日天])u   ^每(?:日|天)u   ^每(\d+)(?:日|天)dtyearsmonthsdaysc           	      C   s   | j t| }| jt| }| j}|dkr!|d7 }|d8 }|dks|dk r1|d8 }|d7 }|dk s%t||d }t||}| j|||ddd}|tt|d S )N   r$   r   yearmonthdaysecondmicrosecondr+   )	r.   intr/   r0   calendar
monthranger   replacer   )	r(   r)   r*   r+   yr   dlastoutr   r   r   _apply_year_month_day_offsetC   s   
r<   r   c                 C   s*   | sdS |  d}ttd|d d S )NFr   z\d)groupboolrer   )r   spanr   r   r   _rel_match_validS   s   
rB   c                 C   s0   |   }t|dk rdS |d dup|d duS )ue   相对片段内是否写了「X时/…小时」或「Y分/…分钟」（与独立 HH:MM 区分）。r   Fr&   Nr'   )groupslen)r   gr   r   r   _rel_has_embedded_clockZ   s   rF   c                 C   s`   |   }t|dkr|d d urt|d nd}t|dkr*|d d ur*t|d nd}||fS )Nr&   r   r'   )rC   rD   r4   )r   rE   hamiar   r   r   _rel_embedded_hours_minutesb   s   ((rI   tokenc              	   C   sD   | sdS | dv r
dS t | dkrdS dddddd	ddd
}|| S )uQ   返回 1–7（周一…周日）。token 为「一」「日」「周天」等。N)u   周天u   周日u   週日   r$   r%   r&   r'   r      )   一   二   三   四   五   六   日u   天)rD   get)rJ   mpr   r   r   _weekday_token_to_ni   s   
rV   kindab_cc                 C   s~   | t krt|dkrdS dt|S | tkr$d}d|t|d  S | tkr2dt|t|S | tkr=dt|S dS )	Nr$   u   每天u   每{}日)rM   rN   rO   rP   rQ   rR   rS   u   每周{}u   每年{}月{}日u   每月{}日u   循环)RECUR_INTERVAL_DAYSr4   formatRECUR_WEEKLYRECUR_YEARLYRECUR_MONTHLY)rW   rX   rY   rZ   cnr   r   r   _format_recur_descu   s   ra   s0c                 C   s>  t | }|rt|d}|dk s|dkrdS t|dd|fS t| }|rPt|dt|d}}|dk s=|dkr?dS |dk sG|dkrIdS t||d|fS t| }|s\t| }|rt|d}t	|}|d	u rmd
S t
|dd|fS t| }|rtddd|fS t| }|rt|d}|dk rdS t|dd|fS d	S )u   
    若 s0 以支持的循环前缀开头，返回 (recur_kind, a, b, c, match)；
    若语法不合法返回错误字符串。
    r$      u/   「每月」后面的日须在 1–31 之间。r   r%   r,   u&   「每年」月须在 1–12 之间。u&   「每年」日须在 1–31 之间。NuW   「每周 / 每星期」后请跟周一至周日（如：每周三、每星期日）。u(   「每N日/天」的 N 须至少为 1。)_RECUR_MONTHLY_REr!   r4   r>   r_   _RECUR_YEARLY_REr^   _RECUR_WEEKLY_LONG_RE_RECUR_WEEKLY_RErV   r]   _RECUR_EVERY_DAY_REr[   _RECUR_N_DAYS_RE)rb   r   dommod_tokwdnr   r   r   _try_match_recurring   sB   






rp   fragmentc                 C   sp   d } }}t d| }|rt|d}t d| }|r$t|d}t d| }|r3t|d}|||fS )uM   从「…年…月…日」片段解析整数，未出现的部分为 None。Nu   (\d+)年r$   u   (\d+)月u   (\d+)(?:日|號|号))r@   r   r4   r>   )rq   r8   m_r9   mymmmdr   r   r   _extract_ymd_from_fragment   s   
rv   nowgygmgdc                 C   sB  | j | j| j}}}|dur |dur |dur |||}}}	n^|dur1|dur1||d}}}	nM|durB|durB|||}}}	n<|durO|dd}}}	n/|dur`|dur`|||}}}	n|durm||d}}}	n|durz|||}}}	ntd|dk s|dkrtdt||d }
tdtt|	|
}	|||	fS )uC   不完整绝对日期：缺省补当前年/月或 1 月 1 日等。Nr$   z	empty ymdr,   z	bad month)	r.   r/   r0   
ValueErrorr5   r6   maxr   r4   )rw   rx   ry   rz   y0m0d0r8   rr   r9   r:   r   r   r   _build_absolute_ymd   s*   
r   c                 C   s   | j dddS )Nr   )r1   r2   )r7   )rw   r   r   r   
_now_trunc   s   r   ro   has_timethtmc                 C   s   t | }|t|d }|r|j||ddd}d}|t | krB|dk rB|t|d }|r4|j||ddd}|d7 }|t | krB|dk s"|S )Nr3   r   hourminuter1   r2   '  r$   )r   r   r7   )rw   ro   r   r   r   basefireguardr   r   r   _first_fire_interval_days   s   r   user_wdc                 C   s   t |d }|r
|n| j}|r|n| j}||   d }|  t|d }	t|	j|	j|	j	||dd}
|
t
| kr?|
tdd }
|
S )Nr$   rK   r3   r   )r4   r   r   weekdaydater   r   r.   r/   r0   r   )rw   r   r   r   r   	target_pyhmideltar   r   r   r   r   _first_fire_weekly   s   r   rj   c                 C   s   |r|n| j }|r|n| j}| j| j}}t||d }	t||	}
zt|||
||dd}W n
 ty8   Y dS w |t	| krt|dkrK|d d}}n|d7 }t||d }	t||	}
zt|||
||dd}W |S  tys   Y dS w |S )Nr$   r   u-   「每月」对应的日期在本月无效。r,   u0   「每月」对应的日期在下一月无效。)
r   r   r.   r/   r5   r6   r   r   r{   r   )rw   rj   r   r   r   r   r   r8   r   r:   r9   r   r   r   r   _first_fire_monthly   s.   

r   r/   r0   c                 C   s   |r|n| j }|r|n| j}| j}t||d }	t||	}
zt|||
||dd}W n
 ty4   Y dS w |t| krd|d7 }t||d }	t||	}
zt|||
||dd}W |S  tyc   Y dS w |S )Nr$   r   u!   「每年」月日组合无效。u-   「每年」在下一年的该月日无效。)	r   r   r.   r5   r6   r   r   r{   r   )rw   r/   r0   r   r   r   r   r   r8   r:   r9   r   r   r   r   _first_fire_yearly  s*   

r   prevc                 C   sF  |t kr2t|}| t|d }d}|t|kr0|dk r0|t|d }|d7 }|t|kr0|dk s|S |tkr=| tdd S |tkrst|}	| j| j}
}|dkrX|
d d}
}n|d7 }t	|
|d }t
|	|}| j|
||dddS |tkrt|t|}}| jd }
t	|
|d }t
||}| j|
||dddS | tdd S )Nr3   r   r   r$   rK   r,   r-   )r[   r4   r   r   r]   r_   r.   r/   r5   r6   r   r7   r^   )r   rw   rW   rX   rY   rZ   ro   nxtrE   rj   r8   r   r:   r9   rk   dyr   r   r   _next_recurring_fire(  s6   


r   bodyc                 C   s   |   }t|}t|tr||d  d    }n4t|}t|r6|d |  d || d   }nt	|}|rN|d |  d || d   }t
d|}d| S )Nr'    )r    rp   
isinstancetupleend_REL_AFTER_REr   rB   r   r   _TIME_REsubjoinsplit)r   r   rrel_mabs_mr   r   r   _strip_patterns_for_contentF  s   

&$r   c           *   	   C   s  |   }t|}t|t}t|tr|nd }|r|S t| }|d u}|rR|\}}}	}
}|| d    }t	|}t
|rAdS t|}|rIdS d }d}d }d}nt| }t
|}|r_d nt| }|d u}|sr|sr|sr|sr	 dS t| }|szdS d\}}|rt|dt|d}}t }d }|r|\}}}}}|tkrt|||||}n<|tkrt|||||}n/|tkrt|||||}t|tr|S |}n|tkrt||||||}t|tr|S |}nd	S ||||f}n|r6t|dpd
}t|dpd
} t|dpd
}!t||| |!}t|r)t|\}"}#|t|"|#d }n|r5|j||d
d
d}n|rd| v rezt|d}$t|d}%t|d}&W n/ t t!fyd   Y dS w t"|d
\}'}(})zt#||'|(|)\}$}%}&W n t!y   Y dS w |$tj$j%k s|$dkrdS z|rt|$|%|&||d
d
}nt|$|%|&|j&|j'd
d
}W n t!y   Y dS w t(|) t*||d
d
}||krdS || t+k rdS |||fS )NuK   循环前缀不能与「…日后／…日後」紧接在同一指令中。uQ   循环前缀不能与用于定时的具体日历日期紧接在同一指令中。Fu  请至少指定「每天/每日」「每N日/天」「每周…」「每年…月…日」「每月…日」之一，或「…年…月…日…(时|小时)…(分|分钟)后」相对时间、「…年…月…日」或 YYYY-MM-DD 具体日期，或「HH:MM」时间。u*   请填写闹钟内容（不能为空）。)r,   r   r$   r%   u   不支持的循环类型。r   r&   )hoursr   r   r8   rk   r9   u0   日期不合法，请检查 YYYY-MM-DD 格式。u-   日期不合法，请检查年、月、日。i'  u   年份超出可表示范围。u`   闹钟触发时间不能早于或等于当前时刻（无日期时默认为当天该时刻）。uN   闹钟须设置在至少 5 分钟之后（距当前时刻不足 5 分钟）。),r    rp   r   r   strr   r   r   r   r!   rB   r#   r   r   r4   r>   r   rw   r[   r   r]   r   r_   r   r^   r   r<   rF   rI   r   r7   	groupdict	TypeErrorr{   rv   r   r   r.   r   r   combiner   dtime_MIN_ALARM_LEAD)*r   rb   
recur_info	has_recur	recur_errm_timer   _k_a_brZ   em
rest_afterrm0am0r   has_relr   has_abscontentr   r   rw   recurrW   rarbrc_emr   fryamadarG   rH   yyrt   ddrx   ry   rz   r   r   r   _parse_create_bodyW  s   








r   c                   @   s   e Zd ZdZdZdZdd Zdd Zdd	 Zd
e	e
e
f fddZdd Zdd Zdd Zde
fddZde
fddZdd ZdS )GroupAlarmPlugingroup_alarmu)   群聊或私聊定时闹钟：/闹钟 …Nc                 C   s$   |dkr|   S |dkr|  S dS )NmessagemetaF)_match_text_command_should_scan_alarms)self
event_typer   r   r   r!     s
   zGroupAlarmPlugin.matchc                 C   sh   | j jsdS | j jd }|ddkrdS |d d  }|dr*d|dd   }|d	p3|d
S )NFr   typer
   data   ／/r$      /闹钟   /鬧鐘)	bot_eventr   rT   r    
startswith)r   r~   r"   r   r   r   r     s   
z$GroupAlarmPlugin._match_text_commandc                 C   s*   t  }|d}tj|krdS |t_dS )N%Y-%m-%d %H:%MFT)r   rw   strftimer   _last_alarm_scan_minute)r   rw   r   r   r   r   r     s   

z$GroupAlarmPlugin._should_scan_alarmsr   c                 C   sl   | j jd d d  }|drd|dd   }|dr*d|tdd   fS d|tdd   fS )	Nr   r   r
   r   r   r$   r   r   )r   r   r    r   rD   )r   rawr   r   r   _command_body  s   

zGroupAlarmPlugin._command_bodyc                 C   s   | j jdkr|   d S | j jr| j jd ddkrd S |  \}}|s+|   d S |d dd }|dv r=|   d S |dv rR|t	|d  
 }| | d S | | d S )N
meta_eventr   r   r
   r$   )u   一览u   一覽u   清單u   清单)u   取消u   撤銷)r   	post_type_handle_meta_duer   rT   r   _send_usager   _handle_listrD   r    _handle_cancel_handle_create)r   _r   firstr   r   r   r   handle  s$   
zGroupAlarmPlugin.handlec                 C   s   | j td d S )Nu  用法：
· 「X年X月X日」无「后」— 具体日历日，可只写年/月/日或任意组合（缺省补当前年、月或 1 日）；亦可用 YYYY-MM-DD（与「YYYY年MM月DD日」等价）。
· 「X年X月X日X时/小时X分/分钟后」— 相对当前时刻的偏移；未写的年/月/日/时/分视为 0；可与独立 HH:MM 并存，若本段内写了时/分则以本段为准。
· 任意闹钟的触发时刻须距当前至少满 5 分钟（不足 5 分钟不可设，刚好 5 分钟可以）。
· 循环（须写在开头，且不能与紧接的「…日后」或定时用具体日历日混用）：
  「每天」「每日」— 等价于每 1 天；「每N日」或「每N天」— 每隔 N 天；「每周一」…「每周日」或「每星期一」…「每星期日」；
  「每年M月D日」；「每月D日」。
· 可同时写 HH:MM；无时间时，具体日/循环为当天当前时刻；相对「…后」若未写时/分，则为偏移后沿用当前时刻（否则以段内时/分为准）。
· /闹钟 HH:MM 内容 — 无日期时，为当天该时刻；若该时刻已过则无法设置。
须至少包含上述之一，且必须有文字内容。
群聊与私聊均可设置；到点后在原会话中提醒。
/闹钟、/鬧鐘 一览／一覽／清單 — 查看本人待触发闹钟
/闹钟、/鬧鐘 取消／撤銷 <编号> — 取消对应闹钟（仅本人创建）；亦可用全形「／」代替「/」。)apisend_msgr
   )r   r   r   r   r     s
   zGroupAlarmPlugin._send_usagec              	   C   s  | j j}| j j}| j||}|s| jtd d S g }|D ][\}}}}}	}
}}t|dkr1|n|d d d }|p<dd d }t	|pEdrpt	|	pKddkrpt
t	|	t	|
pWdt	|p\dt	|pad}|d|||| q|d||| q| jtd	d
|  d S )Nu!   你还没有待触发的闹钟。(   u   …    r   u   #{} · {} · {} · {}u   #{} · {} · {}u   待触发闹钟：

)r   group_iduser_id	dbmanagerlist_pending_alarms_for_userr   r   r
   rD   r4   ra   r   r\   r   )r   giduidrowslinesridfatcis_recrkr   r   r   previewtnextrecr   r   r   r     s    *zGroupAlarmPlugin._handle_listr   c                 C   sn   |  s| jtd d S t|}| j|| jj| jj	}|r-| jtd
| d S | jtd d S )Nuf   请使用：/闹钟 取消 <编号> 或 /鬧鐘 撤銷 <编号>（编号见「一览／一覽」）。u   小埃已经取消闹钟 #{}。uH   取消失败：编号不存在、已触发或不是你创建的闹钟。)isdigitr   r   r
   r4   r   cancel_group_alarmr   r   r   r\   )r   r   aidokr   r   r   r   $  s   zGroupAlarmPlugin._handle_cancelr   c              	   C   s   t |}t|tr| jt| d S |\}}}| jjd u }| jj	| jj
||| jj||d}|rA|\}}	}
}dt||	|
|}nd}| jtd||d|| d S )N)
is_privater   u   （{} 循环）r   uH   小埃记住了，已设置闹钟 #{}，将于 {} 提醒你{}：「{}」r   )r   r   r   r   r   r
   r   r   r   add_group_alarmr   r\   ra   r   )r   r   parsedr   clean_contentr   is_privr  krX   rY   r   extrar   r   r   r   /  s2   

zGroupAlarmPlugin._handle_createc              	   C   s  | j }t }||D ]}|d }|d }|d }|d }|d }t|d p(d}	t|d p0d}
t|d p8d}t|d	 p@d}t|d
 pHd}t|d pPd}|pUdd d }d||}|
r|dkr|	rx| jdt|t|fd n| jdt|t	t|tdt|fd t
|d}t||||||}|||| q||sq|	r| jdt|t|fd q| jdt|t	t|tdt|fd qd S )Nr   r$   r%   r&   r'   r   rL   rK      	   
   r   r   u2   预约「{}」的小埃提醒服务来了喵： {}send_private_msg)r   r   send_group_msgr   )r   r   z%Y-%m-%d %H:%M:%S)r   r   rw   get_due_alarmsr4   r\   r   call_apir
   r	   strptimer   try_advance_recurring_fire_attry_mark_alarm_fired)r   dbrw   rowr  r   creator_uidr   r   r  r   r   r   r   r   
when_labellineprev_dtr   r   r   r   r   K  sZ   
z!GroupAlarmPlugin._handle_meta_due)__name__
__module____qualname__namedescriptionr   r!   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r     s    r   ):r5   r@   r   r   r   r   typingr   r   r   	core.baser   core.cqr	   r
   
core.utilsr   compiler   r   _ABS_DAYr   r   r   r   Matchr   r#   r[   r]   r^   r_   rd   re   rf   rg   rh   ri   r4   r<   r?   rB   rF   rI   rV   ra   rp   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s    

	



.((

"



&4g