
    iL                         d Z ddlmZmZmZmZ ddl ddlmZ ddl	m
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ZddlmZ dd	lmZ d
 Z G d de      Zy)z
    podgen.media
    ~~~~~~~~~~~~

    This file contains the Media class, which represents a pointer to a media
    file.

    :copyright: 2016, Thorben Dahl <thorben@sjostrom.no>
    :license: FreeBSD and LGPL, see license.* for more details.
    )absolute_importdivisionprint_functionunicode_literals)*)urlparse)
raise_fromN)TinyTag)NotSupportedByItunesWarning)versionc                      	 t         } | S N)requestsSessionr   nameversion_full_strheaders)requests_sessions    E/root/podcast_feed/.venv/lib/python3.12/site-packages/podgen/media.py_get_new_requests_sessionr      s     $    c                      e Zd ZdZdddddddd	Z	 	 d!dZed        Zej                  d        Zed        Z	ed        Z
e
j                  d        Z
ed        Zed        Zej                  d        Zd Zed        Zej                  d        Zed        Ze	 	 d"d       Zd Zd Zd Zd Zd Zd Zed        Zd  Zy
)#Mediaa  
    Data-oriented class representing a pointer to a media file.

    A media file can be a sound file (most typical), video file or a document.

    You should provide the absolute URL at which this media can be found, and
    the media's file size in bytes.

    Optionally, you can provide the type of media (expressed using MIME types).
    When not given in the constructor, it will be found automatically by looking
    at the url's file extension. If the url's file extension isn't supported by
    iTunes, you will get an error if you don't supply the type.

    You are also highly encouraged to provide the duration of the media.

    .. note::

        iTunes is lazy and will just look at the URL to figure out if
        a file is of a supported file type. You must therefore ensure your URL
        ends with a supported file extension.

    .. note::

        A warning called :class:`~podgen.warnings.NotSupportedByItunesWarning`
        will be issued if your URL or type isn't compatible with iTunes. See
        the Python documentation for more details on :mod:`warnings`.

    Media types supported by iTunes:

    * Audio
      * M4A
      * MP3
    * Video
      * MOV
      * MP4
      * M4V
    * Document
      * PDF
      * EPUB

    All attributes will always have a value, except size which can be 0 if the
    size cannot be determined by any means (eg. if it's a stream) and duration
    which is optional (but recommended).

    .. seealso::
       :ref:`podgen.Media-guide`
          for a more gentle introduction.
    zaudio/x-m4az
audio/mpegzvideo/quicktimez	video/mp4zvideo/x-m4vzapplication/pdfzdocument/x-epub)m4amp3movmp4m4vpdfepubNc                     d | _         d | _        d | _        d | _        || _        || _        |xs | j                  |      | _        || _        |xs
 t               | _
        y r   )_url_size_type	_durationurlsizeget_typetypedurationr   r   )selfr&   r'   r)   r*   r   s         r   __init__zMedia.__init__f   s^    	

	.DMM#.	  0 O4M4O	r   c                     | j                   S )a  The URL at which this media is publicly accessible.

        Only absolute URLs are allowed, so make sure it starts with http:// or
        https://. The server should support HEAD-requests and byte-range
        requests.

        Ensure you quote parts of the URL that are not supposed to carry any
        special meaning to the browser, typically the name of your file.
        Common offenders include the slash character when not used to separate
        folders, the hash mark (#) and the question mark (?). Use
        :func:`urllib.parse.quote` in Python3 and :func:`urllib.quote` in
        Python2.

        :type: :obj:`str`
        )r"   r+   s    r   r&   z	Media.url   s    " yyr   c                 b   |st        d      t        |      }|j                  j                  d      d   j	                         }|| j
                  vrt        j                  d|z  t        d       |j                  dvr)t        j                  d|j                  z  t        d       || _
        y )	Nzurl cannot be empty or None.z-File extension %s is not supported by iTunes.   
