U
    Bhy                     @   s2  d dl Z d dl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 d dlmZmZ G d	d
 d
ejZG dd dejZG dd dejZG dd dejZG dd dejZG dd dejZG dd dejZG dd dejZG dd dejZG dd dejZG dd dejZdS )    N)datetime)models)gettext_lazy)ValidationError)timezone)User)jingle_upload_pathmd5_upload_pathc                   @   s   e Zd ZejddZejeejddddZ	ej
ddddZej
ddddZej
ddddZej
ddddZej
ddddZej
ddddZej
dddddZej
d	ddddZejddd
Zejddd
ZG dd dZdS )ChannelsTprimary_keyid_user	db_columnblanknull   
max_lengthr   r   ZnetworkNamer   r   r   r   ZzoneNamer   r   c                   @   s   e Zd ZdZdS )zChannels.Metar
   N__name__
__module____qualname__db_table r   r   //var/www/html/Focus/src/apps/channels/models.pyMeta   s   r   N)r   r   r   r   	AutoField
id_channel
ForeignKeyr   
DO_NOTHINGr   	CharFieldchannel_nameZchannel_descZchannel_langZchannel_genreZftp_channel_nameZsfr_channel_namenetworknamezonenameDateTimeFieldcreation_datetimemodif_datetimer   r   r   r   r   r
      s   r
   c                   @   s   e Zd ZejddZejeejddddZ	ej
ddddZej
ddddZej
ddddZej
ddddZej
ddddZG dd	 d	Zd
S )ChannelsZoneTr   r    r   r   r       c                   @   s   e Zd ZdZdS )zChannelsZone.MetaZChannels_zoneNr   r   r   r   r   r   ,   s   r   N)r   r   r   r   r   Zid_zone_channelr!   r
   r"   r    r#   Zregionr&   r%   Zverifs_numberZsfr_namer   r   r   r   r   r*   #   s   r*   c                   @   s`   e Zd ZejddZejeejddddZ	ej
dddddZej
dddddZG d	d
 d
ZdS )ChannelCodecTr   r    r   Z
FFmpeg_cmdr   r   Z	Ateme_cmdc                   @   s   e Zd ZdZdS )zChannelCodec.MetaZChannel_codecNr   r   r   r   r   r   6   s   r   N)r   r   r   r   r   Zid_ch_codecr!   r
   r"   r    r#   Z
ffmpeg_cmdZ	ateme_cmdr   r   r   r   r   r,   0   s
   r,   c                       sz  e Zd ZdZdedfdedfdedfded	fd
