U
    	h}J                     @   sp  d Z ddlZddlZddlmZ ddlmZmZ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 dd
lmZmZmZ ddlm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& ddl'm(Z(m)Z)m*Z*m+Z+m,Z, ddl-m.Z.m/Z/m0Z0 ddl1m2Z2m3Z3m4Z4 ddl5m6Z6 G dd dee"Z7G dd dee"Z8G dd dee"Z9G dd dee"Z:G dd  d ee"Z;G d!d" d"ee"Z<G d#d$ d$eeZ=G d%d& d&eeZ>G d'd( d(eeZ?ed)d* Z@ed+d, ZAed-d. ZBed/d0 ZCed1d2 ZDeeed3gd4d5 ZEeeed3gd6d7 ZFeeed3gd8d9 ZGd:d; ZHd<d= ZIdS )>z
Stream Management Views

This module contains views for managing streaming channels, sessions,
configurations, and real-time stream control operations.
    N)Path)renderget_object_or_404redirectreverse)LoginRequiredMixin)login_required)require_http_methods)csrf_protect)messages)JsonResponseHttp404HttpResponse)reverse_lazy)ListView
CreateView)method_decorator)settings)View)Q)	Paginator   )ChannelStreamSession
HLSSegmentVideoConfigurationAudioConfiguration)start_stream_capturestop_stream_capturecreate_playlist_for_channel)ChannelFormVideoConfigurationFormAudioConfigurationForm)JingleTemplatec                   @   s(   e Zd ZdZdZdZdd Zdd ZdS )	ChannelListViewzo
    List view for streaming channels with filtering and search,
    implemented with the base View class.
    zstreams/channel/list.html   c                 C   s   t jdd}|jdp d }|rN|t|dt|dB t|dB }|jdp\d	 }|d	krx|jd
d}n|dkr|jdd}|S )N
created_byz-created_atsearch )Zname__icontains)Zslug__icontains)Zdescription__icontainsstatusactiveT	is_activeinactiveF)
r   objectsselect_relatedorder_byGETgetstripfilterr   lower)selfrequestqsr'   r)    r9   6/var/www/html/JingleDetector/src/apps/streams/views.pyget_queryset,   s     zChannelListView.get_querysetc           
      O   s~   |  |}t|| j}||jd}t|j}|D ]}| |_	q6||jdd|jdd|||
 d}	t|| j|	S )Npager'   r(   r)   )channelsr'   status_filter	paginatorpage_objis_paginated)r;   r   paginate_byget_pager1   r2   listobject_listget_active_sessionactive_sessionhas_other_pagesr   template_name)
r6   r7   argskwargsquerysetr?   r@   r=   channelcontextr9   r9   r:   r2   A   s    

zChannelListView.getN)__name__
__module____qualname____doc__rI   rB   r;   r2   r9   r9   r9   r:   r$   "   s
   r$   c                   @   s   e Zd ZdZdd ZdS )ChannelDetailViewzstreams/channel/detail.htmlc                 O   sR   t t|d}||jdddd d | tj t	j d}t
|| j|S )Npkvideo_configaudio_config-started_at
   )rM   Zrecent_sessionsrG   video_configsaudio_configs)r   r   sessionsr/   r0   rF   r   r.   allr   r   rI   )r6   r7   rU   rJ   rK   rM   rN   r9   r9   r:   r2   [   s     	zChannelDetailView.getNrO   rP   rQ   rI   r2   r9   r9   r9   r:   rS   X   s   rS   c                   @   s    e Zd ZdZdd Zdd ZdS )ChannelCreateViewstreams/channel/form.htmlc                 O   s   t || jdt iS )Nform)r   rI   r    )r6   r7   rJ   rK   r9   r9   r:   r2   m   s    zChannelCreateView.getc                 O   sL   t |j}| r:|jdd}|j|_|  ttdS t|| j	d|iS )NF)commitzstreams:channel_listra   )
