
    ZɴhU                         S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKJ	r	  SSK
JrJrJrJrJr  SSKJrJr  SSKJr  SSKJr  SSKJr  SSKrSS	KJrJrJrJr  SS
KJrJ r    " S S5      r! " S S5      r"g)z
Jingle Detection Services

This module contains services for jingle detection, image comparison,
and ad break analysis. It provides the core functionality for detecting
jingles in video streams using OpenCV and managing ad break timing.
    N)Path)OptionalDictAnyListTuple)datetime	timedelta)settings)timezone)VideoFileClip)JingleTemplateJingleDetectionAdBreakDetectionStatistics)StreamSession
HLSSegmentc                       \ rS rSrSrS\S\4S jrSS jrS\\	\\\
4      4S	 jrS
\S\\   4S jrS\S\S\4S jrS\S\4S jrS\S\S\\	\\\\
4      4S jrS\S\\   4S jrS\S\
SS4S jrSrg)JingleDetector   a  
Service for detecting jingles in video streams using image comparison.

This service extracts frames from video segments and compares them
against reference jingle templates to identify advertisement breaks
and program transitions.

Attributes:
    logger (Logger): Logger instance for recording operations
    jingles_folder (str): Path to jingle template images
    iframes_folder (str): Path for temporary iframe storage
    similarity_threshold (float): Default similarity threshold for detection
jingles_folderiframes_folderc                     [         R                  " S5      U l        [        U5      U l        [        U5      U l        [        R                  S   U l        U R                  5       U l
        U R                  5         g)z
Initialize the jingle detector.

Args:
    jingles_folder (str): Path to directory containing jingle templates
    iframes_folder (str): Path to directory for storing extracted frames
zstream_processor.jinglesSIMILARITY_THRESHOLDN)logging	getLoggerloggerr   r   r   r   JINGLE_CONFIGsimilarity_threshold_load_jingle_templatesjingle_templates_create_directories)selfr   r   s      AC:\Users\brahi\OneDrive\Desktop\Code\src\apps\jingles\services.py__init__JingleDetector.__init__+   sj     ''(BC #>2">2 %-$:$:;Q$R! !% ; ; = 	  "    returnNc                 *   U R                   U R                  4 HC  n UR                  SSS9  UR                  S5        U R                  R                  SU 35        ME     g! [         a'  nU R                  R                  SU SU 35        e SnAff = f)z
Create necessary directories for jingle detection operations.

Creates the jingles folder and iframes folder if they don't exist,
with appropriate permissions for the application.
T)parentsexist_oki  zCreated directory: zFailed to create directory : N)r   r   mkdirchmodr   debugOSErrorerror)r#   folderes      r$   r"   "JingleDetector._create_directoriesC   s     **D,?,?@FTD9U#!!$7x"@A	 A
  !!$?xr!"MNs   ?A!!
B+"BBc                    / n[         R                  R                  SS9nU H  nUR                  5       (       aR  UR	                  UR
                  UR                  U45        U R                  R                  SUR                   35        Mj  U R                  R                  SUR                   35        M     U R                  R                  S[        U5       S35        U$ )a/  
Load jingle templates from the database and filesystem.

Loads active jingle templates from the database and verifies
that their corresponding image files exist on disk.

Returns:
    List[Tuple[str, str, JingleTemplate]]: List of tuples containing
        (template_name, image_path, template_object)
T)	is_activezLoaded jingle template: z!Jingle template image not found: zLoaded z jingle templates)r   objectsfilterimage_existsappendslug
image_pathr   r/   namewarninginfolen)r#   	templatesr!   templates       r$   r    %JingleDetector._load_jingle_templatesS   s     	 *118848H(H$$&&  MM''" 
 !!$<X]]O"LM##78K8K7LM ) 	73y>"22CDEr'   
