
    AQj8                       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	Z	d dl
Z
d dlmZ d dlmZmZ d dlmZ d dlmZ d dlmZmZ d dlmZ d d	lmZ  ed
      Z ed      Z ed      ZdZ ed       G d d             ZddZd dZ d!dZ!d"dZ"d#dZ#d$dZ$d%dZ%	 	 	 	 	 	 	 	 	 	 	 	 	 	 d&dZ&d'dZ'd(dZ(d)dZ)d*dZ*e+dk(  r e, e*             y)+    )annotationsN)	dataclass)datetimetimezone)Path)Any)hashesserialization)ec)decode_dss_signaturez$bilibili_latest_videos_259655230.csvzapns_device_tokens.txtz.apns_csv_monitor_state.json
   T)slotsc                  R    e Zd ZU ded<   ded<   ded<   ded<   ded<   ed
d       Zy	)
APNsConfigstrteam_idkey_id	bundle_idr   auth_key_pathenvironmentc                $    | j                   dk(  ryy)N
productionzhttps://api.push.apple.comz"https://api.sandbox.push.apple.com)r   )selfs    apns_csv_monitor.pyhostzAPNsConfig.host%   s    |+/3    N)returnr   )__name__
__module____qualname____annotations__propertyr    r   r   r   r      s/    LKN4 4r   r   c                h    t        j                  |       j                  d      j                  d      S )N   =ascii)base64urlsafe_b64encoderstripdecode)datas    r   	base64urlr,   ,   s)    ##D)006==gFFr   c                   t        j                  | j                  j                         d       }t	        |t
        j                        st        d      d| j                  d}| j                  t        t        j                               d}t        t        j                  |d      j                                dt        t        j                  |d      j                                }|j!                  |j                  d	      t        j"                  t%        j&                                     }t)        |      \  }}|j+                  d
d      |j+                  d
d      z   }| dt        |       S )N)passwordz'APNs auth key must be an EC private keyES256)algkid)issiat,:)
separators.r&       big)r
   load_pem_private_keyr   
read_bytes
isinstancer   EllipticCurvePrivateKey	TypeErrorr   r   inttimer,   jsondumpsencodesignECDSAr	   SHA256r   to_bytes)	configprivate_keyheaderclaimssigning_inputder_signaturersraw_signatures	            r   	build_jwtrR   0   s*   44'')K k2#=#=>ABBV]]3F^^C		,<=FTZZ:>EEGH
ITZZ:>EEGH
I	K   $$]%9%9'%BBHHV]]_D]^M.DAqJJr5)AJJr5,AAM_Ai6788r   c                    | j                         sg S g }| j                  d      j                         D ]8  }|j                         }|s|j	                  d      r(|j                  |       : |S )Nutf-8encoding#)exists	read_text
splitlinesstrip
startswithappend)pathtokenslinetokens       r   read_tokensrb   D   sa    ;;=	F0;;=

))#.MM%  > Mr   c                d    t        j                  | j                               j                         S )N)hashlibsha256r<   	hexdigest)csv_paths    r   csv_hashrh   O   s#    >>(--/0::<<r   c                @   | j                  ddd      5 }t        j                  |      }t        |      }d d d        sy|d   }|j	                  dd      j                         }|j	                  dd      j                         }|rd	| nd}|d|fS # 1 sw Y   _xY w)
NrO   z	utf-8-sig )rV   newline)rj   rj   rj   titlepublish_timeu   发布时间：)opencsv
DictReaderlistgetr[   )rg   filereaderrowslatestrm   rn   bodys           r   latest_video_payloadry   S   s    	s["	=%F| 
> "XFJJw#))+E::nb1779L/;_\N+D"d? 
>	=s   !BBc                    | j                         si S 	 t        j                  | j                  d            S # t        j                  $ r i cY S w xY w)NrT   rU   )rX   rB   loadsrY   JSONDecodeError)r^   s    r   
load_stater}   a   sI    ;;=	zz$..'.:;; 	s   $9 AAc                V    | j                  t        j                  |dd      d       y )NF   )ensure_asciiindentrT   rU   )
write_textrB   rC   )r^   states     r   
save_stater   j   s    OODJJu5CgOVr   c                L   d|i}|r||d<   |r||d<   d|ddi}| j                    d| }dd	d
dd|dd| dd| j                   dddddddt        j                  |dd      ddg}	t	        j
                  |	ddd      }