edfdedfdedfdedfdedfdedfdedfgZdedfdedfdedfdedfd ed!fd"ed#fd$ed%fd&ed'fd(ed)fd*ed+fd,ed-fd.ed/fd0ed1fgZd2ed3fd4ed5fd6ed7fd8ed9fd:ed;fd<ed=fgZej	d>ed?d@Z
ejeejdAedBedCdDdEdEdFZejdGedHedId>dJZejdKeedLedMd>dNZejdKed.edOedPd>dQZejed6edRedSdTZejeedUedVdWZejeedXedYd>d>dZZejed[ed\d>d>d]Zejed^ed_d>d>d]Zejed>ed`edadbZ ej!d>edcedddeZ"ej!d>edfedgdeZ#ej$d>edhedid>djZ%e& Z'e& Z(e) Z*G dkdl dlZ+dmdn Z, fdodpZ-dqdr Z.dsdt Z/ fdudvZ0dwdx Z1dydz Z2d{d| Z3e4d}d~ Z5e4dd Z6e4dd Z7e4dd Z8e4dd Z9e4dd Z:dd Z;  Z<S )Jinglesa  
    Channel jingles and station IDs with enhanced placement types and file management.
    
    Represents audio content that is played during broadcasts including
    station identifications, bumpers, promos, and transition sounds.
    Supports advanced scheduling, audio fingerprinting, usage tracking,
    and automated file integrity verification.
    
    Features:
        - Automatic MD5 checksum generation and storage
        - Organized file storage by channel and date
        - Audio fingerprinting for content detection
        - Flexible placement and scheduling options
        - File integrity verification
    
    Attributes:
        channel: Foreign key to the channel this jingle belongs to
        name: Human-readable name for the jingle
        jingle_type: Type of jingle (station_id, bumper, promo, etc.)
        placement_type: When the jingle should be played in the broadcast
        file: Audio file for the jingle (auto-organized by channel/date)
        md5_file: MD5 checksum file (auto-generated after upload)
        duration: Length of the jingle in seconds
        audio_fingerprint: Audio fingerprint data for automatic detection
        frames_fingerprint: Frames fingerprint data for automatic detection
        is_active: Whether this jingle is currently active
        priority: Priority level for jingle selection
        file_size: Size of the audio file in bytes
        created_at: Timestamp when the jingle was created
        updated_at: Timestamp when the jingle was last modified
    
    Related Models:
        - Channel: One-to-many relationship (channel can have multiple jingles)
        - JingleDetection: One-to-many relationship (jingle can have multiple detections)
    Z
station_idz
Station IDZbumperZBumperZpromoZPromoZ
transitionZ
TransitionZcommercial_breakzCommercial BreakZ
news_introz
News IntroZweather_introzWeather IntroZsports_introzSports IntroZmusic_introzMusic IntroZshow_openerzShow OpenerZshow_closerzShow CloserstartzStart of ShowendzEnd of ShowZcommercial_startzStart of Commercial BreakZcommercial_endzEnd of Commercial BreakZprogram_transitionzProgram TransitionZsegment_transitionzSegment TransitionhourlyZHourlyZhalf_hourlyzHalf HourlyZquarter_hourlyzQuarter HourlyZtop_of_hourzTop of HourZbottom_of_hourzBottom of HourrandomzRandom PlacementZmanualzManual Only   zVery Low   ZLow   ZNormal   ZHigh   z	Very High   CriticalTz	Jingle ID)r   verbose_namejinglesChannelzChannel this jingle belongs tor    F)	on_deleterelated_namer9   	help_textr   r   r   r   zJingle Namez#Human-readable name for this jingle)r   r9   r>   db_index   zJingle TypezType of jingle content)r   choicesr9   r>   r?   zPlacement Typez2When this jingle should be played in the broadcast)r   rA   defaultr9   r>   r?   zPriority LevelzEPriority level for jingle selection (higher number = higher priority))rA   rB   r9   r>   z
Audio FilezHAudio file for this jingle (automatically organized by channel and date))	upload_tor9   r>   zMD5 Checksum Filez>MD5 checksum file (automatically generated after audio upload))rC   r9   r>   r   r   zDuration (seconds)z!Duration of the jingle in seconds)r9   r>   r   r   zFile Size (bytes)zSize of the audio file in byteszAudio Metadataz@Additional audio metadata (bitrate, sample rate, channels, etc.))rB   r   r9   r>   zAudio Fingerprintz9Audio fingerprint data for automatic detection in streams)r   r9   r>   zFrames Fingerprintz:Frames fingerprint data for automatic detection in streamsz	Is Activez=Whether this jingle is currently active and available for use)rB   r9   r>   r?   c                   @   s   e Zd ZedZedZdZddgZej	ddgdej	d	d
gdej	ddgdgZ
ejejddddejejddddgZdS )zJingles.MetaZJingler-   r:   z-creation_datetimenamechannel	is_active)fieldsjingle_typeplacement_typepriorityr   )Zduration__gteZpositive_duration)checkrD   )Zfile_size__gteZpositive_file_sizeN)r   r   r   _r9   verbose_name_pluralr   orderingr   IndexindexesCheckConstraintQconstraintsr   r   r   r   r      s"   

r   c                 C   s    | j  d| jr| jj nd dS )Nz (z
No Channel))rD   rE   selfr   r   r   __str__  s    zJingles.__str__c                    s   d}| j rHz tjj| j d}|j| jk}W qL tjk
rD   d}Y qLX nd}t j|| |r| jr|   | 	  t jdddgd dS )	zb
        Enhanced save method with automatic MD5 generation and file metadata extraction.
        F)pkTmd5_fileduration	file_size)update_fieldsN)
rX   r-   objectsgetfileDoesNotExistsupersave_generate_md5_file_extract_file_metadata)rV   argskwargsZis_new_fileZold_instance	__class__r   r   rb     s    
zJingles.savec              
      s   j s
dS zt } j d t fdddD ]}|| q2| }tj	 j j
}| d| d}tj|d  d}t |}dd	lm}  jj|||d
dd W nR tk
r }	 z2ddl}
|
t}|d j dt|	  W 5 d}	~	X Y nX dS )zI
        Generate MD5 checksum file for the uploaded audio file.
        Nr   c                      s    j dS Ni   r_   readr   rU   r   r   <lambda>:      z,Jingles._generate_md5_file.<locals>.<lambda>rm   z  
z.md5)ContentFileutf-8F)rb   z"Failed to generate MD5 for jingle : )r_   hashlibmd5seekiterupdate	hexdigestospathbasenamerD   splitextr	   django.core.files.basero   rY   rb   encode	Exceptionlogging	getLoggerr   error	id_jinglestr)rV   md5_hashchunkZmd5_checksumZoriginal_filenameZmd5_contentZmd5_filenameZmd5_pathro   er   loggerr   rU   r   rc   -  s,    


zJingles._generate_md5_filec                 C   s  | j s
dS ddl}|t}z
| j j| _d}zddlm} t| j drR| j j	n| j j j
}||}|r<t|dr<t|jdrt|jj| _d}|d	| j d
| j d i }t|jdr|jj|d< t|jdr|jj|d< nt|jdr|jj|d< t|jdr|jj|d< t|jdr6t|jj|d< || _W nV tk
r^   |d Y n8 tk
r } z|dt|  W 5 d}~X Y nX |szddlm}	 ddlm}
 |
ds|
dr(t| j dr| j j	n| j j j
}|	|}tt|d | _d}|d| j d
| j d n
|d W nV tk
rT   |d Y n8 tk
r } z|dt|  W 5 d}~X Y nX |sLzbddl }t| j dr| j j	n| j j j
}|j!|d}t|| _d}|d| j d
| j d W nV tk
r   |d Y n8 tk
rJ } z|dt|  W 5 d}~X Y nX |s"| j j
" #d r"zddl$}t| j dr| j j	n| j j j
}|%|d!D}|& }|' }t|| | _d}|d"| j d
| j d W 5 Q R X W n8 tk
r  } z|d#t|  W 5 d}~X Y nX |sАz(ddl(}ddl)}t| j drR| j j	n| j j j
}dd$d%d&d'd(d)|g}|j*|ddd*d+}|j+dkrP|,|j-}d}d,|krd-|d, krt.|d, d- }nXd.|kr t|d. dkr |d. D ]2}|/d/d0krd-|krt.|d- } q q|rPt|| _d}|d1| j d
| j d W n| |j0|j1t2|j3fk
r } z|d2t|  W 5 d}~X Y n8 tk
r } z|d3t|  W 5 d}~X Y nX |s|d4| j d5 d*| _| jr&| jdkr&|d6| j d7| j d8 d*| _W nt tk
r } zT|4d9| j d:t|  t| d;rl| jsrd| _t| d-r| jsd*| _W 5 d}~X Y nX dS )<z
        Extract comprehensive metadata from the audio file including duration, 
        bitrate, sample rate, channels, and other audio properties.
        Nr   F)Filery   infolengthTz,Extracted metadata using mutagen for jingle z: duration=sbitratesample_rate
sampleratechannelsmodez8Mutagen not installed. Install with: pip install mutagenz)Failed to extract metadata with mutagen: )AudioSegment)whichZffprobeZffmpegi  z*Extracted metadata using pydub for jingle z>ffmpeg/ffprobe not found. Install ffmpeg for audio processing.z4pydub not installed. Install with: pip install pydubz'Failed to extract metadata with pydub: )ry   z,Extracted metadata using librosa for jingle z8librosa not installed. Install with: pip install librosaz)Failed to extract metadata with librosa: .wavrz)Extracted metadata using wave for jingle z&Failed to extract metadata with wave: z-vquietz-print_formatjsonz-show_formatz-show_streams   )capture_outputtexttimeoutformatrZ   streamsZ
codec_typeaudioz,Extracted metadata using ffprobe for jingle z)Failed to extract metadata with ffprobe: zUnexpected error with ffprobe: z&Could not extract duration for jingle z). Setting default duration to 30 seconds.zInvalid duration z for jingle z. Setting to 30 seconds.z&Failed to extract metadata for jingle rq   r[   )5r_   r   r   r   sizer[   Zmutagenr   hasattrry   rD   r   intr   rZ   r   r   r   r   r   r   r   metadataImportErrorwarningr~   Zpydubr   Zpydub.utilsr   	from_filelenlibrosaZget_durationlowerendswithwaveopenZ
getnframesZgetframerate
subprocessr   run
returncodeloadsstdoutfloatr^   TimeoutExpiredCalledProcessErrorFileNotFoundErrorJSONDecodeErrorr   )rV   r   r   Zmetadata_extractedZMutagenFile	file_pathZ
audio_fileZadditional_metadatar   r   r   r   r   duration_secondsr   Zwav_fileframesr   r   r   cmdresultdatarZ   streamr   r   r   rd   U  s    


& 
& 
 & *&   	

  $&
zJingles._extract_file_metadatac                    s`   t    | jr\ddddddg}tj| jjd  }||kr\tdt	d	
d
|idS )z#
        Model validation.
        z.mp3r   z.aacz.m4az.oggz.flacr2   r_   z3Only audio files are allowed. Supported formats: {}z, N)ra   cleanr_   rx   ry   r{   rD   r   r   rL   r   join)rV   allowed_extensionsZfile_extensionrg   r   r   r     s    
 zJingles.cleanc                 C   s   | j r| j jS dS )z0
        Get the URL of the audio file.
        N)r_   urlrU   r   r   r   get_file_url  s    zJingles.get_file_urlc                 C   s   | j r| j jS dS )z7
        Get the URL of the MD5 checksum file.
        N)rY   r   rU   r   r   r   get_md5_url  s    zJingles.get_md5_urlc                    s    j r jsdS zx jd  j d}| d }t } j d t fdddD ]}|	| q`|
 }| | kW S  tk
r   Y dS X dS )z
        Verify the integrity of the audio file using the stored MD5 checksum.
        
        Returns:
            bool: True if file integrity is verified, False otherwise
        Fr   rp   c                      s    j dS ri   rj   r   rU   r   r   rl   7  rm   z/Jingles.verify_file_integrity.<locals>.<lambda>rm   N)r_   rY   rt   rk   decodesplitrr   rs   ru   rv   rw   r   r~   )rV   Zstored_md5_contentZ
stored_md5r   r   Zcurrent_md5r   rU   r   verify_file_integrity$  s    zJingles.verify_file_integrityc                 C   s0   | j s
dS | j d }| j d }|dd|dS )z2
        Get duration formatted as MM:SS.
        z00:00<   02d:)rZ   )rV   minutessecondsr   r   r   formatted_duration@  s
    

zJingles.formatted_durationc                 C   sN   | j s
dS t| j }dD ](}|dk r8|dd|   S |d }q|ddS )zC
        Get file size formatted in human-readable format.
        z0 B)BKBMBGBg      @z.1f z TB)r[   r   )rV   r   unitr   r   r   formatted_file_sizeL  s    

zJingles.formatted_file_sizec                 C   s   | j r| j dS dS )zGet bitrate from metadata.r   Nr   r^   rU   r   r   r   r   [  s    zJingles.bitratec                 C   s   | j r| j dS dS )zGet sample rate from metadata.r   Nr   rU   r   r   r   r   `  s    zJingles.sample_ratec                 C   s   | j r| j dS dS )z%Get number of channels from metadata.r   Nr   rU   r   r   r   r   e  s    zJingles.channelsc                 C   s*   | j r&tj| j jd  ddS dS )z%Get audio format from file extension.r2   . N)r_   rx   ry   r{   rD   upperreplacerU   r   r   r   audio_formatj  s     zJingles.audio_formatc                 C   s~   | j | j| jd}| jrz| jr.| j d|d< | jrD| j d|d< | jrz| jdkrXdn| jdkrfd	n
| j d
}||d< |S )z
        Get formatted metadata for display purposes.
        
        Returns:
            dict: Formatted metadata information
        )rZ   r[   r   z kbpsr   z Hzr   r2   ZMonor3   ZStereoz	 channelsr   )r   r   r   r   r   r   r   )rV   Zdisplay_infoZchannel_textr   r   r   get_metadata_displayq  s    (zJingles.get_metadata_display)=r   r   r   __doc__rL   ZJINGLE_TYPESZPLACEMENT_TYPESZPRIORITY_LEVELSr   r   r   r!   r
   CASCADErE   r#   rD   rH   rI   PositiveSmallIntegerFieldrJ   	FileFieldr   r_   r	   rY   PositiveIntegerFieldrZ   PositiveBigIntegerFieldr[   	JSONFielddictr   	TextFieldZaudio_fingerprintZframes_fingerprintBooleanFieldrF   r'   r(   r)   IntegerFieldZ	is_deleter   rW   rb   rc   rd   r   r   r   r   propertyr   r   r   r   r   r   r   __classcell__r   r   rg   r   r-   :   s&  &































	( 2





r-   c                   @   s   e Zd ZejddZejeejddddZ	ej
ddddZejdddZejdddZej
ddddZej
ddddZG dd	 d	Zd
S )EpgTr   r    r   r   r   r   c                   @   s   e Zd ZdZdS )zEpg.Metar   Nr   r   r   r   r   r     s   r   N)r   r   r   r   r   id_emissionr!   r
   r"   r    r#   emission_namer'   
