
    }i9W                        d Z ddlZddlZddlmZ ddlZddlmZmZ ddlm	Z	m
Z
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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jD                  e#      Z$ G d d      Z%y)a/  
This module contains a container for stream manifest data.

A container object for the media stream (video only / audio only / video+audio
combined). This was referred to as ``Video`` in the legacy pytube version, but
has been renamed to accommodate DASH (which serves the audio and video
separately).
    N)ceil)datetimetimezone)BinaryIODictOptionalTupleIteratorCallable)	HTTPError)parse_qs)Path)extractrequest)target_directory)get_format_profile)	Monostate)file_system_verify)ServerAbrStreamc                      e Zd ZdZdedededefdZede	fd       Z
ede	fd	       Zede	fd
       Zej                  d        Zede	fd       Zede	fd       Zdeee   ee   f   fdZedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Zedefd       Z	 	 	 	 	 	 	 d1dee   dee   dee   de	dee   ded ee g e	f      dee   fd!Z!	 	 	 	 d2dee   dee   dee   d"edef
d#Z"d$ede	fd%Z#d&e$ddfd'Z%d(e&d)e$d*efd+Z'd$ee   fd,Z(defd-Z)d(e&d*efd.Z*d3d/ee   de+e&   fd0Z,y)4Streamz#Container for stream manifest data.stream	monostatepo_tokenvideo_playback_ustreamer_configc           
         || _         |d   | _        t        |d         | _        d|v r|d   nd| _        t        j                  |d         \  | _        | _        | j                  j                  d      \  | _
        | _        | j                         \  | _        | _        |d   | _        |d   | _        t        |j#                  d	d
            | _        t'        t)        t'        |j#                  d	d
            dz  dz        dz        | _        t'        t)        t'        |j#                  d	d
            dz  dz  dz        dz        | _        t'        t)        t'        |j#                  d	d
            dz  dz  dz  dz        dz        | _        t1        | j                        }|d   | _        |d   | _        d|v r
|d   | _        |d   | _        d|v r|d   nd| _        d|v r|d   nd| _        |d   | _        |d   | _         |d   | _!        |j#                  dd      | _"        |j#                  dd      | _#        |d   | _$        |d   | _%        || _&        || _'        d|v | _(        | jP                  rd|d   d   v | _)        tU        |d   d         jW                  dd      | _,        | jX                  j                  d       d
   | _-        tU        |d   d!         j                  d"      d
   | _.        | j\                  j                  d#      d
   | _/        y| j`                  xr | jb                   | _)        d| _,        d| _-        d| _.        d| _/        y)$a  Construct a :class:`Stream <Stream>`.

        :param dict stream:
            The unscrambled data extracted from YouTube.
        :param dict monostate:
            Dictionary of data shared across all instances of
            :class:`Stream <Stream>`.
        urlitagxtagsNmimeType/is_otfbitratecontentLengthr        is_dashabrfps
resolutionwidthheightis_3dis_hdris_liveisDrcFis_sabrapproxDurationMslastModified
audioTrackoriginaldisplayNamez	 original  id.-)2
_monostater   intr   r   r   mime_type_codec	mime_typecodecssplittypesubtypeparse_codecsvideo_codecaudio_codecr"   r#   get	_filesizefloatr   _filesize_kb_filesize_mb_filesize_gbr   r'   r(   r)   r*   _width_heightr-   r.   r/   is_drc_is_sabr
durationMslast_Modifiedr   r   includes_multiple_audio_tracksis_default_audio_trackstrreplaceaudio_track_name_regionalizedaudio_track_name$audio_track_language_id_regionalizedaudio_track_language_idincludes_audio_trackincludes_video_track)selfr   r   r   r   itag_profiles         </usr/local/lib/python3.12/dist-packages/pytubefix/streams.py__init__zStream.__init__"   sh    $%=6N
	 )06(9VG_t

 '.&=&=fZ>P&Q# #'.."6"6s";	4< .2->->-@*$*"8,&,Y&7 ),FJJ,J(K .34fjjZ[>\8]`d8dgk8k3los3s-t .34fjjZ[>\8]`d8dgk8knr8r3svz3z-{ .34fjjZ[>\8]`d8dgk8knr8ruy8y3z  ~B  4B  .C *$))4#I.&F?e}DH&
 *1F):fWo+3v+=vh'4!'*
