
    Aʹh[                         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Jr  SSKJ	r	J
r
JrJr  SSKJr  SSKJr  SSKJrJrJrJrJr   " S S	5      r " S
 S5      rg)z
Stream Processing Services

This module contains the core services for stream capture, processing,
and HLS playlist management. It provides the main functionality for
capturing HLS streams using FFmpeg and managing the resulting segments.
    N)Path)OptionalDictAnyList)settings)timezone)ChannelStreamSession
HLSSegmentVideoConfigurationAudioConfigurationc            
       :   \ rS rSrSrS rS\4S jrS\S\	\
\4   4S jr  SS\S	\\   S
\\   S\\
   4S jjrS
\S\\
   4S jrS	\S\\
   4S jr  SS\S	\\   S
\\   S\4S jjrS\S\4S jr  SS\S	\\   S
\\   S\\   4S jjrSS\S\S\4S jjrSrg)StreamCaptureService   a  
Service for capturing and processing HLS streams using FFmpeg.

This service provides the core functionality for stream capture,
including FFmpeg command generation, process management, and
error handling with automatic retry logic.

Attributes:
    logger (Logger): Logger instance for recording operations
    ffmpeg_path (str): Path to the FFmpeg executable
    output_base_dir (str): Base directory for stream output
c                     [         R                  " S5      U l        SU l        [        R
                  S   U l        U R                  5         g)z
Initialize the stream capture service.

Sets up logging, validates FFmpeg availability, and configures
default settings for stream processing operations.
zstream_processor.captureffmpeg
OUTPUT_DIRN)logging	getLoggerloggerffmpeg_pathr   STREAM_CONFIGoutput_base_dir_validate_ffmpegselfs    AC:\Users\brahi\OneDrive\Desktop\Code\src\apps\streams\services.py__init__StreamCaptureService.__init__#   sD     ''(BC $  (55lC 	    returnc                 @    [         R                  " U R                  S/SSSS9nUR                  S:X  a  U R                  R                  S5        g[        SUR                   35      e! [         a    [        S5      e[         R                   a    [        S	5      ef = f)
z
Validate that FFmpeg is available and accessible.

Returns:
    bool: True if FFmpeg is available, raises exception otherwise
    
Raises:
    RuntimeError: If FFmpeg is not found or not executable
z-versionT
   )capture_outputtexttimeoutr   zFFmpeg validation successfulzFFmpeg test failed: z0FFmpeg not found in PATH. Please install FFmpeg.zFFmpeg validation timed out)

subprocessrunr   
returncoder   infoRuntimeErrorstderrFileNotFoundErrorTimeoutExpired)r   results     r   r   %StreamCaptureService._validate_ffmpeg6   s    	>^^!!:.#	F   A%  !?@"%9&--#IJJ  	SQRR(( 	><==	>s   AA) A) )4Bchannelc           
         [        U R                  5      UR                  -  nUS-  nUS-  nUS-  nUUUUS.nUR                  5        HE  u  px UR	                  SSS9  UR                  S5        U R                  R                  SU 35        MG     U$ ! [         a*  n	U R                  R                  S	U S
U SU	 35        e Sn	A	ff = f)aG  
Create the necessary output directories for a channel.

Creates the directory structure needed for HLS output,
including the main channel directory, HLS subdirectory,
and logs directory.

Args:
    channel (Channel): Channel model instance
    
Returns:
    Dict[str, Path]: Dictionary containing paths to created directories
hlslogsiframes)baser4   r5   r6   T)parentsexist_oki  zCreated directory: zFailed to create z directory : N)
r   r   slugitemsmkdirchmodr   r+   OSErrorerror)
r   r2   	base_pathhls_path	logs_pathiframes_pathdirectoriesnamepathes
             r   create_output_directories.StreamCaptureService.create_output_directoriesR   s     --.=	u$&	 9, #	
 &++-JD

4$
7