start_timeend_timegenrecategoryr   r   r   r   r   r     s   r   c                   @   sT   e Zd ZejddZejdddZejddddZ	ejddddZ
G dd dZdS )	RealTimeAdbreakTr   r   r   r   c                   @   s   e Zd ZdZdS )zRealTimeAdbreak.MetaZReal_time_adbreakNr   r   r   r   r   r     s   r   N)r   r   r   r   r   Zid_rtar   r    r#   start_atrZ   r   r   r   r   r   r     s
   r   c                   @   sf   e Zd ZejddZe Ze Z	ej
ddZej
ddZej
ddZej
ddZG dd dZdS )Adbreak_predictTr   r   r   c                   @   s   e Zd ZdZdS )zAdbreak_predict.Metar   Nr   r   r   r   r   r     s   r   Nr   r   r   r   r   Zid_adbreak_historyr   r    r'   r   r#   daytimer$   rZ   r   r   r   r   r   r     s   r   c                   @   sP   e Zd ZejddZe Ze Z	ej
dddZejddZG dd dZdS )	AdbreaksTr   r   r   r   c                   @   s   e Zd ZdZdS )zAdbreaks.Metar   Nr   r   r   r   r   r     s   r   N)r   r   r   r   r   Z
id_adbreakr   r    r'   r   
FloatFieldrZ   r#   r$   r   r   r   r   r   r     s   r   c                       s   e Zd ZdZejdddZejdddZejdddZ	ej
d	d
ddZej
d	dddddZej
ddddddZej
ddddddZejddddZejddddZejddddZG dd  d Z fd!d"Z  ZS )#ConductorDataz(
    Model to store conductor data.
    DatezThe date of the ad-break.)r9   r>   zAd Break Start TimezThe start time of the ad break.zAd Break End TimezThe end time of the ad break.2   r;   zThe channel of the broadcast.)r   r9   r>   DurationTzThe duration of the ad break.)r   r9   r   r   r>   r   zShow BeforezThe show before the ad break.z
