o
    +
jsC                     @   s  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	 ddl
mZ eejdr;ejjdd eejdrHejjdd dZeejd	 Zeejd
 Zeejd ZdZdZejejdejeddeejgd eeZdadd Z d-dede!de"de!de#e f
ddZ$dedede%fddZ&de#de'e#e( e"f fd d!Z)de#e( dB fd"d#Z*d.d%e"fd&d'Z+d(d) Z,d*d+ Z-ed,kre-  dS dS )/z
DAZN Live Scanner
Cattura frame dal flusso DAZN EPG e usa OCR per estrarre
gli eventi in onda e i canali associati ("Events X").
Si aggiorna ogni minuto.
    N)datetime)Pathreconfigureutf-8encodingzGhttps://sell2k25flux.flux-atv2k22.xyz:443/JellyfinLINE/d9DZQGmdwC/26433epg_dataframeszdazn_scanner.log)iG  7     8  i^  z'%(asctime)s [%(levelname)s] %(message)s)levelformathandlersc                  C   s:   t du rddl} td | jddgdda td t S )	z1Inizializza il reader OCR (lazy, una sola volta).Nr   zM[OCR] Caricamento modello EasyOCR (prima volta, potrebbe richiedere tempo)...itenF)gpuz[OCR] Modello caricato.)_ocr_readereasyocrloggerinfoReader)r    r   9/var/www/addictedbytheproject.nl/epg/dazn_live_scanner.pyget_ocr_reader6   s   

r      1/3
output_dirprefixdurationfpsreturnc                 C   s   zMdddt |dtdd| ddt | | d	 g}tj|d
d
|d d t| | d}dd |D }|rFtdt| d |W S t	d |W S  tj
y^   t	d g  Y S  tyy } zt	d|  g W  Y d}~S d}~ww )zICattura multipli frame dal flusso per coprire la rotazione della sidebar.ffmpegz-yz-tz-iz-vfzfps=z-q:v2z	_%03d.jpgT   )capture_outputtexttimeoutz_*.jpgc                 S   s   g | ]}|  jd kr|qS )r   )statst_size).0fr   r   r   
<listcomp>O   s    z"capture_frames.<locals>.<listcomp>z[FRAME] Catturati z frame utili per lo scrolling.z [FRAME] Nessun file frame creatoz&[FRAME] Timeout cattura frame multipliz[FRAME] Errore: N)str
STREAM_URL
subprocessrunsortedglobr   r   lenerrorTimeoutExpired	Exception)r   r   r   r    cmdr	   valid_frameser   r   r   capture_framesA   s0   


r:   
frame_pathsidebar_pathc           	   
   C   s   zVddl m} || }|jdkrHtd|j d |jd d }|jd d }ttd | ttd | ttd	 | ttd
 | f}nt}||}|	| W dS  t
yq } ztd|  W Y d}~dS d}~ww )z,Ritaglia la sidebar 'IN ONDA ORA' dal frame.r   )Image)r   r   z[CROP] Risoluzione inattesa: z, adattamento...r      r         Tz[CROP] Errore: NF)PILr=   opensizer   warningintSIDEBAR_CROPcropsaver6   r4   )	r;   r<   r=   imgsxsyrG   sidebarr9   r   r   r   extract_sidebar]   s*   



rM   ocr_resultsc                    s  d}g }| D ]h\}}}|d d |d d  d }|d d |d d  d }t d|t j}|r?t|d}	|	|kr>|	}n|dk rY|  rYt| }	|	|krY|	dk rY|	}|dk r^q|tkrn|| |||d q|j	d	d
 d t
d t
d    fdd|D }g }
g }d}|D ]-}t|d | dkr|r|
| |g}|d }q|| tdd |D t| }q|r|
| g }|
D ])}|j	dd
 d ddd |D }tdd |D t| }|||d qg }d}|t|k r|| }|d }t d|t j}|rt|d}t d|}|r.|dddddnd}|rV|d  d!rV||d  d"< d#| |d  d$< ||d  d%< |d  d!= n|}t d&d|}t jd'd|t jd(}|d)}||ru|nd*|d#| |d+ nt d,|}|r|ddddd}|d }d}d}t d-|t jrd.}n|rt d/d| }|s|}|r|d  d!r||d  d"< ||d  d$< ||d  d%< |d  d!= ntd0|  |d7 }qt|dk s| d1v r|d7 }q|| d2d3 |d7 }|t|k sg }|D ]"}d!|v r6|d!= |d"d |d$d |d%d || q||fS )4zo
    Analizza i risultati OCR e raggruppa per evento.
    Restituisce (lista_eventi, numero_eventi_attesi)
    r   r?   r>   z(\d+)\s*(?:live|in onda)d   2   g?)r&   xyconfc                 S      | d S )NrR   r   tr   r   r   <lambda>       z#parse_ocr_results.<locals>.<lambda>keyr@   c                    s0   g | ]}d |d   k r d k rn n|qS )<   rR      r   r*   rV   crop_heightr   r   r,      s   0 z%parse_ocr_results.<locals>.<listcomp>irR   r   c                 s       | ]}|d  V  qdS rR   Nr   )r*   itemr   r   r   	<genexpr>       z$parse_ocr_results.<locals>.<genexpr>c                 S   rT   )NrQ   r   rU   r   r   r   rW      rX    c                 s   r`   )r&   Nr   r]   r   r   r   rc      rd   c                 s   r`   ra   r   r]   r   r   r   rc      rd   )r&   rR   r&   zEvents\s*(\d+)z(\d{1,2}[:\.,]\d{2}),:. _needs_infotimezEvents channelchannel_numberz\d{1,2}[:\.,]\d{2}zEvents\s*\d+)flagsz |,-?)titlerl   rm   rn   z^(\d{1,2}[:\.,]\d{2})\s*(.*)zZona\s+Serie\s+A