video_pathc           	      n    [        U5      R                  nU R                  U S3-  nU R                  R	                  SU 35        [        5       R                  S5      R                  U5      R                  [        U5      SSSS9nUR                  " 5         [        [        R                  " [        U R                  U S3-  5      5      5      nU R                  R	                  S	[        U5       S
U 35        U$ ! [         a-  nU R                  R                  SU SU 35        / s SnA$ SnAff = f)aZ  
Extract I-frames from a video file using FFmpeg.

Extracts keyframes (I-frames) from the video file and saves them
as PNG images for comparison with jingle templates.

Args:
    video_path (str): Path to the video file
    
Returns:
    List[str]: List of paths to extracted frame images
    
Raises:
    RuntimeError: If frame extraction fails
z_%d.pngzExtracting frames from: yzselect=gt(scene\,0.10)vfrtrue)vfvsync	frame_ptsz_*.pngz
Extracted z frames from zError extracting frames from r,   N)r   stemr   r   r/   FFmpegoptioninputoutputstrexecutesortedglobr@   	Exceptionr1   )r#   rD   
video_nameoutput_patternffmpegframe_filesr3   s          r$   extract_iframesJingleDetector.extract_iframest   s(    !	j)..J!00j\3IINKK 8EF z"'0$	  	  NN !3##F&;;, " K KK
3{+;*<M*VW 	KK =j\A3OPI	s   C:C= =
D4"D/)D4/D4image_1_pathimage_2_pathc                     [         R                   " 5       n[        R                  " U5      n[        R                  " U5      nUb  Uc  U R                  R	                  S5        g[        R
                  " U/S/SS/SS/5      n[        R
                  " U/S/SS/SS/5      n[        R                  " Xg[        R                  5      n[        R                  " Xg[        R                  5      S   S   n	SU	-
  n
US-  U
S-  -   n[         R                   " 5       nU R                  R                  SX-
  S	 S
US	 35        U$ ! [         a(  nU R                  R                  SU 35         SnAgSnAff = f)av  
Compare two images and return a similarity score.

Uses histogram comparison and template matching to determine
how similar two images are. Lower scores indicate higher similarity.

Args:
    image_1_path (str): Path to the first image
    image_2_path (str): Path to the second image
    
Returns:
    float: Similarity score (0.0 = identical, 1.0 = completely different)
Nz$Failed to load images for comparison      ?r         g      ?zImage comparison took .3fzs, similarity: zError comparing images: )timecv2imreadr   r>   calcHistcompareHistHISTCMP_BHATTACHARYYAmatchTemplateTM_CCOEFF_NORMEDr/   rU   r1   )r#   r\   r]   
start_timeimage_1image_2hist_1hist_2	hist_difftemplate_matchtemplate_diffcombined_diffend_timer3   s                 r$   compare_imagesJingleDetector.compare_images   sb   %	J jj.Gjj.G '/##&JL \\7)aS$3xHF\\7)aS$3xHF 8Q8QRI !..vs?S?STUVWXYZN.M '_1DEMyy{HKK()>s(C D,S13
 !  	KK 8<=	s   A"D? %CD? ?
E1	E,,E1iframe_pathc                 (    [         R                  R                  U5      (       a5  [         R                  " U5        U R                  R                  SU 35        gg! [         a+  nU R                  R                  SU SU 35         SnAgSnAff = f)z
Remove an extracted iframe file from disk.

Args:
    iframe_path (str): Path to the iframe file to remove
    
Returns:
    bool: True if file was removed successfully, False otherwise
zRemoved iframe: TFzError removing iframe r,   N)ospathexistsremover   r/   r0   r>   )r#   rw   r3   s      r$   remove_iframeJingleDetector.remove_iframe   sy    	ww~~k**		+&!!$4[M"BC 	KK"8Rs KL	s   AA 
B&!BBts_filesessionc                    U R                   R                  SU 35        U R                  U5      nU(       d  U R                   R                  SU 35        gU H  nU R                   R                  SU 35        U R                   H  u  pVn U R	                  Xd5      nU R                   R                  SU SU SUS 35        UR
                  =(       d    U R
                  n	X:  a*  U R                   R                  S	U S
US 35        XTX4s  s  $ M     M     g! [         a,  n
U R                   R                  SU SU
 35         Sn
A
M  Sn
A
ff = f)a  
Detect jingles in a video segment file.

Extracts frames from the video segment and compares them against
all loaded jingle templates to find matches.

Args:
    ts_file (str): Path to the video segment file
    session (StreamSession): Stream session this segment belongs to
    
Returns:
    Optional[Tuple[str, str, float, JingleTemplate]]: Tuple containing
        (jingle_name, iframe_path, similarity_score, template) if detected,
        None if no jingle is detected
z)Processing segment for jingle detection: zNo frames extracted from NzAnalyzing frame: zComparison: z vs z = rb   zJingle detected: z with similarity zError comparing with template r,   )	r   r/   rZ   r!   ru   r   r?   rU   r1   )r#   r   r   iframesrw   jingle_namejingle_image_pathrB   
similarity	thresholdr3   s              r$   detect_jingleJingleDetector.detect_jingle   se     	EgYOP &&w/KK 9'CD #KKK 1+?@ =A<Q<Q8!%!4!45F!TJKK%%&{m4}C
SVGWX
 !) = = ZAZAZI!-((/}<MjY\M]^  +MM	 . =R	 #:  ! KK%%(F{mSUVWUX&YZs   A?D
E#!E

Esegmentc                     U R                  UR                  UR                  5      nU(       a  Uu  p4pV[        R                  R                  UR                  UUSU-
  USUSSS.S9nU R                  R                  SUR                   SUR                   35        U R                  UR                  U5        U$ g	! [         a5  nU R                  R                  S
UR                   SU 35         S	nAg	S	nAff = f)a-  
Process a video segment for jingle detection and record results.

Performs jingle detection on a segment and creates database records
for any detections found.

Args:
    segment (HLSSegment): Video segment to process
    
Returns:
    Optional[JingleDetection]: Detection record if jingle was found
r_   g        opencv_comparisonra   )similarity_scoredetection_methodframe_count)r   r   rB   confidence_score
frame_pathframe_timestampmetadataz!Created jingle detection record: z for NzError processing segment r,   )r   	file_pathr   r   r7   creater   r?   idr=   _update_detection_statsrU   r1   )	r#   r   detection_resultr   rw   r   rB   	detectionr3   s	            r$   process_segmentJingleDetector.process_segment)  s    $	#11'2C2CW__UAQ>* ,33::#OO#%%(:%5*$',6,?'( ; 	   7	~ F#==/+ ,,W__hG   	KK 9'**RsKL	s   B8B< <
C;+C66C;rB   c                 :    [         R                  R                  UUSSSS.S9u  p4UR                  5         U(       a)  U R                  R                  SUR                   35        gg! [         a(  nU R                  R                  SU 35         SnAgSnAff = f)z
Update detection statistics for a template and session.

Args:
    session (StreamSession): Stream session
    template (JingleTemplate): Jingle template that was detected
r   )total_detectionsconfirmed_detectionsfalse_positives)r   rB   defaultsz%Created new detection statistics for z%Error updating detection statistics: N)	r   r7   get_or_createupdate_statisticsr   r/   r=   rU   r1   )r#   r   rB   statscreatedr3   s         r$   r   &JingleDetector._update_detection_stats\  s    	K088FF!(),-'( G NE ##%!!$I(--"YZ   	KKK EaSIJJ	Ks   A$A( (
B2BB)r   r!   r   r   r   )r(   N)__name__
__module____qualname____firstlineno____doc__rQ   r%   r"   r   r   r   r    rZ   floatru   boolr}   r   r   r   r   r   r   r   __static_attributes__ r'   r$   r   r      s    #s #C #0 U3^3K-L(M B1# 1$s) 1f33 3c 3e 3j  (7S 7= 7XeTWY\^cesTsNtEu 7r1z 1h6O 1fK} K K[_ Kr'   r   c                       \ rS rSrSrS rS\S\\   4S jr	S\S\4S jr
S\S\S\4S	 jrSS
\S\S\4S jjrS\S\\\4   4S jrSrg)AdBreakAnalyzeriz  z
Service for analyzing jingle detections to identify advertisement breaks.

This service processes sequences of jingle detections to identify
when advertisement breaks start and end, calculating durations
and managing ad break records.
c                     [         R                  " S5      U l        [        R                  S   U l        [        R                  S   U l        g)z!Initialize the ad break analyzer.zstream_processor.adbreaksMIN_AD_BREAK_DURATIONMAX_AD_BREAK_DURATIONN)r   r   r   r   r   min_durationmax_duration)r#   s    r$   r%   AdBreakAnalyzer.__init__  s?    ''(CD %223JK$223JKr'   r   r(   c                     UR                   n[        R                  R                  USS9R	                  5       nUc  U R                  U5      $ U R                  X15      $ )aT  
Process a jingle detection to potentially create or update ad breaks.

Analyzes the detection in the context of previous detections to
determine if it represents the start or end of an ad break.

Args:
    detection (JingleDetection): New jingle detection to process
    
Returns:
    Optional[AdBreak]: Created or updated ad break record
T)r   end_time__isnull)r   r   r7   r8   first_start_ad_break_end_ad_break)r#   r   r   active_adbreaks       r$   process_detection!AdBreakAnalyzer.process_detection  sh     ## !//! 0 
 %' 	
 !''	22 %%n@@r'   c           	          [         R                  R                  UR                  UR                  R                  R
                  SUUR                  SS9nU R                  R                  SUR                   35        U$ )z
