
    j$                        d 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
mZmZ dZdZej                            ej                            e                    Zej                            ed          Z ej        ed           d	 Zd
 Zd#dZd Zd Zd Zd Zd$dZdddddZd Z d%dZ!d&dZ"d Z#d&dZ$d'd Z%d! Z&d" Z'dS )(aO  Digitain/StatsInfo client (the stats widget behind betfa.com).

Reverse-engineered from livescore2 bundle, verified 2026-09-15:
  base = https://d3skketn98dcjt.cloudfront.net/apiv3/  (+ o=dt & guid=<partner>)
  feed/1/<YYYY-MM-DD>/        games for a date (upcoming + finished, scores)
  game/1/<gameId>/            match detail (lineups/preview close to kickoff)
  h2h/1/<minId>vs<maxId>/     mutual meetings, per-team recent, over/under

Context is BONUS data: every function fails soft (returns None / skips) so the
picks pipeline never depends on this site being up or its ids matching.
    N)datetime	timedeltatimezonez,https://d3skketn98dcjt.cloudfront.net/apiv3/z$c0ad5b29-6f4b-4bf1-a364-688531850e24z.cacheT)exist_okc                    t           j                            t          dt	          j        |                                                                           z   dz             }t           j                            |          rt          j	                    t           j        
                    |          z
  |k     rM	 t          |          5 }t          j        |          cd d d            S # 1 swxY w Y   n# t          $ r Y nw xY w	  |            }n# t          $ r Y d S w xY w	 t          |dz   d          5 }t          j        ||           d d d            n# 1 swxY w Y   t          j        |dz   |           n# t          $ r Y nw xY w|S )Nsi_z.jsonz.tmpw)ospathjoin	CACHE_DIRhashlibmd5encode	hexdigestexiststimegetmtimeopenjsonload	Exceptiondumpreplace)keyttl_sfetchr   fdatas         3/root/.hermes/scripts/sports-predictor/statsfeed.py_cacher!      s   7<<	57;szz||+D+D+N+N+P+P#PSZ#Z[[D	w~~d 	bg.>.>t.D.D Du L L	d $qy||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 	 	 	D	uww   tt$-%% 	IdA	 	 	 	 	 	 	 	 	 	 	 	 	 	 	