ZonaSerieAz\s+\d+$z#[PARSE] Riga info orfana ignorata: )ITLIVENHT)rq   rk   )research
IGNORECASErE   groupstripisdigitSIDEBAR_TEXT_X_MINappendsortrF   abssumr3   joinreplacegetsubmatchr   debugupper
setdefault)rN   expected_live_countsidebar_textsbboxr&   rS   x_centery_centermvalrowscurrent_rowlast_yrV   merged_rowsrow	full_textavg_yeventsievents_matchrm   
time_match
event_timerq   
time_start	remainingchannel_namechannel_numfinal_eventsevr   r^   r   parse_ocr_resultsx   s   



$

	R
r   c               	   C   s8  t jddd tjddd t d} td tt d|  ddd}|s)d	S t	 }d
}i }i }d
d	l
}t|D ]\}}t d|  d| d }	t||	sOq:td|d  dt| d |t|	}
t|
\}}||krz|}td|  |D ]n}|dd
}|d
kr||vr|||< q||| }|ds|dr|d|d< t|d t|d kr|d |d< q|tdd|d  }t|dk rq|||vr|||< q|t|d t|| d kr|d || d< q||d
krt||krtd| d  nq:t| }|d
kst||k rX| D ]>\}}d}|D ]}tdd|d  }|d	|| dkr>d} nq!|sV|| |d
krVt||krV nq|jdd d td t| d!| d" t  d#t||d$}td% }t|d&d'd(}tj||dd)d* W d	   n	1 sw   Y  td+|  d, }t|d&d'd(}tj||dd)d* W d	   n	1 sw   Y  t d-d.  t d/t d0  t d1t| d2 t d.  |D ] }|d3d}|dd}t d1|d4d1|d5d1|d   qt d. d- t!d6d7 |S )8z
    Pipeline completa: cattura frames multipli -> OCR -> parsing eventi uniti.
    Restituisce la lista di eventi o None in caso di errore.
    T)parentsexist_okz%Y%m%d_%H%M%SzD[SCAN] Avvio scansione eventi live multipli (copertura scrolling)...frame_r\   r   )r   r    Nr   sidebar__z.jpgz[OCR] Analisi frame r>   /z in corso...z+[PARSE] Rilevato contatore eventi in onda: rn   rl   rq   z	[^a-z0-9]ri      z[SCAN] Trovati tutti i z< eventi previsti! Interrompo l'analisi dei frame successivi.Fg?c                 S   s   |  ddS )Nrn   r   )r   )rQ   r   r   r   rW   ~  s    z"scan_live_events.<locals>.<lambda>rY   z[PARSE] Estratti z  eventi univoci totali (Target: )dazn_live_stream_ocr)	timestampsourcetotal_eventsr   zdazn_live_events.jsonwr   r   r?   )ensure_asciiindent
dazn_live_z.json
z<============================================================z  DAZN LIVE - z%H:%M:%Sz  z$ eventi in onda (uniti da rotazione)rm   z>5z<12   )keep)"
FRAMES_DIRmkdir
OUTPUT_DIRr   nowstrftimer   r   r:   r   difflib	enumeraterM   r3   readtextr-   r   r   rv   r   lowerlistvaluesitemsSequenceMatcherratior}   r~   	isoformatrB   jsondumpprintcleanup_frames)r   r	   readerexpected_countevents_by_channelevents_no_channelr   r   r;   r<   rN   r   frame_expectedr   chanexisting	title_keyr   is_dupchan_evchan_title_keyresultlatest_pathr+   history_pathchrV   r   r   r   scan_live_events$  s   

 




&
r   r   r   c                 C   s   t  sdS d}dD ]#}tt |}t|| kr-|d|   D ]}|jdd |d7 }q q
ttd}t|| krO|d|   D ]}|jdd |d7 }qB|dkratd| d	|  d
 dS dS )zVRimuove i frame, sidebar e storico EPG piu' vecchi, mantenendo solo gli ultimi 'keep'.Nr   )zframe_*.jpgzsidebar_*.jpgT)
missing_okr>   zdazn_live_*.jsonz[CLEANUP] Rimossi z file vecchi (soglia: r   )	r   existsr1   r2   r3   unlinkr   r   r   )r   removedpatternfilesr+   
json_filesr   r   r   r     s$   

r   c               
   C   sH   zt   W dS  ty# }  ztjd|  dd W Y d} ~ dS d} ~ ww )z!Job schedulato: scansione eventi.z[ERRORE] Scansione fallita: T)exc_infoN)r   r6   r   r4   )r9   r   r   r   scheduled_scan  s   "r   c                   C   s   t d t d t d t d t d t d t d td t  tdjt td td	 z	 t	  t
d q9 tyQ   td Y d S w )Nri   z&  ====================================z    DAZN Live Event Scannerz     Estrae eventi e canali dalloz    stream EPG ogni minutoz[AVVIO] Prima scansione...r>   z"[SCHEDULE] Scansione ogni 1 minutoz [INFO] Premi Ctrl+C per uscire.
T
   z 
[STOP] Arresto richiesto. Ciao!)r   r   r   r   scheduleeveryminutesdor   run_pendingrl   sleepKeyboardInterruptr   r   r   r   main  s(   



r   __main__)r   r   )r   ).__doc__sysior/   r   rv   rl   loggingr   r   pathlibr   hasattrstdoutr   stderrr.   __file__parentr   r   LOG_FILErF   r|   basicConfigINFOFileHandlerStreamHandler	getLogger__name__r   r   r   r-   rE   r   r:   boolrM   tupledictr   r   r   r   r   r   r   r   r   <module>   sX    

$ - 