"8,#I.jj%0

9e4 !34#N3 /N,4@F4J+..*4|8L]8[*[D'14VL5I-5X1Y1a1abmoq1rD.$($F$F$L$LS$QRS$TD!7:6,;OPT;U7V7\7\]`7abc7dD5*.*S*S*Y*YZ]*^_`*aD(*.*C*C*eDLeLeHeD'15D.$(D!8<D5*.D(    returnc                 D    t        t        | j                        dz        S )z:Whether the stream is DASH.

        :rtype: bool
           )boollenr@   r]   s    r_   is_adaptivezStream.is_adaptivey   s     C$q())ra   c                     | j                    S )zAWhether the stream is progressive.

        :rtype: bool
        )rh   rg   s    r_   is_progressivezStream.is_progressive   s     ####ra   c                     | j                   S )z:Whether the stream is SABR.

        :rtype: bool
        rP   rg   s    r_   r1   zStream.is_sabr   s     }}ra   c                     || _         y Nrl   )r]   values     r_   r1   zStream.is_sabr   s	    ra   c                 <    | j                   xs | j                  dk(  S )zFWhether the stream only contains audio.

        :rtype: bool
        audiorj   rB   rg   s    r_   r[   zStream.includes_audio_track        "":dii7&::ra   c                 <    | j                   xs | j                  dk(  S )zFWhether the stream only contains video.

        :rtype: bool
        videorr   rg   s    r_   r\   zStream.includes_video_track   rs   ra   c                     d}d}| j                   s| j                  \  }}||fS | j                  r| j                  d   }||fS | j                  r| j                  d   }||fS )a  Get the video/audio codecs from list of codecs.

        Parse a variable length sized list of codecs and returns a
        constant two element tuple, with the video codec as the first element
        and audio as the second. Returns None if one is not available
        (adaptive only).

        :rtype: tuple
        :returns:
            A two element tuple with audio and video codecs.

        Nr   )rh   r@   r\   r[   )r]   ru   rq   s      r_   rD   zStream.parse_codecs   sv     ;;LE5
 e|	 &&KKNE e| &&KKNEe|ra   c                     | j                   S )zVideo width. Returns None if it does not have the value.

        :rtype: int
        :returns:
            Returns an int of the video width
        )rM   rg   s    r_   r+   zStream.width   s     {{ra   c                     | j                   S )zVideo height. Returns None if it does not have the value.

        :rtype: int
        :returns:
            Returns an int of the video height
        )rN   rg   s    r_   r,   zStream.height   s     ||ra   c                 D   | j                   dk(  r1	 t        j                  | j                        | _         | j                   S | j                   S # t        $ rI}|j
                  dk7  r t        j                  | j                        | _         Y d}~| j                   S d}~ww xY w)zFile size of the media stream in bytes.

        :rtype: int
        :returns:
            Filesize (in bytes) of the stream.
        r     N)rH   r   filesizer   r   codeseq_filesizer]   es     r_   r{   zStream.filesize   s     >>Q@!(!1!1$((!;
 ~~t~~	  @66S=!(!5!5dhh!?~~	@s   $A 	B4BBc                    | j                   dk(  rL	 t        t        t        j                  | j
                        dz  dz        dz        | _         | j                   S | j                   S # t        $ rd}|j                  dk7  r t        t        t        j                  | j
                        dz  dz        dz        | _         Y d}~| j                   S d}~ww xY w)zFile size of the media stream in kilobytes.

        :rtype: float
        :returns:
            Rounded filesize (in kilobytes) of the stream.
        r   r%   r&   rz   N)	rJ   rI   r   r   r{   r   r   r|   r}   r~   s     r_   filesize_kbzStream.filesize_kb   s     !c$)$w/?/?/I$/NQU/U*VY]*]$^!
    t   	  c66S=$)$w/C/CDHH/Md/RUY/Y*Z]a*a$b!!   	cs   ?A( (	C1ACCc                    | j                   dk(  rO	 t        t        t        j                  | j
                        dz  dz  dz        dz        | _         | j                   S | j                   S # t        $ rg}|j                  dk7  r t        t        t        j                  | j
                        dz  dz  dz        dz        | _         Y d}~| j                   S d}~ww xY w)zFile size of the media stream in megabytes.

        :rtype: float
        :returns:
            Rounded filesize (in megabytes) of the stream.
        r   r%   r&   rz   N)	rK   rI   r   r   r{   r   r   r|   r}   r~   s     r_   filesize_mbzStream.filesize_mb   s     !h$)$w/?/?/I$/Nt/SVZ/Z*[^b*b$c!
    t   	  h66S=$)$w/C/CDHH/Md/RSW/WZ^/^*_bf*f$g!!   	hs   AA+ +	C4ACCc                    | j                   dk(  rR	 t        t        t        j                  | j
                        dz  dz  dz  dz        dz        | _         | j                   S | j                   S # t        $ rj}|j                  dk7  r t        t        t        j                  | j
                        dz  dz  dz  dz        dz        | _         Y d}~| j                   S d}~ww xY w)zFile size of the media stream in gigabytes.

        :rtype: float
        :returns:
            Rounded filesize (in gigabytes) of the stream.
        r   r%   r&   rz   N)	rL   rI   r   r   r{   r   r   r|   r}   r~   s     r_   filesize_gbzStream.filesize_gb  s     !m$)$w/?/?/I$/Nt/STX/X[_/_*`cg*g$h!
    t   	  m66S=$)$w/C/CDHH/Md/RSW/WX\/\_c/c*dgk*k$l!!   	ms   AA. .	C!7ACC!c                 6    | j                   j                  xs dS )zbGet title of video

        :rtype: str
        :returns:
            Youtube video title
        zUnknown YouTube Video Title)r<   titlerg   s    r_   r   zStream.title  s     $$E(EEra   c                     | j                   j                  r=| j                  r1d}t        | j                   j                  | j                  z  |z        S | j                  S )zGet approximate filesize of the video

        Falls back to HTTP call if there is not sufficient information to approximate

        :rtype: int
        :returns: size of video in bytes
           )r<   durationr#   r=   r{   )r]   bits_in_bytes     r_   filesize_approxzStream.filesize_approx   sP     ??##L))DLL8LH  }}ra   c                     t        | j                  j                  d      d         d   d   }t        j                  t        |      t        j                        S )N?   expirer   )r   r   rA   r   fromtimestampr=   r   utc)r]   r   s     r_   
expirationzStream.expiration1  sC    $((..-a01(;A>%%c&k8<<@@ra   c                 ~    d| j                   v rd| j                   vrd| _        | j                   d| j                   S )zGenerate filename based on the video title.

        :rtype: str
        :returns:
            An os file system compatible filename.
        rq   ru   m4ar:   )r?   rC   r   rg   s    r_   default_filenamezStream.default_filename6  s;     dnn$)F DL**Qt||n--ra   Noutput_pathfilenamefilename_prefixskip_existingtimeoutmax_retriesinterrupt_checkerc                 h    t         j                  }|dk(  rd}	n
|dk(  rd}	nd}	t        |	      }
| j                  j	                  |
      }|r|j	                  |
      } j                  ||||	      }|r= j                  |      r,t        j                  d| d	        j                  |       |S  j                  }t        j                  d
 j                   d|         fd}t        |d      5 	  j                  sjt        j                   j                  ||      D ]D  }|) |       dk(  rt        j                  d        ddd       y|t!        |      z  } |||       F n;t        j                  d       t#         | j$                        j'                           j                  |       |cddd       S # t(        $ r}|j*                  dk7  r Y d}~:d}~wt,        $ r  j                  skt        j.                   j                  ||      D ]E  }|* |       dk(  r t        j                  d        Y ddd       y|t!        |      z  } |||       G n;t        j                  d       t#         | j$                        j'                          Y w xY w# 1 sw Y   yxY w)a  
        Downloads a file from the URL provided by `self.url` and saves it locally with optional configurations.

        Args:
            output_path (Optional[str]): Directory path where the downloaded file will be saved. Defaults to the current directory if not specified.
            filename (Optional[str]): Custom name for the downloaded file. If not provided, a default name is used.
            filename_prefix (Optional[str]): Prefix to be added to the filename (if provided).
            skip_existing (bool): Whether to skip the download if the file already exists at the target location. Defaults to True.
            timeout (Optional[int]): Maximum time, in seconds, to wait for the download request. Defaults to None for no timeout.
            max_retries (int): The number of times to retry the download if it fails. Defaults to 0 (no retries).
            interrupt_checker (Optional[Callable[[], bool]]): A callable function that is checked periodically during the download. If it returns True, the download will stop without errors.

        Returns:
            Optional[str]: The full file path of the downloaded file, or None if the download was skipped or failed.

        Raises:
            HTTPError: Raised if there is an error with the HTTP request during the download process.

        Note:
            - The `skip_existing` flag avoids redownloading if the file already exists in the target location.
            - The `interrupt_checker` allows for the download to be halted cleanly if certain conditions are met during the download process.
            - Download progress can be monitored using the `on_progress` callback, and the `on_complete` callback is triggered once the download is finished.
        linuxext4darwinAPFSNTFSN)r   r   r   file_systemzfile z already exists, skippingzdownloading (z total bytes) file to c                 ,    j                  | |       y rn   )on_progress)chunk_bytes_remaining_fhr]   s     r_   write_chunkz$Stream.download.<locals>.write_chunk  s    VR)9:ra   wb)r   r   TzFinterrupt_checker returned True, causing to force stop the downloadingz-This stream is SABR. Starting ServerAbrStream)r   r   r   rz   )sysplatformr   r   	translateget_file_pathexists_at_pathloggerdebugon_completer{   openr1   r   r   r   rf   r   r<   startr   r|   StopIteration
seq_stream)r]   r   r   r   r   r   r   r   kernelr   translation_table	file_pathbytes_remainingr   chunkr   r   s   `               @r_   downloadzStream.downloadC  s   F W Kx K K.{;,,667HIH))*;<H&&#+#	 ' 
	 T00;LL5+DEFY'--}T]]O3I)UV	;
 )T" (	b$m||!( '$/" 