Start a new advertisement break.

Args:
    detection (JingleDetection): Detection that starts the ad break
    
Returns:
    AdBreak: Created ad break record
Globalactive)r   channel_nameregionstart_detectionrk   statuszStarted new ad break: )
r   r7   r   r   channelr;   detection_timer   r?   r   )r#   r   ad_breaks      r$   r   AdBreakAnalyzer._start_ad_break  sr     ??))%%"**2277% // * 
 	1(++?@r'   r   c                 V   UR                   UR                  -
  R                  5       nU R                  Us=::  a  U R                  ::  ap  O  OmX!l        UR                   Ul        [        U5      Ul        SUl	        UR                  5         U R                  R                  SUR                   SUS S35        U$ X!l        UR                   Ul        SUl        SUl        SUl        SUl	        UR                  5         U R                  R                  SUR                   S	US S35        U$ )
z
End an active advertisement break.

Args:
    ad_break (AdBreak): Active ad break to end
    detection (JingleDetection): Detection that ends the ad break
    
Returns:
    AdBreak: Updated ad break record
	completedzCompleted ad break: z (duration: .1fzs)Nr   zReset ad break: z (invalid duration: )r   rk   total_secondsr   r   end_detectionrt   intduration_secondsr   saver   r?   r   r   )r#   r   r   durations       r$   r   AdBreakAnalyzer._end_ad_break  s    ,,x/B/BBQQS =D,=,==%." ) 8 8H(+HH%)HOMMOKK&x{{m 4&s^2/&  (1$"+":":H%)H" $H(,H%&HOMMOKK"8;;- 0&&.s^27
 r'   r   timeout_minutesc                    [         R                  " 5       [        US9-
  n[        R                  R                  UUSSS9nSnU H  n[         R                  " 5       UR                  -
  R                  5       n/ SQn[        R                  " U5      n	[         R                  " 5       Ul
        Xl        SUl        SUS	-  S
 S3Ul        UR                  5         US-  nU R                  R!                  SUR"                   SU	 S35        M     U$ )a~  
Clean up ad breaks that have been active too long without ending.

Finds ad breaks that have been active longer than the timeout
and either completes them with estimated durations or cancels them.

Args:
    session (StreamSession): Stream session to clean up
    timeout_minutes (int): Timeout in minutes for active ad breaks
    
Returns:
    int: Number of ad breaks cleaned up
)minutesTr   )r   start_time__ltr   r   r   )!            #   (   -   2   7   <   A   F   K   P   U   Z   _   d   i   n   s   x   }                                 r   zAuto-completed after r   r   z  minutes with estimated durationra   zAuto-completed stale ad break: z with estimated duration: s)r   nowr
   r   r7   r8   rk   r   randomchoicert   r   r   notesr   r   r?   r   )
