U
    s1Ùj˜9  ã                   @   s(  d 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 ddlm	Z	 ddl
Z
ddlZddlmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ e d¡Zeeeeƒ d¡ƒƒZej  d¡dkZ!dd„ Z"dd„ Z#dd„ Z$dd„ Z%dd„ Z&dd„ Z'dd„ Z(e)dœdd „Z*dd!œd"d#„Z+dS )$zsHermes LMP V5 runtime. Python 3.8+. No credentials stored here.
Safe by default: dry-run unless HERMES_LMP_LIVE=1.
é    N)ÚdatetimeÚ	timedelta)ÚPath)Úurlsplit)ÚasociarÚidentificar)Úvalidar_asociaciones)Úobtener_inventario)Úextraer_playlist)Ú
planificar)Ú
StateStorezAmerica/Tijuanazhermes_lmp_v5_live_state.jsonZHERMES_LMP_LIVEÚ1c              	      s¬   t j| d |d| | d dœdddd ˆ ¡igd	œd
d�}| ¡  | ¡ }dd„ | dg ¡D ƒ}t|ƒdkrrtdƒ‚‡ fdd„|d  dg ¡D ƒ}t|ƒtˆ ƒkr¨tdƒ‚|S )Nú/api/actionúapplication/jsonz/config/lmp©ÚAuthorizationzContent-TypeZOriginZRefererZ	getstatusÚlmpÚIdú,)ÚActionÚ
ProviderIdÚStreamsé   ©ÚheadersÚjsonÚtimeoutc                 S   s   g | ]}|  d ¡dkr|‘qS )r   r   ©Úget)Ú.0Úp© r!   ú"hermes_lmp_v5_runtime_corregido.pyÚ
<listcomp>    s      z_getstatus.<locals>.<listcomp>Z	Providersé   zProveedor LMP ambiguoc                    s$   i | ]}|  d ¡ˆ kr|d  |“qS )r   r   ©r   Úc©Úidsr!   r"   Ú
<dictcomp>#   s       z_getstatus.<locals>.<dictcomp>r   r   z#Inventario y getstatus no coinciden)	ÚhttpxÚpostÚjoinÚraise_for_statusr   r   ÚlenÚRuntimeErrorÚset)ÚhostÚauthr(   ÚresponseÚdataZ	providersÚfoundr!   r'   r"   Ú
_getstatus   s(    
  þÿür6   c           
         sÊ   t j| d d|idd�}| ¡  dd„ t|jƒD ƒ}i }| ¡ D ]d\}}t|ƒ‰ ‡ fdd„|D ƒ}t|ƒdkrztd	| ƒ‚|d
 d }	t	|	ƒj
dkrœtdƒ‚|	||< q@tt| ¡ ƒƒt|ƒkrÆtdƒ‚|S )Nz/playlist.m3ur   é   )r   r   c                 S   s&   g | ]}|d    ¡  ¡  d¡r|‘qS )Únamez[lmp])ÚstripÚlowerÚ
startswithr%   r!   r!   r"   r#   ,   s    ÿz'_validated_playlist.<locals>.<listcomp>c                    s,   g | ]$}t ˆ ƒd krt|d ƒˆ kr|‘qS )é   r8   )r.   r   r%   ©Zteamsr!   r"   r#   1   s       r$   zM3U ambigua para r   Úurl)ZhttpZhttpszURL invalidazURLs duplicadas)r*   r   r-   r
   ÚtextÚitemsr   r.   r/   r   Zschemer0   Úvalues)
