o
    Սdh                     @   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mZ ddlm	Z	m
Z
mZmZmZ ddlmZmZmZ ddlm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  e!e"Z#de$de	e$ee%e
e$ f f fddZ&de$de	e$ee%e
e$ f f fddZ'de$de	e$ee%e
e$ f f fddZ(de$de	e$ee%e
e$ f f fddZ)de$de	e$ee%e
e$ f f fddZ*de$de	e$ee$e+e,e	f f fddZ-de$de	e$ee$e+e	f f fddZ.de$de	e$ee$e+e,e	f f fddZ/de$de	e$ee$e+e,f f fdd Z0dTde$d$e+d%e+d&e+dee$ f
d'd(Z1dUde$d*e$d%e+dee$ fd+d,Z2dVde$d.ee+e+f dee$ fd/d0Z3de$d.ee+e+f dee$ fd1d2Z4dWde$d4e$dee$ fd5d6Z5d7e$d.ee+e+f dee$ fd8d9Z6de$de$fd:d;Z7d<e$d7e$de%fd=d>Z8dXde$d@e$de$fdAdBZ9de$deee+e+f  fdCdDZ:dEe+de$fdFdGZ;dHe$de$fdIdJZ<dYdLe+dMe+de%fdNdOZ=dHe$de$fdPdQZ>dHe$de$fdRdSZ?dS )Za  Creative Management Utility Functions

Utility functions for creative asset processing and management.
Provides file processing, validation, optimization, and helper functions.

Function Categories:
- File Processing: Upload, conversion, optimization
- Validation: File validation and compliance checking
- Metadata: File metadata extraction
- Image Processing: Image manipulation and optimization
- Video Processing: Video processing and compression
- Audio Processing: Audio file handling
- File Management: File operations and cleanup
- Format Conversion: File format conversions
- Performance: Performance optimization utilities

Functions:
- validate_creative_file: Validate uploaded creative files
- get_file_metadata: Extract file metadata
- generate_thumbnail: Generate file thumbnails
- optimize_image: Optimize image files
- compress_video: Compress video files
- convert_format: Convert file formats
- calculate_file_hash: Calculate file checksums
- get_file_dimensions: Get image/video dimensions
- extract_audio_metadata: Extract audio metadata
- validate_file_size: Validate file size limits

Integrations:
- PIL/Pillow for image processing
- FFmpeg for video/audio processing
- External APIs for content analysis
- Cloud storage services
- File validation libraries
    N)datetime)DictListOptionalTupleUnion)ImageImageOpsImageFilter)TAGS)UploadedFile)settings)ValidationError)slugify)default_storage)ContentFile	file_pathreturnc              
   C   s~  dg g i d}zt j| sd|d< |d d |W S t j| }t j| d  }||t| d|d	< |d
krF|d d d|d< g d}||vr]|d d| d d|d< |d	 d }t||sw|d d| d d|d< |dv rt	| }|d 
|d  |d 
|d  |d sd|d< nE|dv rt| }|d 
|d  |d 
|d  |d sd|d< n"|dv rt| }|d 
|d  |d 
|d  |d sd|d< t| }	|d 
|	d  |d 
|	d  |	d sd|d< td|  d|d   |W S  ty> }
 z%td|  dt|
  d|d< |d dt|
  |W  Y d}
~
S d}
~
ww )z
    Validate creative file for compliance and technical requirements.
    
    Args:
        file_path (str): Path to the file to validate
        
    Returns:
        dict: Validation results with is_valid flag and error list
    T)is_validerrorswarnings	file_infoFr   r   zFile does not exist   )size	extension	mime_typer      zFile size exceeds 50MB limit.jpg.jpeg.png.gif.webp.mp4.mov.avi.webm.mp3.wav.aac.ogg.html.htmzFile extension z not allowedr   z