<
 -8=N=PTX=X"LL)qr"(	 (	 (3u:5#E?;
< LL!PQ#4[TXTcTcdjjl. Y'Q(	 (	$  66S= !  m||!(!3!3 '$/" 
<
 -8=N=PTX=X"LL)qr"?(	 (	B (3u:5#E?;
< LL!PQ#4[TXTcTcdjjl!m+(	 (	sX   7J(9AGAG*J(	J%G$J($AJ%J(AJ%"J($J%%J((J1r   c                 :   |s&t        |      }| j                  j                  |      }|rJt        |      }d| j                  v rd| j                  vs|j                  |      }n|j                  |      }|r| | }t	        t        t        |            |z        S )Nrq   ru   )r   r   r   r?   rU   r   r   )r]   r   r   r   r   r   s         r_   r   zStream.get_file_path  s      2; ?,,667HIH 2; ?t~~-'2O#--.?@#--.?@)*8*5H4(56ABBra   r   c                     t         j                  j                  |      xr, t         j                  j                  |      | j                  k(  S rn   )ospathisfilegetsizer{   )r]   r   s     r_   r   zStream.exists_at_path  s5    GGNN9% <	*dmm;	
ra   bufferc                    | j                   }t        j                  d| j                          t        j                  | j
                        D ]#  }|t        |      z  }| j                  |||       % | j                  d       y)zLWrite the media stream to buffer

        :rtype: io.BytesIO buffer
        +downloading (%s total bytes) file to bufferN)	r{   r   infor   r   r   rf   r   r   )r]   r   r   r   s       r_   stream_to_bufferzStream.stream_to_buffer  sp    
 --94==	
 ^^DHH- 	=Es5z)OUFO<		=
 	ra   r   file_handlerr   c                     |j                  |       t        j                  d|       | j                  j                  r| j                  j	                  | ||       yy)a  On progress callback function.

        This function writes the binary data to the file, then checks if an
        additional callback is defined in the monostate. This is exposed to
        allow things like displaying a progress bar.

        :param bytes chunk:
            Segment of media file binary data, not yet written to disk.
        :param file_handler:
            The file handle where the media is being written to.
        :type file_handler:
            :py:class:`io.BufferedWriter`
        :param int bytes_remaining:
            The delta between the total file size in bytes and amount already
            downloaded.

        :rtype: None

        download remaining: %sN)writer   r   r<   r   )r]   r   r   r   s       r_   r   zStream.on_progress  sI    . 	5!-???&&OO''e_E 'ra   c                     t         j                  d       | j                  j                  }|r t         j                  d|        || |       yy)zOn download complete handler function.

        :param file_path:
            The file handle where the media is being written to.
        :type file_path: str

        :rtype: None

        zdownload finishedzcalling on_complete callback %sN)r   r   r<   r   )r]   r   r   s      r_   r   zStream.on_complete   sA     	()oo11LL:KHi( ra   c                 D   ddg}| j                   rF|j                  ddg       | j                  s|j                  ddg       n&|j                  dg       n|j                  ddg       |j                  g d       d	d