r1   r2   Ú	inventoryr3   ZchannelsÚresultÚcidr8   Úmatchesr>   r!   r=   r"   Ú_validated_playlist)   s     
rF   c                 C   s`   |d| | d dœ}dD ]:}t j| d ||ddœdd	�}| ¡  |d
krt d¡ qt d¡ d S )Nr   z/config/lmp?type=liver   )ÚchannelsupdaterequestZchannelsupdateapplyr   r   )r   r   r   r   rG   é   )r*   r+   r-   ÚtimeÚsleep)r1   r2   r   Úactionr3   r!   r!   r"   Ú_refresh_provider=   s     ÿ ÿrL   c                 C   st   t |  dd¡ƒt |  dd¡ƒ }}t|ƒdksJt|ƒdksJt||B ƒdkrNd S t|  dd¡ƒd d t||B ƒ¡ S )NZawayTeamShortÚ ZhomeTeamShortr$   r<   ÚlocalFullDateú|)r   r   r.   Ústrr,   Úsorted)ÚgameZawayÚhomer!   r!   r"   Ú_keyI   s    "(rT   c           	      C   sð   | d }|D ]Þ}|d }|  d¡}| |dd dd g dddœ¡}|d |d	< | ¡ |d
< |dkrª|  d¡dkr€| ¡ |d< d|d< d|d< |  dd¡d |d< | ¡ |d< q|dkrÌd|d< d|d< d |d< q|dkr|  d¡dkrd|d< qdS )NÚgamesÚ_hermes_keyZ
gameStatusÚunknownr   F)ÚstatusÚfirst_final_seenÚfinal_confirmationsÚlast_final_seenÚstart_attemptsÚpreparedÚstop_confirmedÚ_hermes_channelÚ
channel_idÚ	last_seenr<   rX   ÚfinalrY   rZ   r$   r[   ÚliveZ	scheduledT)r   Ú
setdefaultÚ	isoformat)	r4   r]   Z
status_mapÚnowrU   rR   ÚkeyÚcodeÚrecr!   r!   r"   Ú_apply_observationP   s6    

  ý

rj   c                  C   sL   t j ¡ sdi iS t t jjdd�¡} t| tƒr@t|  d¡tƒsHt	dƒ‚| S )zDNever silently replace damaged persistent state with an empty state.rU   zutf-8)ÚencodingzEstado V5 invalido)
ÚSTATEÚpathÚexistsr   ÚloadsZ	read_textÚ
isinstanceÚdictr   Ú
ValueError)r4   r!   r!   r"   Ú_strict_snapshotn   s    
rs   c                 C   sê  t ƒ d }| ¡ D �]Ð\}}| d¡}| |¡}	|	dkr:q|	 d¡}
| dg ¡}|�r"|d  d¡dk�r"|d }z|t |d	 ¡  ¡ }W n& tttfk
r²   td
| ƒ‚Y nX |
dkræ||d fdd„}t	 
|¡ |d| ƒ n<|
dk�r"|dk�r"||d fdd„}t	 
|¡ |d| ƒ | d¡�p0i }| d¡dkrz|t |d	 ¡  ¡ }W n( tttfk
�r‚   td| ƒ‚Y nX |
dk�r²|fdd„}t	 
|¡ |d| ƒ q|
dkr|dkr|fdd„}t	 
|¡ |d| ƒ qdS )zJResolve uncertain commands from observed O11 state, not from HTTP outcome.rU   r`   NÚRunningr\   éÿÿÿÿrX   ©ÚreservedÚsentrI   z$Intento pendiente sin fecha valida: TÚattemptc                 S   s<   | d | d d }|  d¡|kr8|  d¡dkr8d|d< d S )NrU   r\   ru   ry   rX   rv   Ú	confirmedr   ©ÚdÚkZnumberÚar!   r!   r"   Úconfirm‰   s    z#_reconcile_pending.<locals>.confirmzHERMES V5 RECUPERADO START FéZ   c                 S   s<   | d | d d }|  d¡|kr8|  d¡dkr8d|d< d S )NrU   r\   ru   ry   rX   rv   Úunconfirmedr   r{   r!   r!   r"   Úfail‘   s    z _reconcile_pending.<locals>.failzHERMES V5 START NO CONFIRMADO Ústop_operationz!STOP pendiente sin fecha valida: c                 S   s<   | d | }|  d¡pi   d¡dkr8d|d d< d|d< d S )NrU   rƒ   rX   rv   rz   Tr^   r   ©r|   r}   Úrr!   r!   r"   Ústop_okž   s    z#_reconcile_pending.<locals>.stop_okzHERMES V5 RECUPERADO STOP c                 S   s4   | d | }|  d¡pi   d¡dkr0d|d d< d S )NrU   rƒ   rX   rv   r�   r   r„   r!   r!   r"   Ú	stop_fail¦   s    z%_reconcile_pending.<locals>.stop_failzHERMES V5 STOP NO CONFIRMADO )rs   r@   r   r   ÚfromisoformatÚtotal_secondsrr   Ú	TypeErrorÚKeyErrorrl   Ú
actualizar)r1   r2   Ústatusesrf   ÚlogÚsnapshotrg   ri   rD   ÚchannelÚrunningÚattemptsÚlastZager   r‚   Ústopr†   r‡   r!   r!   r"   Ú_reconcile_pendingx   sH    