Show AfterzThe show after the ad break.zShow Duringz:Boolean indicating if the ad break is shown during a show.)rB   r9   r>   z
Created Atz.The date and time when the record was created.)auto_now_addr9   r>   z
Updated Atz3The date and time when the record was last updated.)auto_nowr9   r>   c                   @   s&   e Zd ZdZdZejdgddgZdS )zConductorData.MetaZconductor_datazConductor Dataad_break_start_atZidx_ad_break_start_at)rG   rD   N)r   r   r   r   rM   r   rO   rP   r   r   r   r   r     s   r   c                    s2   | j s t   tjdd | _ t j|| d S )Nr2   )days)dater   now	timedeltara   rb   )rV   re   rf   rg   r   r   rb     s    zConductorData.save)r   r   r   r   r   	DateFieldr   	TimeFieldr   Zad_break_end_atr#   rE   ZdureeZshow_beforeZ
show_afterr   Zif_show_duringr'   
created_at
updated_atr   rb   r   r   r   rg   r   r     sp   r   c                   @   sf   e Zd ZejddZe Ze Z	ej
ddZej
ddZej
ddZej
ddZG dd dZdS )AdbreakHistoryTr   r   r   c                   @   s   e Zd ZdZdS )zAdbreakHistory.MetaZAdbreak_historyNr   r   r   r   r   r     s   r   Nr   r   r   r   r   r    s   r  c                   @   sb   e Zd ZejddZe ZejddZ	e
 Ze
 ZejddZejddZG dd dZdS )	EmissionsTr   r   r   c                   @   s   e Zd ZdZdS )zEmissions.Metar  Nr   r   r   r   r   r   '  s   r   N)r   r   r   r   r   r   r   r    r#   r   r'   r   r   r   r   r   r   r   r   r   r    s   r  )rx   rr   r   	django.dbr   django.utils.translationr   rL   django.core.exceptionsr   django.utilsr   apps.accounts.modelsr   Zapps.channels.utilsr   r	   Modelr
   r*   r,   r-   r   r   r   r   r   r  r  r   r   r   r   <module>   s.   
    U
T