j                  |      j	                  |        dS )zPrintable object representation.

        :rtype: str
        :returns:
            A string representation of a :class:`Stream <Stream>` object.
        zitag="{s.itag}"zmime_type="{s.mime_type}"zres="{s.resolution}"zfps="{s.fps}fps"zvcodec="{s.video_codec}"zacodec="{s.audio_codec}"zabr="{s.abr}")z progressive="{s.is_progressive}"zsabr="{s.is_sabr}"ztype="{s.type}"z	<Stream: r8   )s>)r\   extendrh   joinformat)r]   partss     r_   __repr__zStream.__repr__  s     #$?@$$LL02DEF##/1KM 89:LL/+EFGbc388E?11D19:!<<ra   c                     t         j                  d|       | j                  j                  r| j                  j                  | ||       yy)a  On progress callback function.

        This function checks if an additional callback is defined in the monostate.
        This is exposed to allow things like displaying a progress bar.

        :param bytes chunk:
        Segment of media file binary data, not yet written to disk.
        :py:class:`io.BufferedWriter`
        :param int bytes_remaining:
        The delta between the total file size in bytes and amount already
        downloaded.

        :rtype: None
        r   N)r   r   r<   r   )r]   r   r   s      r_   on_progress_for_chunkszStream.on_progress_for_chunks%  s;      	-???&&OO''e_E 'ra   