stacklevel)httphttpsz\URL scheme %s is not supported by iTunes. Make sure you use absolute URLs and HTTP or HTTPS.)
ValueErrorr   pathsplitlower
file_typeswarningswarnr   schemer"   )r+   r&   
parsed_urlfile_extensions       r   r&   z	Media.url   s    :;;c]
#..s3B7==?0MMI*+,G%&( $55MM E&--./J%&( 	r   c                 j    dt        | j                        j                  j                  d      d   z   S )zYThe file extension of :attr:`~.Media.url`. Read-only.

        :type: :obj:`str`
        r0   r1   )r   r&   r8   r9   r.   s    r   r@   zMedia.file_extension   s.     Xdhh',,2237;;;r   c                     | j                   S )a  The media's file size in bytes.

        You can either provide the number of bytes as an :obj:`int`, or you can
        provide a human-readable :obj:`str` with a unit, like MB or GiB.

        An unknown size is represented as 0. This should ONLY be used in
        exceptional cases, where it is theoretically impossible to determine
        the file size (for example if it's a stream). Setting the size to 0
        will issue a UserWarning.

        :type: :obj:`str` (which will be converted to and stored as :obj:`int`)
            or :obj:`int`

        .. note::

            If you provide a string, it will be translated to int when the
            assignment happens. Thus, on subsequent accesses, you will get the
            resulting int, not the string you put in.

        .. note::

            The units are case-insensitive. This means that the ``B`` is
            always assumed to mean "bytes", even if it is lowercase (``b``).
            Likewise, ``m`` is taken to mean mega, not milli.
        )r#   r.   s    r   r'   z
Media.size   s    6 zzr   c                    	 t        |      }|dk  rt        d      || _        | j                  dk(  rt	        j
                  dd       y y # t        $ r | j                  |      | _        Y y t        $ r}|d| _        n|Y d }~y d }~ww xY w)Nr   z6File size must be 0 if unknown, or a positive integer.zSize is set to 0. This should ONLY be done when there is no possible way to determine the media's size, like if the media is a stream.   r3   )intr7   r#   r'   r<   r=   _str_to_bytes	TypeError)r+   r'   es      r   r'   z
Media.size   s    	t9Dax  "- . .DJyyA~ M *+, 
  	1**40DI 	|	 	s   AA B-B5BBc           
      8   ddddddddd	d
	}t        |       j                         j                         j                  dd      } t	        | j                  d            }| j                  d      }	 t        |||   z        S # t        $ r t        d|z        w xY w)zParse ``size`` and return the number of bytes it names.
        See :attr:`.Media.size` for more information on this conversion.   i  i   i@B i   i ʚ;i   @l    J)l        )	bkbkibmbmibgbgibtbtib  bkimgtz0123456789.zThe unit %s was not recognized.)
strr:   stripreplacefloatrstriplstriproundKeyErrorr7   )r'   unitsnumberunits       r   rF   zMedia._str_to_bytes   s    
 

 4y &&(00b9t{{8,-{{=)	G%+-.. 	G>EFF	Gs   0B Bc                     | j                   S )a(  The MIME type of this media.

        See https://en.wikipedia.org/wiki/Media_type for an introduction.

        :type: :obj:`str`

        .. note::

            If you leave out type when creating a new Media object, the
            type will be auto-detected from the :attr:`~podgen.Media.url`
            attribute. However, this won't happen automatically other than
            during initialization. If you want to autodetect type when
            assigning a new value to url, you should use
            :meth:`~podgen.Media.get_type`.
        )r$   r.   s    r   r)   z
Media.type   s    " zzr   c                     |st        d      |j                         j                         }|| j                  j	                         vrt        j                  d|z  t        d       || _        y )NzType cannot be empty or Nonez)Media type %s is not supported by iTunes.r2   r3   )	r7   rX   r:   r;   valuesr<   r=   r   r$   )r+   r)   s     r   r)   z
Media.type	  s[    ;<<zz|!!#t--//MMEL5!E
r   c                     t        |      j                  j                  d      d   j                         }	 | j                  |   S # t
        $ r"}t        t        d|z        |       Y d}~yd}~ww xY w)a  Guess the MIME type from the URL.

        This is used to fill in :attr:`~.Media.type` when it is not given (and
        thus called implicitly by the constructor), but you can call it
        yourself.

        Example::

            >>> from podgen import Media
            >>> m = Media("http://example.org/1.mp3", 136532744)
            >>> # The type was detected from the url:
            >>> m.type
            audio/mpeg
            >>> # Ops, I changed my mind...
            >>> m.url = "https://example.org/1.m4a"
            >>> # As you can see, the type didn't change:
            >>> m.type
            audio/mpeg
            >>> # So update type yourself
            >>> m.type = m.get_type(m.url)
            >>> m.type
            audio/x-m4a

        :param url: The URL which should be used to guess the MIME type.
        :type url: str
        :returns: The guessed MIME type.
        :raises: ValueError if the MIME type couldn't be guessed from the URL.
        r0   r1   zThe file extension %s was not recognized, which means it's not supported by iTunes. If this is intended, please provide the type yourself so clients can see what type of file it is.N)r   r8   r9   r:   r;   r^   r	   r7   )r+   r&   r@   rH   s       r   r(   zMedia.get_type  sy    : "#++11#6r:@@B	&??>22 	&zP !!" $%	& &	&s   A 	A1A,,A1c                     | j                   S )a6  The duration of the media file.

        :type: :class:`datetime.timedelta`
        :raises: :obj:`TypeError` if you try to assign anything other than
            :class:`datetime.timedelta` or :obj:`None` to this attribute. Raises
            :obj:`ValueError` if a negative timedelta value is given.
        )r%   r.   s    r   r*   zMedia.duration<  s     ~~r   c                     |d | _         y t        |t        j                        st	        d      |j                         dk  rt        d|z        || _         y )Nz/duration must be a datetime.timedelta instance!r   z%expected a positive timedelta, got %s)r%   
