B
    ]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d+ddZd,ddZdd Zdd Zd-d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 ).z?
The Utils class contains many functions for project-wide use.
    N)futures)logceilF  @ c             C   s   t | dkrt| d | nlt|d\}xT| D ]L}t|d.}||}x|rf|| ||}qLW W dQ R X t| 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   EC:\Users\ibrahim.fayad\Desktop\sentSatProg_v.0.1.3\pySmartDL\utils.pycombine_files   s    


r   utf-8c             C   sH   t j| \}}}}}t j|d}t j|d}t 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    r3      c             C   sb   |  dd} t| }|sdS ddi}tjj| |d}tjj||d}t|jd }|  ||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/   r7   close)urlr8   Zfullsizer7   requrlObjfilesizer   r   r   is_HTTPRange_supportedU   s    rC   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)r8   zaccept-rangesbytesF)r   r;   r<   r=   r7   	Exception)r?   r7   r8   r@   rA   r   r   r   auto_detect_HTTPRange_supportn   s    rF   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
    )r8   zContent-Lengthr   )r   r;   r=   r/   r7   
IndexErrorKeyError	TypeErrorerror	HTTPErrorURLError)r?   r8   rA   	file_sizer   r   r   r:   v   s     r:   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 | 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*    	rQ   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| }|||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r8|r,|dkr8|r4dS dS ddddd	d
dg}|r`ddddddg}ndddddddg}g }xZtt|d ddD ]B}| ||  }|dkr|||| d|  f | |||  8 } qW |r|dkr|||rdndf |rddd |D S dd d |D S )!az  
    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 ssmmhhddZwwyy)secondseconds)minuteminutes)hourhours)daydays)weekweeks)monthmonths)yearZ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   )ru   rv   r   r   r   rw      s    )r/   ranger	   appendjoin)	Zduration	fmt_shortZshow_msrr   Z	INTERVALSZNAMESresultiar   r   r   
time_human   s2    r   c          	   C   sT   t | }d}t|d.}||}x|r@|| ||}q&W W dQ R X | 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
    i   r   N)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 }|||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   rx   ry   )	rB   threadsminChunkFileargsposchunkr}   Z	startByteZendByter   r   r   calc_chunk_size  s    r   c              C   sP   t d} tsL| t j t  }|t j |t d | | 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   | drt|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| | 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| |S )N)supersubmitr   ry   )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 | ]}|  qS r   )done)ru   rv   r   r   r   rw   _  s    z2ManagedThreadPoolExecutor.done.<locals>.<listcomp>)allr   )r   r   r   r   r   ^  s    zManagedThreadPoolExecutor.donec             C   s.   g }x$| j D ]}| r||  qW |S )zY
        Return all the exceptions raised.

        :rtype: List of `Exception` instances)r   	exceptionry   )r   rP   rv   r   r   r   get_exceptionsa  s
    z(ManagedThreadPoolExecutor.get_exceptionsc             C   s$   x| j D ]}| r| 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   rv   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   )r   )r   )r(   r+   )r4   )Nr4   )r4   )FF) r   r   urllib.requestr   urllib.parseurllib.errorrN   r   r   Z
concurrentr   mathr   r   r
   r   r   r'   r3   rC   rF   r:   rQ   r]   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s.   





 
3