o �J�h9W�@s�dZddlZddlZddlmZddlZddlmZmZddlm Z m Z m Z m Z m Z mZddlmZddlmZddlmZdd lmZmZdd lmZdd lmZdd lmZdd lmZddl m!Z!e�"e#�Z$Gdd�d�Z%dS)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@szeZdZdZdedededefdd�Zede fd d ��Z ede fd d ��Z ede fd d��Z e j dd��Z ede fdd��Zede fdd��Zdeeeeeffdd�Zedefdd��Zedefdd��Zedefdd��Zedefdd��Zedefdd��Zedefd d!��Zedefd"d#��Zedefd$d%��Zedefd&d'��Zedefd(d)��Z * * * + * , *dNd-eed.eed/eed0e d1eed2ed3ee ge fdeefd4d5�Z! * * * 6dOd.eed-eed/eed7edef d8d9�Z"d:ede fd;d<�Z#d=e$dd*fd>d?�Z%d@e&dAe$dBefdCdD�Z'd:eefdEdF�Z(defdGdH�Z)d@e&dBefdIdJ�Z*dPdKeede+e&fdLdM�Z,d*S)Q�Streamz#Container for stream manifest data.�stream� monostate�po_token�video_playback_ustreamer_configcCs�||_|d|_t|d�|_d|vr|dnd|_t�|d�\|_|_|j� d�\|_ |_ |� �\|_ |_|d|_|d|_t|�d d ��|_ttt|�d d ��d d �d �|_ttt|�d d ��d d d �d �|_ttt|�d d ��d d d d �d �|_t|j�}|d |_|d|_d|vr�|d|_|d|_d|vr�|dnd|_d|vr�|dnd|_|d|_|d|_ |d|_!|�dd�|_"|�dd�|_#|d|_$|d|_%||_&||_'d|v|_(|j(�r*d|ddv|_)t*|dd��+dd�|_,|j,� d �d |_-t*|dd!�� d"�d |_.|j.� d#�d |_/dS|j0�o1|j1 |_)d|_,d|_-d|_.d|_/dS)$aConstruct 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�bitrateZ contentLengthr����is_dash�abr�fps� resolution�width�height�is_3d�is_hdr�is_liveZisDrcF�is_sabrZapproxDurationMs� lastModifiedZ audioTrack�originalZ displayNamez original�� �id�.�-)2� _monostater�intrrrZmime_type_codec� mime_type�codecs�split�type�subtype� parse_codecs� video_codec� audio_codecrr �get� _filesize�floatr� _filesize_kb� _filesize_mb� _filesize_gbrr#r$r%r&�_width�_heightr)r*r+Zis_drc�_is_sabrZ durationMsZ last_ModifiedrrZincludes_multiple_audio_tracksZis_default_audio_track�str�replaceZaudio_track_name_regionalizedZaudio_track_nameZ$audio_track_language_id_regionalizedZaudio_track_language_id�includes_audio_track�includes_video_track)�selfrrrrZ itag_profile�rL�OC:\pinokio\api\whisper-webui.git\app\env\lib\site-packages\pytubefix\streams.py�__init__"s\ �  &*.    �       zStream.__init__�returncCstt|j�d�S)z:Whether the stream is DASH. :rtype: bool �)�bool�lenr7�rKrLrLrM� is_adaptiveyszStream.is_adaptivecCs|j S)zAWhether the stream is progressive. :rtype: bool )rTrSrLrLrM�is_progressive�szStream.is_progressivecC�|jS)z:Whether the stream is SABR. :rtype: bool �rFrSrLrLrMr,�szStream.is_sabrcCs ||_dS�NrW)rK�valuerLrLrMr,�s cC�|jp|jdkS)zFWhether the stream only contains audio. :rtype: bool �audio�rUr9rSrLrLrMrI��zStream.includes_audio_trackcCrZ)zFWhether the stream only contains video. :rtype: bool �videor\rSrLrLrMrJ�r]zStream.includes_video_trackcCsPd}d}|js|j\}}||fS|jr|jd}||fS|jr$|jd}||fS)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)rTr7rJrI)rKr^r[rLrLrMr;�s  � � zStream.parse_codecscCrV)z�Video width. Returns None if it does not have the value. :rtype: int :returns: Returns an int of the video width )rDrSrLrLrMr'��z Stream.widthcCrV)z�Video height. Returns None if it does not have the value. :rtype: int :returns: Returns an int of the video height )rErSrLrLrMr(�r_z Stream.heightc Csj|jdkr2z t�|j�|_W|jSty1}z|jdkr�t�|j�|_WYd}~|jSd}~ww|jS)z�File size of the media stream in bytes. :rtype: int :returns: Filesize (in bytes) of the stream. r�N)r?r�filesizerr �code� seq_filesize�rK�erLrLrMra�s � ��zStream.filesizec Cs�|jdkrFzttt�|j�dd�d�|_W|jStyE}z|jdkr(�ttt�|j�dd�d�|_WYd}~|jSd}~ww|jS)z�File size of the media stream in kilobytes. :rtype: float :returns: Rounded filesize (in kilobytes) of the stream. rr!r"r`N) rAr@rrrarr rbrcrdrLrLrM� filesize_kb�s $� ,��zStream.filesize_kbc Cs�|jdkrJzttt�|j�ddd�d�|_W|jStyI}z!|jdkr*�ttt�|j�ddd�d�|_WYd}~|jSd}~ww|jS)z�File size of the media stream in megabytes. :rtype: float :returns: Rounded filesize (in megabytes) of the stream. rr!r"r`N) rBr@rrrarr rbrcrdrLrLrM� filesize_mb�s (� 0��zStream.filesize_mbc Cs�|jdkrNzttt�|j�dddd�d�|_W|jStyM}z#|jdkr,�ttt�|j�dddd�d�|_WYd}~|jSd}~ww|jS)z�File size of the media stream in gigabytes. :rtype: float :returns: Rounded filesize (in gigabytes) of the stream. rr!r"r`N) rCr@rrrarr rbrcrdrLrLrM� filesize_gbs ,� 4��zStream.filesize_gbcCs |jjpdS)zbGet title of video :rtype: str :returns: Youtube video title zUnknown YouTube Video Title)r4�titlerSrLrLrMris z Stream.titlecCs.|jjr|jrd}t|jj|j|�S|jS)z�Get 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 �)r4�durationr r5ra)rKZ bits_in_byterLrLrM�filesize_approx s  �zStream.filesize_approxcCs.t|j�d�d�dd}t�t|�tj�S)N�?��expirer)r rr8r� fromtimestampr5r�utc)rKrorLrLrM� expiration1szStream.expirationcCs,d|jvr d|jvr d|_|j�d|j��S)z�Generate filename based on the video title. :rtype: str :returns: An os file system compatible filename. r[r^�m4ar2)r6r:rirSrLrLrM�default_filename6szStream.default_filenameNTr� output_path�filename�filename_prefix� skip_existing�timeout� max_retries�interrupt_checkerc sJtj}|dkr d} n |dkrd} nd} t| �} |dur!�j�| �}|r(|�| �}�j|||| d�} |rH��| �rHt�d| �d ���� | �| S�j } t�d �j �d | �����fd d �} t | d����zD�j s�t j�j||d�D]%}|dur�|�dkr�t�d�WWd�dS| t|�8} | || �qqnt�d�t�| �jd���Wncty�}z |jdkr��WYd}~nPd}~wt�y �j s�t j�j||d�D]%}|dur�|�dkr�t�d�YWd�dS| t|�8} | || �q�nt�d�t�| �jd���Ynw�� | �| Wd�S1�swYdS)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. �linuxZext4�darwinZAPFS�NTFSN)rvrurw� file_systemzfile z already exists, skippingz downloading (z total bytes) file to cs��|�|�dSrX)� on_progress)�chunk_Zbytes_remaining_��fhrKrLrM� write_chunk�sz$Stream.download.<locals>.write_chunk�wb)ryrzTzFinterrupt_checker returned True, causing to force stop the downloadingz-This stream is SABR. Starting ServerAbrStream)rr�rr`)�sys�platformrrt� translate� get_file_path�exists_at_path�logger�debug� on_completera�openr,rrrrRrr4�startr rb� StopIteration� seq_stream)rKrurvrwrxryrzr{�kernelr�translation_table� file_path�bytes_remainingr��chunkrerLr�rM�downloadCs�#  �   � � � �  �� � � ! � �� &�zStream.downloadr~rcCsr|s t|�}|j�|�}|r't|�}d|jvrd|jvs"|�|�}n|�|�}|r/|�|��}ttt|��|�S)Nr[r^)rrtr�r6rGr r)rKrvrurwrr�rLrLrMr��s    zStream.get_file_pathr�cCstj�|�otj�|�|jkSrX)�os�path�isfile�getsizera)rKr�rLrLrMr��s �zStream.exists_at_path�buffercCsN|j}t�d|j�t�|j�D]}|t|�8}|�|||�q|�d�dS)zLWrite the media stream to buffer :rtype: io.BytesIO buffer �+downloading (%s total bytes) file to bufferN) rar��inforrrrRr�r�)rKr�r�r�rLrLrM�stream_to_buffer�s� zStream.stream_to_bufferr�� file_handlerr�cCs6|�|�t�d|�|jjr|j�|||�dSdS)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�r4r�)rKr�r�r�rLrLrMr��s  �zStream.on_progresscCs4t�d�|jj}|rt�d|�|||�dSdS)z�On download complete handler function. :param file_path: The file handle where the media is being written to. :type file_path: str :rtype: None zdownload finishedzcalling on_complete callback %sN)r�r�r4r�)rKr�r�rLrLrMr�s  �zStream.on_completecCsvddg}|jr |�ddg�|js|�ddg�n|�dg�n|�ddg�|�gd��d d �|�j|d ��d �S) z�Printable object representation. :rtype: str :returns: A string representation of a :class:`Stream <Stream>` object. zitag="{s.itag}"zmime_type="{s.mime_type}"zres="{s.resolution}"zfps="{s.fps}fps"zvcodec="{s.video_codec}"zacodec="{s.audio_codec}"z abr="{s.abr}")z progressive="{s.is_progressive}"zsabr="{s.is_sabr}"ztype="{s.type}"z <Stream: r0)�s�>)rJ�extendrT�join�format)rK�partsrLrLrM�__repr__s�zStream.__repr__cCs,t�d|�|jjr|j�|||�dSdS)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�r4r�)rKr�r�rLrLrM�on_progress_for_chunks%s �zStream.on_progress_for_chunks� chunk_sizec cs��|j}|r |t_t�d|j�zt�|j�}Wnty6}z|jdkr&�t� |j�}WYd}~nd}~ww|D]}|t |�8}|� ||�|Vq9|� d�dS)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�r`N) rarZdefault_range_sizer�r�rrr rbr�rRr�r�)rKr�r�rrer�rLrLrM� iter_chunks9s*�� ��  zStream.iter_chunks)NNNTNrN)NNNr~rX)-�__name__� __module__� __qualname__�__doc__rrrGrN�propertyrQrTrUr,�setterrIrJrrr;r5r'r(rar@rfrgrhrirlrrrrtr r�r�r�rr��bytesr�r�r�r�r r�rLrLrLrMrs���� �W     �������� �t����� ��� � r)&r��loggingr��mathrr�rr�typingrrrrr r � urllib.errorr � urllib.parser �pathlibr � pytubefixrrZpytubefix.helpersrZpytubefix.itagsrZpytubefix.monostaterZpytubefix.file_systemrZ%pytubefix.sabr.core.server_abr_streamr� getLoggerr�r�rrLrLrLrM�<module>s$            
Memory