isinstancedatetime	timedeltarG   total_secondsr7   )r+   r*   s     r   r*   zMedia.durationG  sT    !DNHh&8&89MNN##%)DxOPP%DNr   c                    | j                   y| j                   j                  dz  | j                   j                  dz  z   }| j                   j                  dz  dz  }| j                   j                  dz  }|rd|||fz  S d||fz  S )aw  :attr:`.duration`, formatted as a string according to iTunes' specs.
        That is, HH:MM:SS if it lasts more than an hour, or MM:SS if it lasts
        less than an hour.

        This is just an alternate, read-only view of :attr:`.duration`.

        If :attr:`.duration` is :obj:`None`, then this will be :obj:`None` as
        well.

        :type: :obj:`str`
        N   i  <   z%02d:%02d:%02dz	%02d:%02d)r*   daysseconds)r+   hoursminutesrp   s       r   duration_strzMedia.duration_strR  s     == MM&&+MM))T12E}},,2b8Gmm++b0G'5'7*CCC"gw%777r   c                 >   |r|sV|xs
 t               }|j                  |dd      }|j                          |s	 |j                  d   }|s	 |j                  d   }t        ||||      S # t        $ r t        d|z        w xY w# t        $ r t        d|z        w xY w)a  Create new Media object, with size and/or type fetched from the
        server when not given.

        See :meth:`.Media.fetch_duration` for a (slow!) way to fill in the
        duration as well.

        Example (assuming the server responds with Content-Length: 252345991 and
        Content-Type: audio/mpeg)::

            >>> from podgen import Media
            >>> # Assume an episode is hosted at example.com
            >>> m = Media.create_from_server_response(
            ...     "http://example.com/episodes/ep1.mp3")
            >>> m
            Media(url=http://example.com/episodes/ep1.mp3, size=252345991,
                type=audio/mpeg, duration=None)


        :param url: The URL at which the media can be accessed right now.
        :type url: str
        :param size: Size of the file. Will be fetched from server if not given.
        :type size: int or None
        :param type: The media type of the file. Will be fetched from server if
            not given.
        :type type: str or None
        :param duration: The media's duration.
        :type duration: :class:`datetime.timedelta` or :obj:`None`
        :param requests_: Either the
            `requests <http://docs.python-requests.org/en/master/>`_ module
            itself, or a :class:`requests.Session` object. Defaults to a new
            :class:`~requests.Session`.
        :type requests_: :mod:`requests` or :class:`requests.Session`
        :returns: New instance of Media with url, size and type filled in.
        :raises: The appropriate requests exceptions are thrown when networking
            errors occur. RuntimeError is thrown if some information isn't
            given and isn't found in the server's response.Tg      $@)allow_redirectstimeoutzContent-LengthzEContent-Length not returned by server when sending HEAD request to %szContent-TypezJContent-Type header not returned by server when sending HEAD request to %s)r   headraise_for_statusr   r^   RuntimeErrorr   )clsr&   r'   r)   r*   	requests_rs          r   create_from_server_responsez!Media.create_from_server_responsel  s    N !@%>%@IsD$GA P99%56D .99^4D S$h//   P& (IKN(O P PP   .& (P),(- . ..s   A) B )BBc           	      p    d| j                   d| j                  d| j                  d| j                  d	S )Nz