5!  #6tf!=> . 	  !!$5dV;tfBqc"RSs   ?B
C%CCNvideo_configaudio_configc                    U R                  U5      nUS   nU R                  SSSSSSSS	UR                  S
SS
S/nU(       a!  UR                  U R	                  U5      5        O`UR                  SSSSS[        [        R                  S   5      S[        [        R                  S   5      S[        R                  S   /
5        U(       a!  UR                  U R                  U5      5        O~UR                  SSSSSSS[        R                  S   S[        R                  S    S![        R                  S"   S#[        R                  S$   S%[        R                  S"   S&S'S(S)S*S+S,S+/5        UR                  S-SS.[        UR                  5      S/[        UR                  5      S0S1S2S3S4S5S6S1S7[        US8-  5      [        US9-  5      /5        U$ ):a  
Build the FFmpeg command for stream capture.

Constructs the complete FFmpeg command line arguments based on
channel configuration and encoding parameters.

Args:
    channel (Channel): Channel configuration
    video_config (VideoConfiguration, optional): Video encoding settings
    audio_config (AudioConfiguration, optional): Audio encoding settings
    
Returns:
    List[str]: FFmpeg command as list of arguments
r4   z-hide_bannerz	-loglevelr+   z-user_agentz<Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36z-headerszReferer: http://www.radio2m.ma/z-iz-mapz0:v:0z0:a:0-afloudnorm=I=-16:LRA=11:TP=-1-c:aaac-arSAMPLE_RATE-acCHANNELS-b:aBITRATE-c:vh264
-profile:vmain-levelz3.1-s
RESOLUTION-aspectASPECT_RATIO-b:vMIN_BITRATE-maxrateMAX_BITRATE-bufsize-crf20-sc_threshold0-g48-keyint_minz-fz	-hls_timez-hls_list_sizez-hls_delete_threshold1z
-hls_flagsdelete_segmentsz-hls_start_number_sourcedatetimez	-strftimez-hls_segment_filenamezindex_%Y_%m_%d_%H_%M_%S.ts
index.m3u8)rI   r   hls_urlextend_build_audio_optionsstrr   AUDIO_CONFIG_build_video_optionsVIDEO_CONFIGsegment_durationmax_segments)r   r2   rK   rL   rE   rB   cmds          r   build_ffmpeg_command)StreamCaptureService.build_ffmpeg_commandz   s   * 44W=u%  Y 9 '// GG!
( JJt00>? JJ4s800?@s800<=--i8  JJt00>? JJf%h++L9800@--m<H11-@H11-@dt   	

%W556c'"6"67#S+&
 $778 <'(
 	" 
r!   c           
          / nUR                   (       a  UR                  SS/5        UR                  SUR                  S[        UR                  5      S[        UR
                  5      SUR                  /5        U$ )z
Build audio encoding options from configuration.

Args:
    audio_config (AudioConfiguration): Audio configuration object
    
Returns:
    List[str]: Audio encoding options for FFmpeg
rN   rO   rP   rR   rT   rV   )	normalizerr   codecrt   sample_ratechannelsbitrate)r   rL   optionss      r   rs   )StreamCaptureService._build_audio_options   sv      !!NNE#@AB 	L&&3|//03|,,-L((	
 	 r!   c                 ^   SUR                   SUR                  SUR                  SUR                  SUR                  S[        UR                  5      SUR                  SUR                  S	UR                  /nUR                   S
:X  a%  UR                  SUR                  SSSSSSSS/
5        U$ )z
Build video encoding options from configuration.

Args:
    video_config (VideoConfiguration): Video configuration object
    
Returns:
    List[str]: Video encoding options for FFmpeg
rX   rZ   r\   r]   r_   z-rra   rc   re   rY   z-presetrf   rg   rh   ri   rj   rk   rl   )r   profilelevel
resolutionaspect_ratiort   
frame_ratemin_bitratemax_bitraterr   preset)r   rK   r   s      r   rv   )StreamCaptureService._build_video_options   s     L&&,..l((,))|00#l--.L,,0000

 'NN<..dt  r!   c           	      X   U R                   R                  SUR                   35        [        R                  R                  UUUS[        R                  " 5       S9n U R                  XU5      nU R                   R                  SSR                  U5       35        [        R                  " U[        R                  [        R                  SSSS9n[        UR                  5      Ul        S	Ul        UR#                  5         U R                   R                  S
UR                   35        U$ ! [$         ar  nSUl        [        U5      Ul        [        R                  " 5       Ul        UR#                  5         U R                   R+                  SU 35        [-        SU 35      eSnAff = f)a  
Start stream capture for a channel.

Initiates the FFmpeg process for stream capture and creates
a StreamSession to track the operation.

Args:
    channel (Channel): Channel to capture
    video_config (VideoConfiguration, optional): Video encoding settings
    audio_config (AudioConfiguration, optional): Audio encoding settings
    
Returns:
    StreamSession: Created session object
    
Raises:
    RuntimeError: If capture fails to start
z%Starting stream capture for channel: pending)r2   rK   rL   status
started_atzFFmpeg command:  T   )stdoutr-   r&   bufsizeuniversal_newlinesactivez!Stream capture started with PID: failedz Failed to start stream capture: zStream capture failed: N)r   r+   rF   r   objectscreater	   nowr{   joinr(   PopenPIPErt   pid
process_idr   save	Exception
last_errorended_atr@   r,   )r   r2   rK   rL   sessionrz   processrH   s           r   start_capture"StreamCaptureService.start_capture  sh   . 	@OP  ''..%%||~ / 
"	>++G<PC KK/?@ !&&!!#'G "%W[[!1G%GNLLNKK@NON 	>%GN!$QG'||~GLLNKK @DE!8<==	>s   CD- -
F)7A-F$$F)r   c                    U R                   R                  SUR                   35         UR                  (       aZ   [        R
                  " SUR                  /5      nUR                  SS9  U R                   R                  SUR                   35        SUl	        [        R                  " 5       Ul        UR                  5         g! [        R                   a&    [        R                  " SSUR                  /5         Nf = f! [         a<  nU R                   R                  S	U 35        UR!                  S
U 35         SnAgSnAff = f)z
Stop an active stream capture session.

Terminates the FFmpeg process and updates the session status.

Args:
    session (StreamSession): Session to stop
    
Returns:
    bool: True if successfully stopped, False otherwise
z!Stopping stream capture session: killr$   )r'   z-9zTerminated process PID: 	completedTz Failed to stop capture session: zStop failed: NF)r   r+   idr   r(   r   waitr/   r)   r   r	   r   r   r   r   r@   	add_error)r   r   r   rH   s       r   stop_capture!StreamCaptureService.stop_capture]  s    	<WZZLIJ	!!G(..8J8J/KLGLLL,
   #;G<N<N;O!PQ )GN'||~GLLN "00 GNNFD'2D2D#EFG  	KK @DEaS12	s;   D 1C -AD 7D>D  DD 
E
2EE
c                    SnUR                   nUR                  nXE:  a   U R                  R                  SUS-    SU 35        U R	                  XU5      nU R                  U5      (       a  U$ US-  nXE:  a5  U R                  R                  SU S35        [        R                  " U5        XE:  a  M  U R                  R                  SU SUR                   35        g
! [         am  nU R                  R                  SUS-    SU 35        US-  nXE:  a5  U R                  R                  S	U S35        [        R                  " U5         S
nANS
nAff = f)a  
Start stream capture with automatic retry logic.

Implements the retry logic from the original bash script,
attempting to restart capture on failure with configurable
retry attempts and intervals.

Args:
    channel (Channel): Channel to capture
    video_config (VideoConfiguration, optional): Video encoding settings
    audio_config (AudioConfiguration, optional): Audio encoding settings
    
Returns:
    Optional[StreamSession]: Session if successful, None if all retries failed
r   zStream capture attempt r   /zCapture failed, retrying in z seconds...zCapture attempt z	 failed: zRetrying in NzAll z capture attempts failed for )retry_attemptsretry_intervalr   r+   r   _monitor_capturewarningtimesleepr   r@   rF   )	r   r2   rK   rL   retriesmax_retriesr   r   rH   s	            r   capture_with_retry'StreamCaptureService.capture_with_retry  s\   * ,, //#/  #:7Q;-q!VW ,,WLQ ((11"N qLG,++:>:J+V 

>2# #< 	D-J7<<.YZ  /!!$4Wq[M1#"NO1(KK''&~&6kB JJ~./s   AC! /?C! !
E+A#EEr'   c                 6   [         R                   " 5       n[         R                   " 5       U-
  U:  Ga   UR                  (       aN  [        R                  " SSUR                  /SS9nUR                  S:w  a  U R
                  R                  S5        g[        UR                  R                  5       5      nUS-  nUR                  5       (       aE  [        UR                  S	5      5      n[        U5      S:  a  U R
                  R                  S
5        g[         R                  " S5        [         R                   " 5       U-
  U:  a  GM  U R
                  R#                  S5        g! [          a(  nU R
                  R                  SU 35         SnAgSnAff = f)aZ  
Monitor a capture session for initial success.

Waits for the capture to start producing segments and verifies
that the process is running correctly.

Args:
    session (StreamSession): Session to monitor
    timeout (int): Timeout in seconds for initial success check
    
Returns:
    bool: True if capture appears successful, False otherwise
psz-pT)r%   r   zFFmpeg process has terminatedFrp   *.tsz!Stream capture appears successful   zError monitoring capture: NzCapture monitoring timed out)r   r   r(   r)   r*   r   r@   r   r2   get_hls_pathexistslistgloblenr+   r   r   r   )	r   r   r'   
start_timer0   rB   playlist_filesegmentsrH   s	            r   r   %StreamCaptureService._monitor_capture  sG    YY[
iikJ&0%%'^^tW%7%78'+F ((A-))*IJ$   < < >? (< 7 ''))#HMM&$9:H8}q((()LM# 

11 iikJ&0< 	:;  !!$>qc"BCs%   AE& BE& E& &
F0FF)r   r   r   )NN)<   )__name__
__module____qualname____firstlineno____doc__r   boolr   r
   r   rt   r   rI   r   r   r   r   r{   rs   rv   r   r   r   r   intr   __static_attributes__ r!   r   r   r      sk    &>$ >8& &T#t)_ &V 6:59	__ 12_ 12	_
 
c_B1C S	 4 1C  S	  J 6:59	D>D> 12D> 12	D>
 
D>L$M $d $R 6:59	88 128 12	8
 
-	 8t/ / /T / /r!   r   c                   b    \ rS rSrSrS rS\S\4S jrS\S\4S jr	SS\S	\
\   S\4S
 jjrSrg)HLSPlaylistManageri  z
Service for managing HLS playlists and segments.

This service handles playlist file creation, segment management,
and cleanup operations for HLS streams.
c                 :    [         R                  " S5      U l        g)z$Initialize the HLS playlist manager.zstream_processor.hlsN)r   r   r   r   s    r   r   HLSPlaylistManager.__init__  s    ''(>?r!   r2   r"   c                 |    [        UR                  5       5      nUS-  n/ SQn[        US5       nUR                  SR	                  U5      5        SSS5        U R
                  R                  SU 35        g! , (       d  f       N-= f! [         a(  nU R
                  R                  SU 35         SnAg	SnAff = f)
z
Create a master HLS playlist file for a channel.

Args:
    channel (Channel): Channel to create playlist for
    
Returns:
    bool: True if playlist was created successfully
zmaster.m3u8)#EXTM3U#EXT-X-VERSION:3z#EXT-X-INDEPENDENT-SEGMENTSzz#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID="CC",LANGUAGE="eng",NAME="english",DEFAULT=YES,AUTOSELECT=YES,INSTREAM-ID="CC1"zy#EXT-X-STREAM-INF:BANDWIDTH=3405600,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2",FRAME-RATE=25,CLOSED-CAPTIONS="CC"rp   w
NzCreated master playlist: Tz"Failed to create master playlist: F)	r   r   openwriter   r   r+   r   r@   )r   r2   rB   master_pathcontentfrH   s          r   create_master_playlist)HLSPlaylistManager.create_master_playlist  s    	G0023H"]2KG k3'1		'*+ ( KK8FG	 ('  	KK B1#FG	s.   .B	 !A8&B	 8
BB	 	
B;B66B;c                     [        UR                  5       5      nUS-  nUR                  5       (       dZ  / SQn[        US5       nUR	                  SR                  U5      S-   5        SSS5        U R                  R                  SU 35        U R                  U5        g! , (       d  f       N>= f! [         a(  nU R                  R                  SU 35         SnAg	SnAff = f)
z
Ensure that playlist files exist for a channel.

Args:
    channel (Channel): Channel to check
    
Returns:
    bool: True if playlists exist or were created
zplaylist.m3u8)r   r   z#EXT-X-TARGETDURATION:6z#EXT-X-MEDIA-SEQUENCE:0r   r   NzCreated playlist: Tz"Failed to ensure playlist exists: F)r   r   r   r   r   r   r   r+   r   r   r@   )r   r2   rB   playlist_pathr   r   rH   s          r   ensure_playlist_exists)HLSPlaylistManager.ensure_playlist_exists  s    	G0023H$6M '')) --GGDIIg.56 .   #5m_!EF ''0 .-  	KK B1#FG	s0   AB2 $B!)7B2 !
B/+B2 2
C$<CC$N
keep_countc                 r   Uc  UR                   n [        UR                  5       5      n[        UR	                  S5      S S9nSn[        U5      U:  aC  USU*  nU H7  n UR                  5         US-  nU R                  R                  SU 35        M9     US:  a+  U R                  R                  S
U SUR                   35        U$ ! [         a,  nU R                  R                  SU S	U 35         SnAM  SnAff = f! [         a(  nU R                  R                  SU 35         SnAgSnAff = f)z
Clean up old segment files beyond the configured limit.

Args:
    channel (Channel): Channel to clean up
    keep_count (int, optional): Number of segments to keep
    
Returns:
    int: Number of segments deleted
Nr   c                 6    U R                  5       R                  $ N)statst_mtime)xs    r   <lambda>9HLSPlaylistManager.cleanup_old_segments.<locals>.<lambda>R  s    1668CTCTr!   )keyr   r   zDeleted segment: zFailed to delete segment r:   zCleaned up z old segments for zFailed to cleanup segments: )ry   r   r   sortedr   r   unlinkr   debugr?   r   r+   rF   r   r@   )	r   r2   r   rB   r   deleted_countsegments_to_deletesegmentrH   s	            r   cleanup_old_segments'HLSPlaylistManager.cleanup_old_segmentsB  s@     --J	G0023HhmmF39TUHM8}z)%-l
{%;"1GX(%*)),=gY*GH	  2 q   ;}o=OPWP\P\~!^_   # X++.GyPRSTRU,VWWX  	KK <QC@A	sB   AD !3C6D 
D!C<6D <DD 
D6D11D6)r   r   )r   r   r   r   r   r   r
   r   r   r   r   r   r   r   r   r!   r   r   r     sY    @ g  $  D#g #$ #J%G %# %Z] % %r!   r   )r   osr(   r   r   shutilpathlibr   typingr   r   r   r   django.confr   django.utilsr	   apps.streams.modelsr
   r   r   r   r   r   r   r   r!   r   <module>r     sI    
      , ,   ! j jW Wtx xr!   