3
]1                 @   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Zddl	m
Z
 ddlmZmZ ddlZdad+dd	Zd,ddZd.ddZd/ddZd0ddZd1ddZdd Zdd Zd2ddZdd  Zd!d" Zd#d$ ZG d%d& d&eZG d'd( d(e
jZdS )3z?
The Utils class contains many functions for project-wide use.
    N)futures)logceilFi      c             C   s   t | dkrtj| d | nlt|d\}xT| D ]L}t|d.}|j|}x|rf|j| |j|}qLW W dQ R X tj| q0W W dQ R X dS )z
	Combines files.

	:param parts: Source files.
	:type parts: list of strings
	:param dest: Destination file.
	:type dest: string
    :param chunkSize: Fetching chunk size.
	:type chunkSize: int

	   r   wbrbN)lenshutilmoveopenreadwriteosremove)partsdestZ	chunkSizeoutputpartinputdata r   =C:\Users\ibrahim.fayad\Desktop\SentinelTUI\pySmartDL\utils.pycombine_files   s    


r   utf-8c             C   sH   t jj| \}}}}}t jj|d}t jj|d}t jj|||||fS )u  
    Sometimes you get an URL by a user that just isn't a real
    URL because it contains unsafe characters like ' ' and so on.  This
    function can fix some of the problems in a similar way browsers
    handle data entered by the user:

    >>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffsklärung)')
    'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'

    :param s: Url address.
    :type s: string
    :param charset: The target charset for the URL if the url was
                    given as unicode string. Default is 'utf-8'.
    :type charset: string
    :rtype: string
                    
    (taken from `werkzeug.utils <http://werkzeug.pocoo.org/docs/utils/>`_)
    z/%z:&=)urllibparseurlsplitquote
quote_plus
urlunsplit)scharsetschemenetlocpathqsZanchorr   r   r   url_fix)   s    r'   -#   c             C   sT   |d8 }| dk rd} | dkr d} d|d t | |   |d |t | |    d S )a:  
    Returns a textual progress bar.
    
    >>> progress_bar(0.6)
    '[##########--------]'
    
    :param progress: Number between 0 and 1 describes the progress.
    :type progress: float
    :param length: The length of the progress bar in chars. Default is 20.
    :type length: int
    :rtype: string
       r   r   [])int)progress	look_feellengthr   r   r   progress_barA   s    r2      c             C   sb   | j dd} t| }|sdS ddi}tjj| |d}tjj||d}t|jd }|j  ||kS )	a_  
    Checks if a server allows `Byte serving <https://en.wikipedia.org/wiki/Byte_serving>`_,
    using the Range HTTP request header and the Accept-Ranges and Content-Range HTTP response headers.
    
    :param url: Url address.
    :type url: string
    :param timeout: Timeout in seconds. Default is 15.
    :type timeout: int
    :rtype: bool
     z%20FRangez	bytes=0-3)headers)timeoutzContent-Length)	replaceget_filesizer   requestRequesturlopenr.   r6   close)urlr7   Zfullsizer6   requrlObjfilesizer   r   r   is_HTTPRange_supportedU   s    rB   c             C   sH   t jj| f|}yt jj||d}|jd dkS  tk
rB   dS X d S )N)r7   zaccept-rangesbytesF)r   r:   r;   r<   r6   	Exception)r>   r6   r7   r?   r@   r   r   r   auto_detect_HTTPRange_supportn   s    rE   c             C   sN   y"t jj| |d}t|jd }W n& tttt jj	t jj
fk
rH   dS X |S )z
    Fetches file's size of a file over HTTP.
    
    :param url: Url address.
    :type url: string
    :param timeout: Timeout in seconds. Default is 15.
    :type timeout: int
    :returns: Size in bytes.
    :rtype: int
    )r7   zContent-Lengthr   )r   r:   r<   r.   r6   