r#   r   r   timeout_timestale_breakscleaned_countr   elapsedad_duration_optionsrandom_durations
             r$   cleanup_stale_ad_breaks'AdBreakAnalyzer.cleanup_stale_ad_breaks  s     ||~	/(JJ --'!	 . 
 $H||~(;(;;JJLG#
 %mm,?@O !)H(7%)HO4WRZ4DDdeHNMMOQMKK1(++ ?,,;+<A?+ %4 r'   c                     UR                   R                  5       UR                  (       a  UR                  R                  5       OSUR                  UR                  UR
                  [        UR                  5      S.$ )z
Get ad break data formatted for external API submission.

Args:
    ad_break (AdBreak): Ad break to format
    
Returns:
    Dict[str, Any]: Formatted ad break data
N)startendr   r   r   ad_break_id)rk   	isoformatrt   r   r   r   rQ   r   )r#   r   s     r$   get_ad_break_data!AdBreakAnalyzer.get_ad_break_data  sa     ((2244<4E4E8$$..04 11,,oox{{+
 	
r'   )r   r   r   N)   )r   r   r   r   r   r%   r   r   r   r   r   r   r   r   r  r   rQ   r   r
  r   r   r'   r$   r   r   z  s    LA? Ax?P A8 W ,*g */ *g *X4} 4s 4[^ 4l
' 
d38n 
r'   r   )#r   ry   rd   rc   rT   r   shutilr   pathlibr   typingr   r   r   r   r   r	   r
   django.confr   django.utilsr   moviepy.editorr   rX   apps.jingles.modelsr   r   r   r   apps.streams.modelsr   r   r   r   r   r'   r$   <module>r     s]    
 
       3 3 (   ! (  ] ] 9[K [K|
v
 v
r'   