r•   )rŽ   c          "   	      s:  t  t¡‰|d  d¡|d  }}| d  dg ¡| d  dg ¡ }t||ƒ}t||t|ƒƒ‰t||ƒ}i }	ˆ 	¡ ˆt
dd�  	¡ fD ]}
|	 t||||
 ¡ ƒ¡ q„g ‰|D ]<}t|ƒ‰ˆ|	krªt|ƒ}ˆ|	ˆ  |d	< |d
< ˆ |¡ qªˆsø|dƒ dS t ‡‡‡fdd„¡ t||ˆˆ|ƒ tƒ d }d}ˆD �]”}|d	 |d
  ‰}t  |d  dd¡¡}|jdk�rxtj|dd�}|t
dd� ˆ  k�r¤|t
dd� k�sªn �q0|ˆ }| d¡�s0| d¡dk�rÒ�q0t�r|�st||ƒ t||ƒ}t||t|ƒƒ‰d}t|||ƒ}t||ƒ}| ˆ¡|k�r8tdˆ ƒ‚|ˆ }t�r||d  ¡ D ](\}}|t|| ƒk�rR|| |d< �qRt�rª||	ˆ< ||d
< t ˆ|f‡fdd„	¡ |dˆ t�r¼d nd! ƒ �q0tƒ d }i }ˆD ]P}|d	 ‰|ˆ }| d"|d
 ¡}ˆ |i ¡}t|| d#¡| d$¡d%�|ˆ< �qÚtˆ|	|ˆƒ}|D �]ô}|d& |d'  ‰}|ˆ }|| d"¡k�s>| d¡�s~�q>|d( d)k�r¶| d*g ¡}|�r¶|d+  d¡d,k�r¶�q>|d( d-k�rÔ| d.¡�rÔ�q>|d( d-k�r$| d/d0¡d1k �rø�q>| d2¡}|�r>ˆt  |¡   ¡ d3k�r$�q>t�sF|d4|d(  d5 ˆ ƒ �q>d0d6l!m"} | d7¡‰ ˆ �r„‡ ‡‡fd8d9„}t |¡�s¢�q>n‡‡fd:d;„}t |¡�s¢�q>|||dd<� #|d( |¡ t|||gƒ|  d#¡}|d( d)k} || k	�rtd=|d(  d5 | ƒ‚‡ ‡fd>d?„}!t |!¡ |d@|d(  d5 ˆ ƒ �q>dS )AzBOne synchronous scheduler tick; does not start a second scheduler.r1   ú/r2   r3   rU   Z	prevGamesr$   )ZdaysrV   r_   z1HERMES V5: sin asociaciones validas; sin accionesNc                    s   t | ˆˆˆ ƒS )N)rj   )r|   )rf   r]   r�   r!   r"   Ú<lambda>Ã   ó    ztick.<locals>.<lambda>FrN   ÚZz+00:00©Zis_dsté
   ©Zminutesr7   r]   rX   rb   Tz'Canal cambiado o ausente tras refresh: r   Zregionalc                    s   | d |   d|ˆ  ¡ dœ¡S )NrU   T)r]   r`   Zprepared_at)Úupdatere   )r|   r}   r&   ©rf   r!   r"   r—   ä   s   ÿz HERMES V5: preparacion validada z LIVEz DRYr`   rt   ZOnDemand)r‘   ZondemandrR   r�   rK   Ústartr\   ru   rv   r”   r^   rZ   r   r<   r[   é,  zHERMES V5 DRY ú )Ú