|
j                  j                         }|r|j                         d   nd}dj                  |j                         d d       }|
j                  dk7  s|j                  d      s2t        d |d d!  d"| d#| d$|
j                  j                                y )%Nrm   subtitlerx   apsdefault)alertsoundz
/3/device/curlz--http2z-sSz-XPOSTz-Hzauthorization: bearer zapns-topic: zapns-push-type: alertzapns-priority: 10zcontent-type: application/jsonz-dFr4   )r   r7   z-wz
%{http_code}T)checkcapture_outputtextrl   000
r   2zAPNs failed for token    z... status=z stdout=z stderr=)r   r   rB   rC   
subprocessrunstdoutr[   rZ   join
returncoder\   RuntimeErrorstderr)rI   jwtdevice_tokenrm   r   rx   r   payloadurlcommandresultoutputstatusresponse_bodys                 r   send_apns_notificationr   n   s}    %e,E$jf 	
G [[ML>
2C
 &
v''()(

7:F)G, ^^G5DQF]]  "F(.V $EFIIf//1#267MAV%6%6s%;$\#2%6$7{6( K#_HV]]-@-@-B,CE
 	
 &<r   c            
        dD  cg c]#  } t         j                  j                  |       s| % }} |rt        ddj	                  |             t        t         j                  d   t         j                  d   t         j                  d   t        t         j                  d         j                         t         j                  j                  dd	      
      S c c} w )N)APNS_TEAM_IDAPNS_KEY_IDAPNS_BUNDLE_IDAPNS_AUTH_KEY_PATHu   缺少环境变量：z, r   r   r   r   APNS_ENVIRONMENTdevelopment)r   r   r   r   r   )osenvironrs   
SystemExitr   r   r   
expanduser)namemissings     r   build_config_from_envr      s     \[Dzz~~d# 	[  
 071C0DEFF

>*zz-(**-.2::&:;<GGIJJNN#5}E s   (Cc                 B   t        j                  d      } | j                  dt        t        d       | j                  dt        t
        d       | j                  dt        t        d	       | j                  d
t        t        d       | j                  ddd       | S )Nu9   监控 CSV 文件变更，并通过 APNs 推送到 iPhone)descriptionz--csvu   要监控的 CSV 文件)typer   helpz--tokensu   APNs device token 列表z--stateu&   存储上次 CSV 哈希的状态文件z
--intervalu   检查间隔秒数z--once
store_trueu   只检查一次)actionr   )	argparseArgumentParseradd_argumentr   DEFAULT_CSV_PATHDEFAULT_TOKENS_PATHDEFAULT_STATE_PATHr@   DEFAULT_INTERVAL_SECONDS)parsers    r   build_parserr      s    $$1lmF
d4DKde

7JQkl
	6HOwx
38PWkl
<MNMr   c           	        | j                   j                         j                         }|j                         st	        |      t        |      }t        | j                        }|j                  d      }||k(  r1t        t        j                         j                  d       d       y |[||d<   t        j                  t        j                        j                         |d<   t        | j                  |       t        d       y t!        | j"                        }|st        d| j"                          y t%        |      \  }}}	|st        d       y t'        |      }
|D ]  }t)        ||
||||	        ||d<   t        j                  t        j                        j                         |d<   t        | j                  |       t        d	t+        |       d
       y )Nrh   seconds)timespecu    CSV 未变化
updated_atu5   首次运行，已建立 CSV 基线，不发送通知uN   CSV 已变化，但没有 device token。请把 app 中复制的 token 放入 u:   CSV 已变化，但未找到视频标题，不发送通知u   CSV 已变化，已推送 u
    台设备)rp   r   resolverX   FileNotFoundErrorrh   r}   r   rs   printr   now	isoformatr   utcr   rb   r_   ry   rR   r   len)argsrI   rg   current_hashr   previous_hashr_   rm   r   rx   r   ra   s               r   run_oncer      s   xx""$,,.H??))H%Ltzz"EIIj)M$))9)=>nMN(j&ll8<<8BBDl4::u%EF%F^_c_j_j^klm0:E8TJK
F
CvsE5(DI $E*",,x||4>>@E,tzz5!	&s6{m:
>?r   c                 $   t               j                         } t               }	 	 t        | |       | j                  ryt        j                  | j                         :# t        $ r(}t        d| t        j                         Y d }~Yd }~ww xY w)Nu	   错误：)rt   r   )r   
parse_argsr   r   	Exceptionr   sysr   oncerA   sleepinterval)r   rI   excs      r   mainr      sw    >$$&D"$F
	6T6" 99

4==!   	6IcU##**55	6s   A 	B'B

B__main__)r+   bytesr   r   )rI   r   r   r   )r^   r   r   z	list[str])rg   r   r   r   )rg   r   r   ztuple[str, str, str])r^   r   r   dict[str, Any])r^   r   r   r   r   None)rI   r   r   r   r   r   rm   r   r   r   rx   r   r   r   )r   r   )r   zargparse.ArgumentParser)r   zargparse.NamespacerI   r   r   r   )r   r@   )-
__future__r   r   r'   rp   rd   rB   r   r   r   rA   dataclassesr   r   r   pathlibr   typingr   cryptography.hazmat.primitivesr	   r
   )cryptography.hazmat.primitives.asymmetricr   /cryptography.hazmat.primitives.asymmetric.utilsr   r   r   r   r   r   r,   rR   rb   rh   ry   r}   r   r   r   r   r   r   r   r   r#   r   r   <module>r      s!   "   
   	  
  ! '   @ 8 P >? 34 89   4 4 4G9(=W3
3
	3
 3
 	3

 3
 3
 
3
l$#@L" z
TV
 r   