IndexErrorKeyError	TypeErrorerror	HTTPErrorURLError)r>   r7   r@   	file_sizer   r   r   r9   v   s     r9   c              C   s6   ddddddddd	d
ddddddddddg} t j| S )z
    Returns a random popular user-agent.
    Taken from `here <http://techblog.willshouse.com/2012/01/03/most-common-user-agents/>`_, last updated on 2019/07/26.
    
    :returns: user-agent
    :rtype: string
    zsMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36zsMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36zsMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36zyMozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36zNMozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0zwMozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15zNMozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0zrMozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36ziMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36zyMozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36zLMozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0zrMozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36zRMozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:67.0) Gecko/20100101 Firefox/67.0zyMozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36zMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134zMMozilla/5.0 (Windows NT 6.1; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0zAMozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0zMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763zRMozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0zLMozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0)randomchoice)lr   r   r   get_random_useragent   s*    	rP   c          	   C   s   t tddddddgdddd	d	d	g}| dkrzttt| d
t|d }t| d
|  }|| \}}d| }|j||S | dkrdS | dkrdS dS )a2  
    Human-readable formatting for filesizes. Taken from `here <http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size>`_.
    
    >>> sizeof_human(175799789)
    '167.7 MB'
    
    :param num: Size in bytes.
    :type num: int
    
    :rtype: string
    BZkBMBZGBZTBZPBr   r   r+   i   z{:,.%sf} {}z0 bytesz1 byteN)listzipminr.   r   r	   floatformat)numZ	unit_listexponentZquotientunitZnum_decimalsformat_stringr   r   r   sizeof_human   s    &r\   c       	      C   s*  t | d d }t | } | dkr:| s.|dkr:|r6dS dS ddddd	d
dg}|rbd(d)d*d+d,d-g}nd.d/d0d1d2d3d4g}g }xZtt|d d5d6D ]B}| ||  }|dkr|j||| d|  f | |||  8 } qW | r|dk r|j|| rd!nd"f |rd#jd$d% |D S d&jd'd% |D S )7az  
    Human-readable formatting for timing. Based on code from `here <http://stackoverflow.com/questions/6574329/how-can-i-produce-a-human-readable-difference-when-subtracting-two-unix-timestam>`_.
    
    >>> time_human(175799789)
    '6 years, 2 weeks, 4 days, 17 hours, 16 minutes, 29 seconds'
    >>> time_human(589, fmt_short=True)
    '9m49s'
    
    :param duration: Duration in seconds.
    :type duration: int/float
    :param fmt_short: Format as a short string (`47s` instead of `47 seconds`)
    :type fmt_short: bool
    :param show_ms: Specify milliseconds in the string.
    :type show_ms: bool
    :rtype: string
    r   i  r   Z0sz	0 seconds<   i  iQ i:	 i $ i r!   r+   mhdwysecondsecondsminuteminuteshourhoursdaydaysweekweeksmonthmonthsyearyearsmsmilliseconds c             S   s   g | ]}d | qS )z%s%sr   ).0xr   r   r   
<listcomp>   s    ztime_human.<locals>.<listcomp>z, c             S   s   g | ]}d | qS )z%s %sr   )rt   ru   r   r   r   rv      s    ssmmhhddZwwyy)rc   rd   )re   rf   )rg   rh   )ri   rj   )rk   rl   )rm   rn   )ro   rp   r|   )r.   ranger	   appendjoin)	Zduration	fmt_shortZshow_msrq   Z	INTERVALSZNAMESresultiar   r   r   
time_human   s2    r   c          	   C   sT   t j| }d}t|d.}|j|}x|r@|j| |j|}q&W W dQ R X |j S )ah  
    Calculates a file's hash.

    .. WARNING::
        The hashing algorithm must be supported on your system, as documented at `hashlib documentation page <http://docs.python.org/3/library/hashlib.html>`_.
    
    :param algorithm: Hashing algorithm.
    :type algorithm: string
    :param path: The file path
    :type path: string
    :rtype: string
    r   i   r+   r   Ni   i   )hashlibnewr   r   update	hexdigest)	algorithmr%   ZhashAlgZblock_szfr   r   r   r   get_file_hash   s    