MIME type z does not match file extensionr   r   r    r!   r"   r   r#   r$   r%   r&   r'   r(   r)   r*   zFile validation completed: z
 - Valid: zError validating file : zValidation error: N)ospathexistsappendgetsizesplitextlowerget_mime_typeis_valid_mime_typevalidate_image_fileextendvalidate_video_filevalidate_audio_filevalidate_file_securityloggerinfo	Exceptionerrorstr)r   validation_result	file_sizefile_extallowed_extensionsr   Zimage_validationZvideo_validationZaudio_validationZsecurity_validationexc rI   HC:\Users\vibe-look\OneDrive\Desktop\Adtlas_V\src\apps\creatives\utils.pyvalidate_creative_file<   sz   

rK   c              
   C   sx  dg g d}zt | }|  t | ^}|j\}}|dks$|dkr1|d d| d|  |dk s9|dk rF|d d| d|  |jd	vrV|d d
|j  t|drm|jrmt|dddkrm|d d W d   n1 sww   Y  W d   W |S W d   W |S 1 sw   Y  W |S  t	y } zd|d< |d dt
|  W Y d}~|S d}~ww )z
    Validate image file.
    
    Args:
        file_path (str): Path to image file
        
    Returns:
        dict: Image validation results
    Tr   r   r      r   zLarge image dimensions: xd   zSmall image dimensions: )RGBRGBALPzUnusual color mode: is_animatedn_framesr   z!GIF has many frames, may be largeNFr   r   zInvalid image file: )r   openverifyr   r4   modehasattrrT   getattrrA   rC   )r   resultimgwidthheightrH   rI   rI   rJ   r:      s<   


"r:   c              
   C   s  dg g d}zddddddd	| g}t j|ddd
}|jdkr,d|d< |d d |W S t|j}t|di dd}|dkrN|d d|dd dd |dg D }|sgd|d< |d d n)|d }t	|dd}t	|dd}	|dks|	dkr|d d| d |	  t	|di d!d}
|
d"kr|d d#|
 d$ W |S W |S  t j
y   d|d< |d d% Y |S  tjy   d|d< |d d& Y |S  ty } zd|d< |d d't|  W Y d(}~|S d(}~ww ))z
    Validate video file using FFprobe.
    
    Args:
        file_path (str): Path to video file
        
    Returns:
        dict: Video validation results
    TrL   ffprobe-vquiet-print_formatjson-show_format-show_streamscapture_outputtextr   Fr   r   z#Invalid video file or FFprobe errorformatduration,  r   zLong video duration: .1f secondsc                 S      g | ]}| d dkr|qS 
codec_typevideoget.0srI   rI   rJ   
<listcomp>       z'validate_video_file.<locals>.<listcomp>streamszNo video stream foundr]   r^     8  zHigh resolution video: rN   bit_ratei zHigh bitrate: z bpszVideo validation timeoutzError parsing video informationzVideo validation error: N)
subprocessrun
returncoder4   rc   loadsstdoutfloatrs   intTimeoutExpiredJSONDecodeErrorrA   rC   )r   r[   cmdprocess
video_inforj   video_streamsvideo_streamr]   r^   bitraterH   rI   rI   rJ   r<      s^   
	