chunk_sizec              #     K   | j                   }|r|t        _        t        j	                  d| j                          	 t        j
                  | j                        }|D ]&  }|t        |      z  }| j                  ||       | ( | j                  d       y# t        $ r9}|j                  dk7  r t        j                  | j                        }Y d}~zd}~ww xY ww)a  Get the chunks directly

        Example:
        # Write the chunk by yourself
        with open("somefile.mp4") as out_file:
            out_file.writelines(stream.iter_chunks(512))

            # Another way
            # for chunk in stream.iter_chunks(512):
            #   out_file.write(chunk)

        # Or give it external api
        external_api.write_media(stream.iter_chunks(512))

        :param int chunk size:
        The size in the bytes
        :rtype: Iterator[bytes]
        r   rz   N)r{   r   default_range_sizer   r   r   r   r   r|   r   rf   r   r   )r]   r   r   r   r   r   s         r_   iter_chunkszStream.iter_chunks9  s     ( --)3G&9MM	
	2^^DHH-F  	Es5z)O''?K	
 	  	2vv}''1F	2s.   :CB =C	C"/CCCC)NNNTNr   N)NNNr   rn   )-__name__
__module____qualname____doc__r   r   rU   r`   propertyre   rh   rj   r1   setterr[   r\   r	   r   rD   r=   r+   r,   r{   rI   r   r   r   r   r   r   r   r   r   r   r   r   r   r   bytesr   r   r   r   r
   r    ra   r_   r   r      s   -U/U/'0U/<?U/beU/n *T * * $ $ $    ^^  ;d ; ; ;d ; ;eHSM8C=$@A . s      #    !U ! !  !U ! !  !U ! !  F F F     AH A A 
.# 
. 
. &*"&)-"!%:>pc]p 3-p "#	p
 p #p p $HRX$67p 
#ph #'%))-!C3-C c]C "#	C
 C 
C.
 
 
x D "FF*2FEHF:)Xc] ) =# =*FE FC F()hsm )x )ra   r   )&r   loggingr   mathr   r   r   r   typingr   r   r   r	   r
   r   urllib.errorr   urllib.parser   pathlibr   	pytubefixr   r   pytubefix.helpersr   pytubefix.itagsr   pytubefix.monostater   pytubefix.file_systemr   %pytubefix.sabr.core.server_abr_streamr   	getLoggerr   r   r   r   ra   r_   <module>r      sZ     	  
 ' F F " !  & . . ) 4 A			8	$C	 C	ra   