r   c       	      C   s   | s
dgS x$t | | |k r.|dkr.|d8 }qW g }d}t | | }xJt|D ]>}|}|| }|| d krr| d }|j||f ||d 7 }qNW |S )a+  
    Calculates the byte chunks to download.
    
    :param filesize: filesize in bytes.
    :type filesize: int
    :param threads: Number of trheads
    :type threads: int
    :param minChunkFile: Minimum chunk size
    :type minChunkFile: int
    :rtype: Array of (startByte,endByte) tuples
    r   r   )r   r   )r   r}   r~   )	rA   threadsminChunkFileargsposchunkr   Z	startByteZendByter   r   r   calc_chunk_size  s    r   c              C   sP   t jd} tsL| jt j t j }|jt j |jt jd | j| da| S )zg
    Creates a debugging logger that prints to console.
    
    :rtype: `logging.Logger` instance
    	pySmartDLzA[%(levelname)s||%(thread)d@{%(pathname)s:%(lineno)d}] %(message)sT)	logging	getLoggerDEFAULT_LOGGER_CREATEDsetLevelDEBUGStreamHandlersetFormatter	Formatter
addHandler)Zt_logZconsoler   r   r   create_debugging_logger.  s    

r   c               @   s(   e Zd ZdZdd Zdd Zdd ZdS )	DummyLoggerzk
    A dummy logger. You can call `debug()`, `warning()`, etc on this object, and nothing will happen.
    c             C   s   d S )Nr   )selfr   r   r   __init__F  s    zDummyLogger.__init__c             O   s   d S )Nr   )r   r   Zkargsr   r   r   
dummy_funcI  s    zDummyLogger.dummy_funcc             C   s   |j drtj|S | jS )N__)
startswithobject__getattr__r   )r   namer   r   r   r   L  s    

zDummyLogger.__getattr__N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   B  s   r   c                   s@   e Zd ZdZdd Z fddZdd Zdd	 Zd
d Z  Z	S )ManagedThreadPoolExecutorzF
	Managed Thread Pool Executor. A subclass of ThreadPoolExecutor.
    c             C   s   t jj| | g | _d S )N)r   ThreadPoolExecutorr   _futures)r   Zmax_workersr   r   r   r   U  s    z"ManagedThreadPoolExecutor.__init__c                s$   t  j|f||}| jj| |S )N)supersubmitr   r~   )r   fnr   kwargsfuture)	__class__r   r   r   Y  s    z ManagedThreadPoolExecutor.submitc             C   s   t dd | jD S )Nc             S   s   g | ]}|j  qS r   )done)rt   ru   r   r   r   rv   _  s    z2ManagedThreadPoolExecutor.done.<locals>.<listcomp>)allr   )r   r   r   r   r   ^  s    zManagedThreadPoolExecutor.donec             C   s.   g }x$| j D ]}|j r|j|j  qW |S )zY
        Return all the exceptions raised.

        :rtype: List of `Exception` instances)r   	exceptionr~   )r   rO   ru   r   r   r   get_exceptionsa  s
    z(ManagedThreadPoolExecutor.get_exceptionsc             C   s$   x| j D ]}|j r|j S qW dS )z
        Returns only the first exception. Returns None if no exception was raised.

        :rtype: `Exception` instance
        N)r   r   )r   ru   r   r   r   get_exceptionl  s    z'ManagedThreadPoolExecutor.get_exception)
r   r   r   r   r   r   r   r   r   __classcell__r   r   )r   r   r   Q  s   r   i     @ )r   )r   r(   r)   )r   r*   )r3   )Nr3   )r3   )FF) r   r   urllib.requestr   urllib.parseurllib.errorrM   r   r   Z
concurrentr   mathr   r   r
   r   r   r'   r2   rB   rE   r9   rP   r\   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s.   





 
3