O11Actionsry   c                    sF   | d ˆ }t | dg ¡ƒˆ d kr(dS |d  ˆ dˆ ¡ dœ¡ dS )NrU   r\   r$   Frw   )ry   rX   rI   T)r.   r   Úappendre   )r|   r…   )ry   rg   rf   r!   r"   Úreserve  s    ÿztick.<locals>.reservec                    sP   | d ˆ  }|  d¡rdS |  d¡p&i }|  d¡dkr:dS dˆ ¡ dœ|d< d	S )
NrU   r^   Frƒ   rX   )rw   rx   rz   rw   )rX   rI   T)r   re   )r|   r…   Úop)rg   rf   r!   r"   Úreserve_stop  s    
ztick.<locals>.reserve_stop)Zdry_runzO11 no confirmo c                    sL   | d ˆ }ˆ r4|d d }|  d¡ˆ krHd|d< nd|d d< d|d	< d S )
NrU   r\   ru   ry   rz   rX   rƒ   Tr^   r   )r|   r…   r~   )ry   rg   r!   r"   r   "  s    
ztick.<locals>.confirmzHERMES V5 CONFIRMADO )$r   rf   ÚTZÚrstripr   r	   r6   Úlistr   Údater   r�   r   re   rT   rq   r£   rl   rŒ   r•   rs   rˆ   ÚreplaceÚtzinfoÚlocalizeÚLIVErL   rF   r/   r@   r   r   r‰   Zhermes_lmp_actionsr¢   Zejecutar)"ZepgZpanelZstream_databaserŽ   r1   r2   rU   rB   rE   ZvalidZdayrR   Úgr�   Zrefreshed_this_tickrD   rŸ   ri   ZlinksZcurrentÚslugZdbZstatesr�   ZactionsrK   r’   r“   r¢   r¤   r¦   ZverifiedZdesiredr   r!   )ry   rg   rf   r]   r�   r"   Útick®   sÄ    
 



.



"


	
	
r±   rž   c                C   s8  t sdS |pt t¡}�ztƒ }|d  ¡ D ]ê\}}| | d¡dd… krLq,| d¡s,| d¡sbq,t | d¡d ¡}|j	dkrŽtj
|dd	�}||td
d� k r¢q,||tdd� kr¼ W dS | d¡dkr,| d¡}|r,t |¡}|j	dk	r,d||  ¡   k�r
dkr,n q, W dS q,W n tk
�r2   Y dS X dS )z3Fail closed for LMP only when live mode is enabled.TrU   rO   r$   Nr^   r]   r   rš   r›   rœ   é   )ZhoursrX   rc   ra   r    F)r®   r   rf   r§   rs   r@   Úsplitr   rˆ   r¬   r­   r   r‰   Ú	Exception)r°   rf   r4   rg   rR   rŸ   ÚseenZobservedr!   r!   r"   Úaccess_allowed/  s4    


,r¶   ),Ú__doc__Úosr   rI   r   r   Úpathlibr   Zurllib.parser   r*   ZpytzZhermes_lmp_matcherr   r   Zhermes_lmp_guardr   Zhermes_lmp_inventoryr	   Zhermes_lmp_playlistr
   Zhermes_lmp_coordinatorr   Zhermes_lmp_v5_stater   Útimezoner§   rP   Ú__file__Z	with_namerl   Úenvironr   r®   r6   rF   rL   rT   rj   rs   r•   Úprintr±   r¶   r!   r!   r!   r"   Ú<module>   s6   

6 