4&=$''''   Ks~   9C5 C)C5 )C--C5 0C-1C5 5
DD
D 
DD#E< 6EE< EE< E E< <
F	F	c                 R    t            |  dt           t          | |fd          S )Nz?o=dt&guid=c                  "    t                     S N)_get)urls   r    <lambda>z_api.<locals>.<lambda>4   s    tCyy     )BASEGUIDr!   )itemr   r&   s     @r    _apir,   2   s7    
*4
*
*D
*
*C$0000111r(      c                 6   t           j                            | dddd          }t           j                            ||          5 }t	          j        |                                                    dd                    cd d d            S # 1 swxY w Y   d S )	NzMozilla/5.0zhttps://statsinfo.co/zapplication/json)z
User-AgentRefererAccept)headers)timeoututf-8r   )urllibrequestRequesturlopenr   loadsreaddecode)r&   r2   reqrs       r    r%   r%   7   s    
.
 
 #0G$/& /&
  ' 'C 
		W		5	5 ?z!&&((//'9==>>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?s   :BBBc                     t          j        dt          | pd                    } d                    d | D                                                       } t          j        dd|                                           S )NNFKD c              3   B   K   | ]}t          j        |          |V  d S r$   )unicodedata	combining).0cs     r    	<genexpr>z_norm.<locals>.<genexpr>A   s2      ==aK$9!$<$<=======r(   z
[^a-z0-9]+ )rA   	normalizestrr   lowerresubstrip)ss    r    _normrN   ?   sj    fc!'rll33A
==1=====CCEEA6-a((..000r(   c                     t          |           t          |          }} | r|sdS | |v s|| v rdS t          j        d | |                                          S )Ng        g      ?)rN   difflibSequenceMatcherratio)abs     r    _similarrU   E   sb    88U1XXqA A sAvvas"4A..44666r(   c                     t          d|  d| t                      k    rdnd          }|r(t          |                    d          t                    si S |d                             di           pi S )z]All games for a date: {gid: {side1, side2, side1Id, side2Id, score1, score2, status, dateT}}.zfeed/1//`T  i:	 responsegame)r,   _today
isinstancegetdict)dayds     r    feed_dayra   N   sv    s3&((??xx	JJA JquuZ00$77 	Z=VR((.B.r(   c                  d    t          j        t          j                                      d          S )N%Y-%m-%d)r   nowr   utcstrftime r(   r    r[   r[   V   s"    <%%..z:::r(      c                    g }t          d| dz             D ]}t          j        t          j                  t          |          z
                      d          }t          |                                          D ]E}|	                    d          dk    r*|	                    d          |
                    |           F|S )z:Finished games from the last N days (for form + matching).   daysrc   statusFTscore1)ranger   rd   r   re   r   rf   ra   valuesr]   append)	days_backoutir_   gs        r    finished_gamesrw   Z   s    
C1i!m$$  |HL))I1,=,=,==GG
SS#%%'' 	 	AuuX$&&155??+F

1	 Jr(   zdeportivo la corunazathletic clubzreal betis balompiezrc celta vigo)zdeportivo a corunazathletic bilbaoz
real betisz
celta vigoc                 ~   t          |          | v r|          S t                                        | v r|          S t          fd| D             d          }|rZ|d         d         dk    rHt	          |          dk    s!|d         d         |d         d         z
  dk    r| |d         d                  S dS )	uO   Exact → alias → unique-best fuzzy (ratio>=0.72 with margin over runner-up).c              3   <   K   | ]}t          |          |fV  d S r$   )rU   )rC   kr   s     r    rE   z_lookup.<locals>.<genexpr>v   s2      ==qhsA&&*======r(   T)reverser   g
ףp=
?rj   g?N)rN   ALIASESr]   sortedlen)upcomingnamescoredr   s      @r    _lookupr   n   s    
++C
h}
++c3

C
h}====H===tLLLF &&)A,$&&CKK1,<,</5ay|fQil/Jd/R/Rq	!%%4r(      c           	         i }t          d| dz             D ]}t          j        t          j                  t          |          z                       d          }t          |                                          D ]^}dD ]Y\  }}|	                    |          |	                    |          }}|r(|&|
                    t          |          ||d           Z_|S )u=   Digitain name→id map from today's and the next days' feeds.r   rj   rk   rc   ))side1side1Id)side2side2IdN)idr   )rp   r   rd   r   re   r   rf   ra   rq   r]   
setdefaultrN   )	
days_aheadmru   r_   rv   name_keyid_keynmgids	            r    upcoming_teamsr   }   s    
A1j1n%% E E|HL))I1,=,=,==GG
SS#%%'' 	E 	EA$P E E &%%//155==C E#/LLr3,C,CDDDE	E
 Hr(      c                 X   g }| D ]}|                     d          |k    s|                     d          |k    rp|d         |k    }|r|d         |d         fn|d         |d         f\  }}||k    rdn	||k    rdnd}|                    |                     dd	          |||f           |                                 || d
         }	|	sd
S d                    d |	D                       t	          d |	D                       t	          d |	D                       t          |	          dS )zKLast-n finished results for a Digitain team id -> (string 'WDLLW', gf, ga).r   r   ro   score2WDLdateTr   Nr?   c              3   &   K   | ]}|d          V  dS )rj   Nrg   rC   r<   s     r    rE   zteam_form.<locals>.<genexpr>   s&      //QAaD//////r(   c              3   &   K   | ]}|d          V  dS )   Nrg   r   s     r    rE   zteam_form.<locals>.<genexpr>   s&      :N:NA1Q4:N:N:N:N:N:Nr(   c              3   &   K   | ]}|d          V  dS )   Nrg   r   s     r    rE   zteam_form.<locals>.<genexpr>   s&      ))qad))))))r(   )formgfgan)r]   rr   sortr   sumr~   )
gamesteam_idr   rowsrv   homer   r   reslasts
             r    	team_formr      sV   D : :55w&&!%%	*:*:g*E*EY<7*D37Wak1X;//ak1X;=WFBb##bBhhssCCKKw**CR8999IIKKK9D tGG//$/////s:N:N:N:N:N7N7N))D)))))D		; ; ;r(   c           	         t          | |g          \  }}t          d| d| dd          }|r(t          |                    d          t                    sdS |d                             d          pg }g }|D ]}|                    d          |                    |                    d          r;t          j        |d         d	z  t          j	                  
                    d
          nd|                    d          |                    d          |d         |d         d           |                    d            |pdS )z8Mutual meetings -> list of dicts (newest last), or None.zh2h/1/vsrW   rX   rY   Nro   r   i  rc   ?r   r   r   )dater   r   hgagc                     | d         S )Nr   rg   )xs    r    r'   zh2h.<locals>.<lambda>   s
    1V9 r(   )r   )r}   r,   r\   r]   r^   rr   r   fromtimestampr   re   rf   r   )id_aid_blohir`   meetsrt   rv   s           r    h2hr      sU   T4L!!FB!b!!B!!!8,,A JquuZ00$77 tjMd##)rE
C ; ;55??"

-.UU7^^EH21W:3DhlSSXj)))UU7^^aeeGnnH+Qx[: : 	; 	; 	; 	; HH$$H%%%;$r(   c                    | sdS | | d         }fdfd|D             }t          d |D                       }t          d |D                       }t          d |D                       }|d         d         |d         d	         |d         d
         }}
}	| d| d| dt          |           d|d          d|d          d|d          d|d          d|d          dS )uM   '2W-1D-2L · last: Alaves 0-1 Valencia (2026-02-14)' from home's perspective.Nc                     t          | d                   t                    k    }|r| d         | d         fn| d         | d         f\  }}||k    rdn	||k    rdnd||| fS )Nr   r   r   r   r   r   )rN   )r   home_is_side1r   r   r   s       r    res_forzh2h_summary.<locals>.res_for   ss    aj))U4[[8'4L!D'1T7##1T7AdG:LB2ggss288CCr2qHHr(   c                 &    g | ]} |          S rg   rg   )rC   r   r   s     r    
<listcomp>zh2h_summary.<locals>.<listcomp>   s!    	#	#	#''!**	#	#	#r(   c              3   2   K   | ]}|d          dk    dV  dS )r   r   rj   Nrg   r   s     r    rE   zh2h_summary.<locals>.<genexpr>   *      ))!QqTS[[A[[[[))r(   c              3   2   K   | ]}|d          dk    dV  dS )r   r   rj   Nrg   r   s     r    rE   zh2h_summary.<locals>.<genexpr>   s*      **1adckkQkkkk**r(   c              3   2   K   | ]}|d          dk    dV  dS )r   r   rj   Nrg   r   s     r    rE   zh2h_summary.<locals>.<genexpr>   r   r(   rj   r   r   zW-zD-z
L in last u
    · last: r   rF   r   -r   r    (r   ))r   r~   )meetingsr   awayr   r   rsr	   ddlr   r   r   r   s    `          @r    h2h_summaryr      sg    tQBCC=DI I I I I
 
$	#	#	#d	#	#	#B))r)))))A	*****	*	*B))r)))))A2q	2b6!9bfQiAB > >B > >! > >s2ww > >!G* > >w> >4> >#$W:> >126> > > ?r(      c                 8   t          |          }t                      }g }| D ]v}|d         |d         d}t          ||d                   }t          ||d                   }|r|s0|s|d         n|d         }	d|	 |d<   |                    |           t|d         |d         c|d<   |d<   t	          ||d                   }
t	          ||d                   }|
r+|
d	         d
k    r|
d         n|
d          d|
d	          d|d<   |r+|d	         d
k    r|d         n|d          d|d	          d|d<   t          |d         |d                   }|r2t          ||d         |d                   |d<   t          |          |d<   |                    |           x|S )zfixtures: [{'home','away','kickoff_utc'}] -> per-fixture context dicts.

    Returns (contexts, stats) where contexts[i] has form strings + h2h summary,
    or 'team' set to the unmatched side name when no Digitain match was found.
    r   r   )r   r   zno Digitain match for noter   home_idaway_idr   r   r   r   zg)	form_home	form_awayr   
n_meetings)rw   r   r   rr   r   r   r   r~   )fixturesrs   r   r   contextsr   ctxhidaidmissfhfar   s                r    build_contextr      s    9%%EHH  y!F)44h&	**h&	** 	# 	$'61V99QvYD9499CKOOC   ),TCI&IIuc$i((uc$i(( 	\-/W\\r&zz"V*?[?[PRSVPW?[?[?[C 	\-/W\\r&zz"V*?[?[PRSVPW?[?[?[CCIs4y)) 	+$UAfIqyAACJ #E

COr(   c                 :   g }| D ]}g }|                     d          r<|                     d          r'|                    d|d          d|d                     |                     d          r|                    d|d                     |                     d          r|                    |d                    |r>|                    d|d	          d|d
          dd                    |          z              |sdS dd                    |          z   dz   S )zI'## Match context' section for the daily report; empty string if nothing.r   r   zform z vs r   zH2H: r   z- **r   r   u   ** — u    · r?   z-## Match context (last games & head-to-head)

u   

*Informational only — not a model input. Backtest verdict (n=6,943, 2022-26): form −0.6pp accuracy, H2H ±0.0 — both REJECTED per the pre-declared adoption rule.*)r]   rr   r   )r   linesrD   bitss       r    context_markdownr      sG   E 	W 	W55 	F!%%"4"4 	FKKD+DDAkNDDEEE55<< 	,KK*%**+++55== 	#KK&	""" 	WLLA&	AAqyAAAFKKPTDUDUUVVV r<ii>> ?r(   c                 4   t           j                            t          d          }t	          |dd          5 }t          j        t          j        t          j
                                                  | d|d           d d d            n# 1 swxY w Y   |S )Nzapp_context.jsonr	   r3   )encoding)generated_utcmatchesF)ensure_ascii)r
   r   r   HEREr   r   r   r   rd   r   re   	isoformat)r   rt   r   s      r    write_app_contextr      s    
',,t/
0
0C	c3	)	)	) @Q	HL$>$>$H$H$J$J&( ()*	@ 	@ 	@ 	@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ Js   A	BBB)r-   )rh   )r   )r   )r   )(__doc__rP   r   r   r
   rJ   r   rA   urllib.requestr4   r   r   r   r)   r*   r   dirnameabspath__file__r   r   r   makedirsr!   r,   r%   rN   rU   ra   r[   rw   r|   r   r   r   r   r   r   r   r   rg   r(   r    <module>r      s  
 
    				 				          2 2 2 2 2 2 2 2 2 25-	wrwx0011GLLx((	 I % % % %  *2 2 2
? ? ? ?1 1 17 7 7/ / /; ; ;    0&'!	   
 
 
 
; ; ; ;"  &? ? ? ?(   B? ? ?,    r(   