Media(url=z, size=z, type=z, duration=))r&   r'   r)   r*   r.   s    r   __str__zMedia.__str__  s%    $))TYY? 	?r   c                 "    | j                         S r   )r   r.   s    r   __repr__zMedia.__repr__  s    ||~r   c                 @    | j                   j                         }|d= |S )Nr   )__dict__copyr+   states     r   __getstate__zMedia.__getstate__  s"    ""$$%r   c                 X    | j                   j                  |       t               | _        y r   )r   updater   r   r   s     r   __setstate__zMedia.__setstate__  s    U# 9 ;r   c                    | j                   j                  | j                  d      }|j                          d}t	        |d      }	 |r|}nt        |d      }|j                  d      D ]  }|j                  |       ~ 	 |r|s|j                          yyy# t        t        t        f$ r< |r8|s6	 |j                          t        j                  |        # t        $ r Y  w xY w w xY w# |r|s|j                          w w w xY w)a%  Download the media file.

        This method will block until the file is downloaded in its entirety.

        .. note::

            The destination will not be populated atomically; if you need this,
            you must give provide a temporary file as destination and rename the
            file yourself.

        :param destination: Where to save the media file. Either a filename,
            or a file-like object. The file-like object will *not* be closed by
            PodGen.
        :type destination: :obj:`fd` or :obj:`str`.
        T)streamNwritewb)
chunk_size)r   getr&   rx   hasattropeniter_contentr   	ExceptionKeyboardInterruptInterruptedErrorcloseosremoveFileNotFoundError)r+   destinationr|   fddestination_is_fdchunks         r   downloadzMedia.download  s   " !!%%dhht%<	#K9	  +t,48 9 +
 ,r ,.>? 	+HHJIIk*  ) 	 +
 ,rs<   :B C)2%CC)	C$!C)#C$$C))C, ,Dc                 0    | j                  |      | _        y)ad  Populate :attr:`.Media.duration` by analyzing the given file.

        Use this method when you have the media file on the local file system.
        Use :meth:`.Media.fetch_duration` if you need to download the file from
        the server.

        :param filename: Path to the media file which shall be used to determine
            this media's duration. The file extension must match its file type,
            since it is used to determine what type of media file it is. For
            a list of supported formats, see
            https://pypi.python.org/pypi/tinytag/
        :type filename: str
        N)_get_duration_ofr*   )r+   filenames     r   populate_duration_fromzMedia.populate_duration_from  s     --h7r   c                 h    t        j                  t        j                  |       j                        S )ag  Return the duration of the media file located at ``filename``.

        Use :meth:`.Media.populate_duration_from` if you want to populate the
        duration property of a Media instance using a local file.

        :param filename: Path to the media file which shall be used to determine
            this media's duration. The file extension must match its file type,
            since it is used to determine what type of media file it is. For
            a list of supported formats, see
            https://pypi.python.org/pypi/tinytag/
        :type filename: str
        :returns: datetime.timedelta
        )rp   )ri   rj   r
   r   r*   )r   s    r   r   zMedia._get_duration_of  s$     !!'++h*?*H*HIIr   c                 <   d}	 t        j                  d| j                        5 }|j                  }| j	                  |       ddd       | j                  |       |rt        j                  |       yy# 1 sw Y   3xY w# |rt        j                  |       w w xY w)as  Download :attr:`.Media.url` locally and use it to populate
        :attr:`.Media.duration`.

        Use this method when you don't have the media file on the local file
        system. Use :meth:`~.Media.populate_duration_from` otherwise.

        This method will take quite some time, since the media file must be
        downloaded before it can be analyzed.
        NF)deletesuffix)tempfileNamedTemporaryFiler@   r   r   r   r   r   )r+   r   r   s      r   fetch_durationzMedia.fetch_duration  s     	$,, )<)<>AC77b!> ''1		(# > > 		(# s"   !B A5B 5A>:B B)r   NNN)NNNN)__name__
__module____qualname____doc__r;   r,   propertyr&   setterr@   r'   staticmethodrF   r)   r(   r*   rs   classmethodr}   r   r   r   r   r   r   r   r    r   r   r   r   +   s|   /b   !J 9="&6  $ 	ZZ   < <  8 
[[ ( G G,  $ 
[[	 	%&N   __& & 8 82 >B=A80 80t?
<)V8  J J $r   r   )r   
__future__r   r   r   r   builtinsfuture.moves.urllib.parser   future.utilsr	   r   r   r<   ri   tinytagr
   r   podgen.warningsr   podgenr   r   objectr   r   r   r   <module>r      sG   	 S R  . # 	      7 
k$F k$r   