r    POSTis_validsaveuserr&   r   r   r   rI   )r6   r7   rJ   rK   ra   rM   r9   r9   r:   postp   s    
zChannelCreateView.postN)rO   rP   rQ   rI   r2   rg   r9   r9   r9   r:   r_   j   s   r_   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ChannelUpdateViewr`   c                 C   s   t t|dS )NrT   )r   r   )r6   rU   r9   r9   r:   
get_object}   s    zChannelUpdateView.get_objectc                 O   s&   |  |}t|d}t|| jd|iS )Ninstancera   )ri   r    r   rI   r6   r7   rU   rJ   rK   rM   ra   r9   r9   r:   r2      s    

zChannelUpdateView.getc                 O   s\   |  |}t|j|d}| rJ|  t|d ttdd|j	idS t
|| jd|iS )Nrj   zChannel updated successfully!streams:channel_detailrU   )rK   ra   )ri   r    rc   rd   re   r   successr   r   rU   r   rI   rl   r9   r9   r:   rg      s    
zChannelUpdateView.postN)rO   rP   rQ   rI   ri   r2   rg   r9   r9   r9   r:   rh   z   s   rh   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )StreamSessionListViewzstreams/session/list.htmlr%   c                 C   sv   t jdddd}|jd}|r2|j|d}|jd}|rN|j|d}|jdp\d	 }|rr|j|d
}|S )NrM   rV   rW   rX   )
channel_idr)   r)   r'   r(   )Zchannel__name__icontains)r   r.   r/   r0   r1   r2   r4   r3   )r6   r7   r8   rp   r)   r'   r9   r9   r:   r;      s"      z"StreamSessionListView.get_querysetc              
   O   sx   |  |}t|| j}||jd}t|jtj	j
dd|jdd|jddtj||| |d	}t|| j|S )Nr<   Tr+   rM   r(   r)   )	r\   r=   Zchannel_filterr>   Zstatus_choicesr?   r@   rA   r7   )r;   r   rB   rC   r1   r2   rD   rE   r   r.   r4   r   STATUS_CHOICESrH   r   rI   )r6   r7   rJ   rK   rL   r?   r@   rN   r9   r9   r:   r2      s    
zStreamSessionListView.getN)rO   rP   rQ   rI   rB   r;   r2   r9   r9   r9   r:   ro      s   ro   c                   @   s   e Zd ZdZdd ZdS )StreamSessionDetailViewzstreams/session/detail.htmlc           	      O   st   t t|d}|j }|jtdtdd}||jdd d | |jdd |d	 |d
 d}t	|| j
|S )NrT   duration	file_size)total_duration
total_size-processed_atr%   T)is_availablerv   rw   )sessionZrecent_segmentstotal_segmentsZavailable_segmentsrv   rw   )r   r   segmentsr]   	aggregateSumr0   countr4   r   rI   )	r6   r7   rU   rJ   rK   rz   Zsegments_qsZaggrN   r9   r9   r:   r2      s    
 zStreamSessionDetailView.getNr^   r9   r9   r9   r:   rs      s   rs   c                       s4   e Zd ZdZeZdZdZdd Z fddZ	  Z
S )ConfigurationListViewz@
    Combined list view for video and audio configurations.
    zstreams/config/list.htmlZconfigurationsc                 C   s
   t j S )z?Return empty queryset since we handle data in get_context_data.)r   r.   none)r6   r9   r9   r:   r;      s    z"ConfigurationListView.get_querysetc                    s:   t  jf |}tj d|d< tj d|d< |S )z(Get both video and audio configurations.namerZ   r[   )superget_context_datar   r.   r]   r0   r   )r6   rK   rN   	__class__r9   r:   r      s    z&ConfigurationListView.get_context_data)rO   rP   rQ   rR   r   modelrI   context_object_namer;   r   __classcell__r9   r9   r   r:   r      s   r   c                       s4   e Zd ZdZeZeZdZe	dZ
 fddZ  ZS )VideoConfigurationCreateViewz/
    Create view for video configurations.
    zstreams/config/video_form.htmlstreams:config_listc                    s   t | jd t |S )Add success message.z)Video configuration created successfully!r   rn   r7   r   
form_validr6   ra   r   r9   r:   r      s    z'VideoConfigurationCreateView.form_valid)rO   rP   rQ   rR   r   r   r!   
form_classrI   r   success_urlr   r   r9   r9   r   r:   r      s   r   c                       s4   e Zd ZdZeZeZdZe	dZ
 fddZ  ZS )AudioConfigurationCreateViewz/
    Create view for audio configurations.
    zstreams/config/audio_form.htmlr   c                    s   t | jd t |S )r   z)Audio configuration created successfully!r   r   r   r9   r:   r      s    z'AudioConfigurationCreateView.form_valid)rO   rP   rQ   rR   r   r   r"   r   rI   r   r   r   r   r9   r9   r   r:   r      s   r   c                 C   sH   t t|d}|jjdd }|||r4d|j dndd}t| d|S )	z3
    HLS media player for live stream viewing.
    idr*   rq   z/media/streams/z/hls/index.m3u8N)rM   rG   hls_urlzstreams/hls_player.html)r   r   r\   r4   firstslugr   )r7   rp   rM   rG   rN   r9   r9   r:   hls_player_view  s    r   c                 C   s   t t|d}ttjd |j d }g }| rj|d }ttt	|t
jjdd}dd |d	d
 D }||d}t| d|S )z9
    Browse and view TS segment files for a channel.
    r   
OUTPUT_DIRhlsz*.tsTkeyr   c                 S   s(   g | ] }|t j|t j|d qS ))pathr   size)osr   basenamegetsize.0fr9   r9   r:   
<listcomp>$  s     z#ts_file_browser.<locals>.<listcomp>N2   )rM   ts_fileszstreams/ts_browser.htmlr   r   r   r   STREAM_CONFIGr   existssortedglobstrr   r   getmtimer   )r7   rp   rM   Zhls_pathr   Z
ts_patternrN   r9   r9   r:   ts_file_browser  s    r   c                 C   s   t t|d}ttjd |j d }g }| rj|d }ttt	|t
jjdd}dd |d	d
 D }||d}t| d|S )z/
    View extracted iframes for a channel.
    r   r   iframesz*.pngTr   c                 S   s   g | ]}|t j|d qS ))r   r   )r   r   r   r   r9   r9   r:   r   ;  s     z"iframe_gallery.<locals>.<listcomp>Nd   )rM   iframe_fileszstreams/iframe_gallery.htmlr   )r7   rp   rM   Ziframes_pathr   Ziframe_patternrN   r9   r9   r:   iframe_gallery-  s    r   c                 C   s0   t t|d}|jjdd}||d}t| d|S )z1
    Preview jingle templates for a channel.
    r   Tr+   )rM   jingle_templateszstreams/jingle_preview.html)r   r   r   r4   r   )r7   rp   rM   r   rN   r9   r9   r:   jingle_previewD  s    r   c              
   C   s   t t|d}dddd}||kr(td|dkrDttjd | }n ttjd |j ||  | }| rt|	 s|td	d
ddddd}|j
 }||d}	t|d2}
t|
 |	d}d| d|d< |W  5 Q R  S Q R X dS )zB
    Serve media files (TS, PNG, M3U8) for the media players.
    )r   r   r   z
../jingles)r   r   jingleszInvalid file typer   r   zFile not foundz
video/mp2tzapplication/vnd.apple.mpegurlz	image/pngz
image/jpeg)z.tsz.m3u8z.pngz.jpgz.jpegzapplication/octet-streamrb)content_typezinline; filename=""zContent-DispositionN)r   r   r   r   r   
MEDIA_ROOTr   r   r   is_filesuffixr5   r2   openr   read)r7   Zchannel_slugZ	file_typefilenamerM   Zfile_mappings	file_pathcontent_typesfile_extr   r   responser9   r9   r:   serve_media_fileS  s0     
r   rc   c              
   C   s  t t|d}| r.t| d td|jdS z| jd}| jd}t	j
t|j||d}t| d|j  | jd	r|  | }t| d
||dW S td|jdW S  tk
 r } z,t| dt|  td|jd W Y S d}~X Y nX dS )z
    HTMX endpoint to start stream capture for a channel.
    
    Args:
        request: HTTP request object
        channel_id: ID of the channel to start streaming
        
    Returns:
        HttpResponse: HTML content for HTMX swap
    r   z,Channel already has an active stream sessionrm   rT   rV   rW   )rp   video_config_idaudio_config_idzStream capture started for 
HX-Request#streams/partials/stream_status.htmlrM   rG   zFailed to start stream: N)r   r   rF   r   errorr   rU   rc   r2   r   delayr   r   rn   r   headersrefresh_from_dbr   	Exception)r7   rp   rM   r   r   taskrG   er9   r9   r:   start_stream  s0    
r   c              
   C   s   t t|d}| s0t| d td|jjdS znt	t
|j}t| d|jj  | jdr|j}|  | }t| d||dW S td|jjdW S  tk
r } z.t| d	t
|  td|jjd W Y S d
}~X Y nX d
S )z
    HTMX endpoint to stop an active stream session.
    
    Args:
        request: HTTP request object
        session_id: ID of the session to stop
        
    Returns:
        HttpResponse: HTML content for HTMX swap
    r   z Session is not currently runningrm   rT   zStream stopped for r   r   r   zFailed to stop stream: N)r   r   
is_runningr   r   r   rM   rU   r   r   r   r   rn   r   r   r2   r   rF   r   r   )r7   
session_idrz   r   rM   rG   r   r9   r9   r:   stop_stream  s&    
r   c              
   C   s   t t|d}| r.t| d td|jdS z.|jj}|	  t
| d| d tdW S  tk
r } z,t| dt|  td|jd W Y S d	}~X Y nX d	S )
z
    Delete a stream session and all associated segments.
    
    Args:
        request: HTTP request object
        session_id: ID of the session to delete
        
    Returns:
        HttpResponse: Redirect to session list
    r   z/Cannot delete a running session. Stop it first.zstreams:session_detailrT   zSession for z has been deletedzstreams:session_listzFailed to delete session: N)r   r   r   r   r   r   r   rM   r   deletern   r   r   )r7   r   rz   channel_namer   r9   r9   r:   delete_session  s    
r   c              
   C   sj   z.t t|d}|| | d}t| d|W S  tk
rd } ztd| d W Y S d}~X Y nX dS )z
    HTMX endpoint for real-time stream status updates.
    
    Args:
        request: HTTP request object
        session_id: ID of the session to check
        
    Returns:
        HttpResponse: HTML fragment with session status
    r   )rz   rt   r   z$streams/partials/session_status.htmlz!<div class="text-red-500">Error: z</div>N)r   r   rt   r   r   r   r   )r7   r   rz   rN   r   r9   r9   r:   stream_status  s    r   c                 C   sP   t t|d}|jd}| jdd}t|d}||}||d}t| d|S )z
    HTMX endpoint for paginated segment list.
    
    Args:
        request: HTTP request object
        session_id: ID of the session
        
    Returns:
        HttpResponse: HTML fragment with segment list
    r   rx   r<   r   rY   )rz   r|   z"streams/partials/segment_list.html)	r   r   r|   r0   r1   r2   r   rC   r   )r7   r   rz   r|   r<   r?   Zsegments_pagerN   r9   r9   r:   segment_list!  s    

r   )JrR   r   r   pathlibr   django.shortcutsr   r   r   r   Zdjango.contrib.auth.mixinsr   django.contrib.auth.decoratorsr   Zdjango.views.decorators.httpr	   django.views.decorators.csrfr
   django.contribr   django.httpr   r   r   django.urlsr   Zdjango.views.genericr   r   django.utils.decoratorsr   django.confr   django.viewsr   django.db.modelsr   django.core.paginatorr   modelsr   r   r   r   r   tasksr   r   r   formsr    r!   r"   Zapps.jingles.modelsr#   r$   rS   r_   rh   ro   rs   r   r   r   r   r   r   r   r   r   r   r   r   r   r9   r9   r9   r:   <module>   sl   6+




.2+