"r<   c              
   C   s  dg g d}zeddddddd	| g}t j|ddd
}|jdkr,d|d< |d d |W S t|j}t|di dd}|dkrN|d d|dd dd |dg D }|sid|d< |d d W |S W |S  t	y } zd|d< |d dt
|  W Y d}~|S d}~ww )z
    Validate audio file.
    
    Args:
        file_path (str): Path to audio file
        
    Returns:
        dict: Audio validation results
    TrL   r_   r`   ra   rb   rc   rd   re   rf   r   Fr   r   z#Invalid audio file or FFprobe errorri   rj   iX  r   zLong audio duration: rl   rm   c                 S   rn   rp   audiorr   rt   rI   rI   rJ   rw   1  rx   z'validate_audio_file.<locals>.<listcomp>ry   zNo audio stream foundzAudio validation error: N)r}   r~   r   r4   rc   r   r   r   rs   rA   rC   )r   r[   r   r   
audio_inforj   audio_streamsrH   rI   rI   rJ   r=     s>   
	
"r=   c              
   C   s  dg g d}zht | t jrd|d< |d d t| dF}|d}t j| d	  }|d
vrRd| v s>d| v r[d|d< |d d W d   W |S W d   W |S W d   W |S 1 sgw   Y  W |S  t	y } z|d dt
|  W Y d}~|S d}~ww )z
    Validate file for security issues.
    
    Args:
        file_path (str): Path to file
        
    Returns:
        dict: Security validation results
    TrL   Fr   r   zFile has executable permissionsrb   r   )r+   r,   s   <scripts   javascript:z"Suspicious script content detectedNr   zSecurity validation warning: )r1   accessX_OKr4   rV   readr2   r6   r7   rA   rC   )r   r[   fcontentrF   rH   rI   rI   rJ   r>   =  s6   

"r>   c              
   C   s8  | t j| ddddddd}zet j| s|W S t | }||jt j| d  t	| t
|j t
|j t| d |d }|dv rS|t|  n|d	v r_|t|  n|d
v rj|t|  td|   |W S  ty } ztd|  dt|  t||d< |W  Y d}~S d}~ww )z
    Extract comprehensive metadata from file.
    
    Args:
        file_path (str): Path to file
        
    Returns:
        dict: File metadata
    r    N)r   	file_namerE   file_extensionr   
created_atmodified_atchecksumr   )rE   r   r   r   r   r   r   r-   r.   r/   zMetadata extracted for file: zError extracting metadata from r0   rB   )r1   r2   basenamer3   statupdatest_sizer6   r7   r8   r   fromtimestampst_ctime	isoformatst_mtimecalculate_file_hashget_image_metadataget_video_metadataget_audio_metadatar?   r@   rA   rB   rC   )r   metadatar   rF   rH   rI   rI   rJ   get_file_metadataa  sH   


r   c           
   
   C   sH  i }z~t | n}|j\}}|| d| |||j|jd t|drF| rFi }|  D ]\}}t	
||}t|||< q1||d< t|drd|j|d< |jrmt|dd|d< W d	   W |S W d	   W |S W d	   W |S 1 syw   Y  W |S  ty }	 ztd
t|	  t|	|d< W Y d	}	~	|S d	}	~	ww )z
    Extract image-specific metadata.
    
    Args:
        file_path (str): Path to image file
        
    Returns:
        dict: Image metadata
    rN   )
dimensionsr]   r^   Z
color_moderi   _getexifexifrT   rU   r   Zframe_countNz!Error extracting image metadata: rB   )r   rV   r   r   rX   ri   rY   r   itemsr   rs   rC   rT   rZ   rA   r?   rB   )
r   r   r\   r]   r^   Z	exif_dataZtag_idvaluetagrH   rI   rI   rJ   r     sJ   

	

r   c                 C   s  i }zddddddd| g}t j|ddd	}|jd
krt|j}|di }|t|dd
t	|dd
|ddd dd |dg D }|rz|d
 }t	|dd
}t	|dd
}	|| d|	 ||	|ddt
|ddd dd |dg D }
|
r|
d
 }||ddt	|dd
t	|dd
d W |S W |S W |S  ty } ztdt|  t||d < W Y d!}~|S d!}~ww )"z
    Extract video-specific metadata using FFprobe.
    
    Args:
        file_path (str): Path to video file
        
    Returns:
        dict: Video metadata
    r_   r`   ra   rb   rc   rd   re   Trf   r   ri   rj   r|   format_namer   )rj   r   r   c                 S   rn   ro   rr   rt   rI   rI   rJ   rw     rx   z&get_video_metadata.<locals>.<listcomp>ry   r]   r^   rN   
codec_nameZr_frame_ratez0/1)r   r]   r^   codecZfpsc                 S   rn   r   rr   rt   rI   rI   rJ   rw     rx   sample_ratechannels)Zaudio_codecr   r   z!Error extracting video metadata: rB   N)r}   r~   r   rc   r   r   rs   r   r   r   evalrA   r?   rB   rC   )r   r   r   r   r   format_infor   r   r]   r^   r   audio_streamrH   rI   rI   rJ   r     sb   
	


	


(r   c           	   
   C   s   i }zjddddddd| g}t j|ddd	}|jd
krgt|j}|di }|t|dd
t	|dd
d dd |dg D }|rj|d
 }||ddt	|dd
t	|dd
d W |S W |S W |S  t
y } ztdt|  t||d< W Y d}~|S d}~ww )z
    Extract audio-specific metadata.
    
    Args:
        file_path (str): Path to audio file
        
    Returns:
        dict: Audio metadata
    r_   r`   ra   rb   rc   rd   re   Trf   r   ri   rj   r|   )rj   r   c                 S   rn   r   rr   rt   rI   rI   rJ   rw   *  rx   z&get_audio_metadata.<locals>.<listcomp>ry   r   r   r   r   )r   r   r   z!Error extracting audio metadata: rB   N)r}   r~   r   rc   r   r   rs   r   r   r   rA   r?   rB   rC   )	r   r   r   r   r   r   r   r   rH   rI   rI   rJ   r     sH   
	



r   U   rz   r{   quality	max_width
max_heightc              
   C   sN  zt | y}tj| }|j\}}||kp||k}|dk}	|s,|	s,	 W d   W dS |jdv r6|d}|rB|||ft j	j
 dt|    d}
t|}|j|
d|dd	 tj|
}|| | d
 }td|dd |
W  d   W S 1 sw   Y  W dS  ty } ztdt|  W Y d}~dS d}~ww )aC  
    Optimize image file for web delivery.
    
    Args:
        file_path (str): Path to image file
        quality (int): JPEG quality (1-100)
        max_width (int): Maximum width
        max_height (int): Maximum height
        
    Returns:
        str: Path to optimized image or None if no optimization needed
    i   NrQ   LArS   rP   z/tmp/optimized_r   JPEGT)r   optimizerO   zImage optimized: rl   % size reductionzError optimizing image: )r   rV   r1   r2   r5   r   rX   convert	thumbnail
ResamplingLANCZOShashlibmd5encode	hexdigestr	   exif_transposesaver?   r@   rA   rB   rC   )r   r   r   r   r\   original_sizer]   r^   needs_resizeneeds_compressionoptimized_pathZoptimized_sizecompression_ratiorH   rI   rI   rJ   optimize_image;  s4   



(!r   2Mtarget_bitratec                 C   s\  zt | }d|v rW dS tj| }|dd}|dk}||k}|s'|s'W dS dt|    d}dd	| d
dd|ddddddd|g}	|rW|		dd |		dd| d t
j|	ddd}
|
jdkrtj|rtj|}|| | d }td|dd |W S td|
j  W dS  ty } ztdt|  W Y d}~dS d}~ww ) a$  
    Compress video file using FFmpeg.
    
    Args:
        file_path (str): Path to video file
        target_bitrate (str): Target bitrate (e.g., '2M')
        max_width (int): Maximum width
        
    Returns:
        str: Path to compressed video or None if no compression needed
    rB   Nr]   r   i   z/tmp/compressed_r#   ffmpeg-iz-c:vZlibx264z-b:vz-c:aaacz-b:aZ128kz	-movflagsz
+faststart-y-vfzscale=z:-2Trf   rO   zVideo compressed: rl   r   zFFmpeg error: zError compressing video: )r   r1   r2   r5   rs   r   r   r   r   insertr}   r~   r   r3   r?   r@   rB   stderrrA   rC   )r   r   r   r   r   r]   r   r   compressed_pathr   r   Zcompressed_sizer   rH   rI   rI   rJ   compress_videoo  sJ   r   rk   rk   r   c              
   C   s   z#t j| d  }|dv rt| |W S |dv rt| W S t||W S  ty@ } zt	dt
|  W Y d}~dS d}~ww )z
    Generate thumbnail for any supported file type.
    
    Args:
        file_path (str): Path to file
        size (tuple): Thumbnail size (width, height)
        
    Returns:
        str: Path to generated thumbnail or None if failed
    r   r-   r.   zError generating thumbnail: N)r1   r2   r6   r7   generate_image_thumbnailgenerate_video_thumbnailgenerate_generic_thumbnailrA   r?   rB   rC   )r   r   rF   rH   rI   rI   rJ   generate_thumbnail  s   
r   c              
   C   s   zBt | 2}|jdv r|d}||t jj dt| 	 
  d}|j|ddd |W  d   W S 1 s;w   Y  W dS  ty_ } ztd	t|  W Y d}~dS d}~ww )
z
    Generate thumbnail for image file.
    
    Args:
        file_path (str): Path to image file
        size (tuple): Thumbnail size
        
    Returns:
        str: Path to generated thumbnail
    r   rP   /tmp/thumb_r   r   r   r   Nz"Error generating image thumbnail: )r   rV   rX   r   r   r   r   r   r   r   r   r   rA   r?   rB   rC   )r   r   r\   
thumb_pathrH   rI   rI   rJ   r     s   

(r   00:00:01time_offsetc                 C   s   z<dt |    d}dd| d|dddd	d
|g}tj|ddd}|jdkr1tj	|r1|W S t
d|j  W dS  tyY } zt
dt|  W Y d}~dS d}~ww )z
    Generate thumbnail for video file.
    
    Args:
        file_path (str): Path to video file
        time_offset (str): Time offset for thumbnail
        
    Returns:
        str: Path to generated thumbnail
    r   r   r   r   z-ssz-vframes1r   z2scale=300:300:force_original_aspect_ratio=decreaser   Trf   r   zFFmpeg thumbnail error: Nz"Error generating video thumbnail: )r   r   r   r   r}   r~   r   r1   r2   r3   r?   rB   r   rA   rC   )r   r   r   r   r   rH   rI   rI   rJ   r     s(   
r   rF   c              
   C   s   z't jd|dd}d| dd  d|d  d	|d  d
}|j|ddd |W S  tyD } ztdt|  W Y d}~dS d}~ww )z
    Generate generic file icon thumbnail.
    
    Args:
        file_ext (str): File extension
        size (tuple): Thumbnail size
        
    Returns:
        str: Path to generated thumbnail
    rP   z#f8f9fa)colorz/tmp/thumb_generic_r   N_r   rN   r   r   r   r   z$Error generating generic thumbnail: )r   newr   rA   r?   rB   rC   )rF   r   r\   r   rH   rI   rI   rJ   r     s   (r   c                 C   s\   zt tdrtj| ddW S t| \}}|pdW S  ty-   t| \}}|p*d Y S w )z
    Get MIME type of file.
    
    Args:
        file_path (str): Path to file
        
    Returns:
        str: MIME type
    	from_fileT)mimezapplication/octet-streamN)rY   magicr   	mimetypes
guess_typerA   )r   r   r   rI   rI   rJ   r8   -  s   


r8   r   c                 C   sT   dgdgdgdgdgdgdgdgdgd	gd
dgdgdgdgdgd}| | |g v S )z
    Check if MIME type matches file extension.
    
    Args:
        mime_type (str): MIME type
        file_ext (str): File extension
        
    Returns:
        bool: True if MIME type is valid for extension
    z
image/jpegz	image/pngz	image/gifz
image/webpz	video/mp4zvideo/quicktimezvideo/x-msvideoz
video/webmz
audio/mpegz	audio/wavzaudio/x-wavz	audio/aacz	audio/oggz	text/htmlr   Nrr   )r   rF   Zvalid_combinationsrI   rI   rJ   r9   E  s"   r9   r   	algorithmc              
      s   z1t t| }t| d t fdddD ]}|| qW d   n1 s(w   Y  | W S  tyN } ztdt	|  W Y d}~dS d}~ww )z
    Calculate file hash.
    
    Args:
        file_path (str): Path to file
        algorithm (str): Hash algorithm (md5, sha1, sha256)
        
    Returns:
        str: File hash
    r   c                      s
     dS )NrM   )r   rI   r   rI   rJ   <lambda>t  s   
 z%calculate_file_hash.<locals>.<lambda>    NzError calculating file hash: r   )
rZ   r   rV   iterr   r   rA   r?   rB   rC   )r   r   Z	hash_funcchunkrH   rI   r   rJ   r   e  s   
r   c              
   C   s   zHt j| d  }|dv r+t| }|jW  d   W S 1 s#w   Y  W dS |dv rFt| }|d}|d}|rF|rF||fW S W dS  t	ye } zt
dt|  W Y d}~dS d}~ww )z
    Get file dimensions for images and videos.
    
    Args:
        file_path (str): Path to file
        
    Returns:
        tuple: (width, height) or None if not applicable
    r   r-   Nr.   r]   r^   zError getting file dimensions: )r1   r2   r6   r7   r   rV   r   r   rs   rA   r?   rB   rC   )r   rF   r\   r   r]   r^   rH   rI   rI   rJ   get_file_dimensions~  s&   
"



r   
size_bytesc                 C   sl   | dkrdS g d}d}| dkr,|t |d k r,| d } |d7 }| dkr,|t |d k s| dd||  S )
z
    Format file size in human-readable format.
    
    Args:
        size_bytes (int): Size in bytes
        
    Returns:
        str: Formatted size string
    r   z0 B)BKBMBGBTBr   r   g      @rl    N)len)r   Z
size_namesirI   rI   rJ   format_file_size  s   
r  filenamec                 C   s<   t j| } t j| \}}t|}|sd}| |  S )z
    Clean filename for safe storage.
    
    Args:
        filename (str): Original filename
        
    Returns:
        str: Cleaned filename
    fileN)r1   r2   r   r6   r   r7   )r  nameext
clean_namerI   rI   rJ   clean_filename  s   r  r   rE   max_sizec                 C   s   | |kS )z
    Validate file size against limit.
    
    Args:
        file_size (int): File size in bytes
        max_size (int): Maximum allowed size in bytes
        
    Returns:
        bool: True if file size is valid
    NrI   )rE   r  rI   rI   rJ   validate_file_size  s   r	  c                 C   s8   t |}t d}t| dd}d| d| d| S )z
    Generate upload path for creative files.
    
    Args:
        instance: Model instance
        filename (str): Original filename
        
    Returns:
        str: Upload path
    %Y/%m/%dcreative_typeunknownz
creatives//N)r  r   nowstrftimerZ   )instancer  r  	date_pathr  rI   rI   rJ   get_upload_path  s   r  c                 C   s&   t |}t d}d| d| S )z
    Generate upload path for thumbnail files.
    
    Args:
        instance: Model instance
        filename (str): Original filename
        
    Returns:
        str: Upload path
    r
  zcreatives/thumbnails/r  N)r  r   r  r  )r  r  r  r  rI   rI   rJ   get_thumbnail_upload_path  s   r  )r   rz   r{   )r   rz   )r   )r   )r   )r   )@__doc__r1   r   r   r}   rc   loggingr   typingr   r   r   r   r   PILr   r	   r
   ZPIL.ExifTagsr   r   django.core.files.uploadedfiler   django.confr   django.core.exceptionsr   django.utils.textr   django.core.files.storager   django.core.files.baser   	getLogger__name__r?   rC   boolrK   r:   r<   r=   r>   r   r   r   r   r   r   r   r   r   r   r   r   r8   r9   r   r   r  r  r	  r  r  rI   rI   rI   rJ   <module>   sV    $
&&_&,&D&2&$$7&,$C$4 4$B""% 