o
    {#iX  ã                   @   s  d Z ddlZddlZddlmZ ddlmZmZmZm	Z	m
Z
mZ ddlmZmZ ddlmZmZ ddlmZmZ e e¡ZG dd	„ d	ƒZd
edefdd„Zd
ede	e fdd„Zd
edede	e fdd„Zd
ededefdd„Zd
edefdd„Zd
edefdd„Zd
ede	e fdd„Z d
efdd„Z!de	de
e fdd „Z"de	d!e#fd"d#„Z$de	d!e#fd$d%„Z%de&fd&d'„Z'd(e&d)efd*d+„Z(d(e&d)e#fd,d-„Z)d(e&d)e#fd.d/„Z*d(e&d)efd0d1„Z+d(e&d)e#fd2d3„Z,d(e&d)e#fd4d5„Z-d(e&d)e#fd6d7„Z.d>de&d8e#fd9d:„Z/d;edefd<d=„Z0dS )?aX  
This module contains all logic necessary to decipher the signature.

YouTube's strategy to restrict downloading videos is to send a ciphered version
of the signature to the client, along with the decryption algorithm obfuscated
in JavaScript. For the clients to play the videos, JavaScript must take the
ciphered version, cycle it through a series of "transform functions," and then
signs the media URL with the output.

This module is responsible for (1) finding and extracting those "transform
functions" (2) maps them to Python equivalents and (3) taking the ciphered
signature and decoding it.

é    N)Úchain)ÚAnyÚCallableÚDictÚListÚOptionalÚTuple)ÚExtractErrorÚRegexMatchError)ÚcacheÚregex_search)Úfind_object_from_startpointÚthrottling_array_splitc                   @   sX   e Zd Zdefdd„Zdefdd„Zdedefd	d
„Zedede	ee
f fdd„ƒZdS )ÚCipherÚjsc                 C   s|   t |ƒ| _t d¡}| | jd ¡}|std|jd‚| d¡d d… }t||ƒ| _	ddg| _
t|ƒ| _t|ƒ| _d | _d S )Nz^\w+\Wr   Ú__init__©ÚcallerÚpatternéÿÿÿÿz\w+\.(\w+)\(\w,(\d+)\)z\w+\[(\"\w+\")\]\(\w,(\d+)\))Úget_transform_planÚtransform_planÚreÚcompileÚsearchr
   r   ÚgroupÚget_transform_mapÚtransform_mapÚjs_func_patternsÚget_throttling_planÚthrottling_planÚget_throttling_function_arrayÚthrottling_arrayÚcalculated_n)Úselfr   Ú	var_regexÚ	var_matchÚvar© r(   úT/var/www/GraceOrthoHospital/venv_grace/lib/python3.10/site-packages/pytube/cipher.pyr      s   

ÿþ


zCipher.__init__Ú	initial_nc                 C   sò   | j r| j S tt| jƒƒD ]}| j| dkr|| j|< q| jD ]P}| jt|d ƒ }t|ƒsGt |› d¡ t d| j› d¡ t	|› dƒ‚| jt|d ƒ }t|ƒdkr[||ƒ qt|ƒdkro| jt|d ƒ }|||ƒ qd	 
|¡| _ | j S )
z6Converts n to the correct value to prevent throttling.Úbr   z is not callable.zThrottling array:
Ú
é   é   é   Ú )r#   ÚrangeÚlenr"   r    ÚintÚcallableÚloggerÚdebugr	   Újoin)r$   r*   ÚiÚstepÚ	curr_funcÚ	first_argÚ
second_argr(   r(   r)   Úcalculate_n0   s*   
€


€zCipher.calculate_nÚciphered_signatureÚreturnc              	   C   sZ   t |ƒ}| jD ] }|  |¡\}}| j| ||ƒ}t dd |¡||| j| ¡ qd |¡S )aA  Decipher the signature.

        Taking the ciphered signature, applies the transform functions.

        :param str ciphered_signature:
            The ciphered signature sent in the ``player_config``.
        :rtype: str
        :returns:
            Decrypted signature required to download the media content.
        zOapplied transform function
output: %s
js_function: %s
argument: %d
function: %sr0   )Úlistr   Úparse_functionr   r5   r6   r7   )r$   r>   Ú	signatureÚjs_funcÚnameÚargumentr(   r(   r)   Úget_signatureL   s   
÷
zCipher.get_signaturerC   c                 C   sV   t  d¡ | jD ]}t |¡}| |¡}|r$| ¡ \}}|t|ƒf  S qtddd‚)aè  Parse the Javascript transform function.

        Break a JavaScript transform function down into a two element ``tuple``
        containing the function name and some integer-based argument.

        :param str js_func:
            The JavaScript version of the transform function.
        :rtype: tuple
        :returns:
            two element tuple containing the function name and an argument.

        **Example**:

        parse_function('DE.AJ(a,15)')
        ('AJ', 15)

        zparsing transform functionrA   r   r   )	r5   r6   r   r   r   r   Úgroupsr3   r
   )r$   rC   r   ÚregexÚparse_matchÚfn_nameÚfn_argr(   r(   r)   rA   j   s   



þÿzCipher.parse_functionN)Ú__name__Ú
__module__Ú__qualname__Ústrr   r@   r=   rF   r   r   r3   rA   r(   r(   r(   r)   r      s     r   r   r?   c                 C   sZ   g d¢}t  d¡ |D ]}t |¡}| | ¡}|r&t  d|¡ | d¡  S qtddd‚)zÖExtract the name of the function responsible for computing the signature.
    :param str js:
        The contents of the base.js asset file.
    :rtype: str
    :returns:
        Function name from regex match
    )zX\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(zg\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(zi(?:\b|[^a-zA-Z0-9$])(?P<sig>[a-zA-Z0-9$]{2})\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)zS(?P<sig>[a-zA-Z0-9$]+)\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)z1(["\'])signature\1\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(z!\.sig\|\|(?P<sig>[a-zA-Z0-9$]+)\(z€yt\.akamaized\.net/\)\s*\|\|\s*.*?\s*[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?:encodeURIComponent\s*\()?\s*(?P<sig>[a-zA-Z0-9$]+)\(z>\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(zM\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(zH\bc\s*&&\s*a\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(úS\bc\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(rP   zfinding initial function nameú"finished regex search, matched: %sr-   Úget_initial_function_nameÚmultipler   )r5   r6   r   r   r   r   r
   )r   Úfunction_patternsr   rH   Úfunction_matchr(   r(   r)   rR   Š   s   	


þÿrR   c                 C   s4   t  t| ƒ¡}d| }t d¡ t|| dd d¡S )a‹  Extract the "transform plan".

    The "transform plan" is the functions that the ciphered signature is
    cycled through to obtain the actual signature.

    :param str js:
        The contents of the base.js asset file.

    **Example**:

    ['DE.AJ(a,15)',
    'DE.VR(a,3)',
    'DE.AJ(a,51)',
    'DE.VR(a,3)',
    'DE.kT(a,51)',
    'DE.kT(a,8)',
    'DE.VR(a,3)',
    'DE.kT(a,21)']
    z.%s=function\(\w\){[a-z=\.\(\"\)]*;(.*);(?:.+)}zgetting transform planr-   )r   ú;)r   ÚescaperR   r5   r6   r   Úsplit)r   rD   r   r(   r(   r)   r   ®   s   
r   r'   c                 C   sZ   dt  |¡ }t d¡ t j|t jd}| | ¡}|s!td|d‚| d¡ 	dd¡ 
d	¡S )
aå  Extract the "transform object".

    The "transform object" contains the function definitions referenced in the
    "transform plan". The ``var`` argument is the obfuscated variable name
    which contains these functions, for example, given the function call
    ``DE.AJ(a,15)`` returned by the transform plan, "DE" would be the var.

    :param str js:
        The contents of the base.js asset file.
    :param str var:
        The obfuscated variable name that stores an object with all functions
        that descrambles the signature.

    **Example**:

    >>> get_transform_object(js, 'DE')
    ['AJ:function(a){a.reverse()}',
    'VR:function(a,b){a.splice(0,b)}',
    'kT:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c}']

    zvar %s={(.*?)};zgetting transform object)ÚflagsÚget_transform_objectr   r-   r,   ú z, )r   rW   r5   r6   r   ÚDOTALLr   r
   r   ÚreplacerX   )r   r'   r   rH   Útransform_matchr(   r(   r)   rZ   È   s   

rZ   c                 C   s<   t | |ƒ}i }|D ]}| dd¡\}}t|ƒ}|||< q	|S )aW  Build a transform function lookup.

    Build a lookup table of obfuscated JavaScript function names to the
    Python equivalents.

    :param str js:
        The contents of the base.js asset file.
    :param str var:
        The obfuscated variable name that stores an object with all functions
        that descrambles the signature.

    ú:r-   )rZ   rX   Úmap_functions)r   r'   Útransform_objectÚmapperÚobjrD   ÚfunctionÚfnr(   r(   r)   r   è   s   

r   c              	   C   sØ   dg}t  d¡ |D ][}t |¡}| | ¡}|ret  d|¡ t| ¡ ƒdkr-| d¡  S | d¡}|re| d¡}t dj	t 
| d¡¡d| ¡}|re| d¡ d¡ d	¡}d
d„ |D ƒ}|t|ƒ   S q
tddd‚)zúExtract the name of the function that computes the throttling parameter.

    :param str js:
        The contents of the base.js asset file.
    :rtype: str
    :returns:
        The name of the function used to compute the throttling parameter.
    zha\.[a-zA-Z]\s*&&\s*\([a-z]\s*=\s*a\.get\("n"\)\)\s*&&\s*\([a-z]\s*=\s*([a-zA-Z0-9$]+)(\[\d+\])?\([a-z]\)z Finding throttling function namerQ   r-   r.   z[]zvar {nfunc}\s*=\s*(\[.+?\]);)Únfuncú,c                 S   s   g | ]}|  ¡ ‘qS r(   )Ústrip)Ú.0Úxr(   r(   r)   Ú
<listcomp>%  s    z0get_throttling_function_name.<locals>.<listcomp>Úget_throttling_function_namerS   r   )r5   r6   r   r   r   r2   rG   r   rh   ÚformatrW   rX   r3   r
   )r   rT   r   rH   rU   ÚidxÚarrayr(   r(   r)   rl   ÿ   s6   ø




ÿý€ÿrl   c                 C   sZ   t  t| ƒ¡}d| }t  |¡}| | ¡}t| | ¡ d ƒ d¡}d |¡}| 	d¡| S )zãExtract the raw code for the throttling function.

    :param str js:
        The contents of the base.js asset file.
    :rtype: str
    :returns:
        The name of the function used to compute the throttling parameter.
    z%s=function\(\w\)r-   r,   r0   r   )
r   rW   rl   r   r   r   ÚspanrX   r7   r   )r   rD   Úpattern_startrH   ÚmatchÚcode_lines_listÚjoined_linesr(   r(   r)   Úget_throttling_function_code-  s   



ru   c                 C   sX  t | ƒ}d}t |¡}| |¡}t|| ¡ d d ƒ}t|ƒ}g }|D ]s}z	| t|ƒ¡ W q# t	y7   Y nw |dkrB| d¡ q#| 
d¡rV| d¡rV| |dd… ¡ q#| 
d¡r‘dtfd	tfd
tfdtfdtfdtfdtfdtfdtff	}	d}
|	D ]\}}t ||¡r| |¡ d}
q||
r‘q#| |¡ q#tt|ƒƒD ]}|| du r©|||< q|S )z«Extract the "c" array.

    :param str js:
        The contents of the base.js asset file.
    :returns:
        The array of various integers, arrays, and functions.
    z,c=\[r-   ÚnullNú"r   rd   zS{for\(\w=\(\w%\w\.length\+\w\.length\)%\w\.length;\w--;\)\w\.unshift\(\w.pop\(\)\)}ú{\w\.reverse\(\)}z{\w\.push\(\w\)}z.;var\s\w=\w\[0\];\w\[0\]=\w\[\w\];\w\[\w\]=\w}z	case\s\d+z1\w\.splice\(0,1,\w\.splice\(\w,1,\w\[0\]\)\[0\]\)z;\w\.splice\(\w,1\)}zL\w\.splice\(-\w\)\.reverse\(\)\.forEach\(function\(\w\){\w\.unshift\(\w\)}\)zBfor\(var \w=\w\.length;\w;\)\w\.push\(\w\.splice\(--\w,1\)\[0\]\)}FT)ru   r   r   r   r   rp   r   Úappendr3   Ú
ValueErrorÚ
startswithÚendswithÚthrottling_unshiftÚthrottling_reverseÚthrottling_pushÚthrottling_swapÚthrottling_cipher_functionÚthrottling_nested_spliceÚ	js_spliceÚthrottling_prependr1   r2   )r   Úraw_codeÚarray_startÚarray_regexrr   Ú	array_rawÚ	str_arrayÚconverted_arrayÚelrb   Úfoundr   re   r8   r(   r(   r)   r!   F  sZ   

þ

÷
€€r!   c           
      C   s    t | ƒ}d}t |¡}| |¡}t|| ¡ d d ƒ}d}t |¡}| |¡}g }	|D ]"}|d dkrB|	 |d |d |d f¡ q+|	 |d |d f¡ q+|	S )a·  Extract the "throttling plan".

    The "throttling plan" is a list of tuples used for calling functions
    in the c array. The first element of the tuple is the index of the
    function to call, and any remaining elements of the tuple are arguments
    to pass to that function.

    :param str js:
        The contents of the base.js asset file.
    :returns:
        The full function code for computing the throttlign parameter.
    ztry{r-   z(c\[(\d+)\]\(c\[(\d+)\](,c(\[(\d+)\]))?\)é   r0   r   )ru   r   r   r   r   rp   Úfindallry   )
r   r…   Útransform_startÚ
plan_regexrr   Útransform_plan_rawÚ
step_startÚ
step_regexÚmatchesÚtransform_stepsr(   r(   r)   r   ˆ  s   



r   ÚarrÚ_c                 C   s   | ddd… S )a@  Reverse elements in a list.

    This function is equivalent to:

    .. code-block:: javascript

        function(a, b) { a.reverse() }

    This method takes an unused ``b`` variable as their transform functions
    universally sent two arguments.

    **Example**:

    >>> reverse([1, 2, 3, 4])
    [4, 3, 2, 1]
    Nr   r(   )r–   r—   r(   r(   r)   Úreverse«  s   r˜   r+   c                 C   s   | |d… S )zÓAdd/remove items to/from a list.

    This function is equivalent to:

    .. code-block:: javascript

        function(a, b) { a.splice(0, b) }

    **Example**:

    >>> splice([1, 2, 3, 4], 2)
    [1, 2]
    Nr(   )r–   r+   r(   r(   r)   Úsplice¿  s   r™   c                 C   s>   |t | ƒ }tt| | g| d|… | d g| |d d… ƒƒS )zùSwap positions at b modulus the list length.

    This function is equivalent to:

    .. code-block:: javascript

        function(a, b) { var c=a[0];a[0]=a[b%a.length];a[b]=c }

    **Example**:

    >>> swap([1, 2, 3, 4], 2)
    [3, 2, 1, 4]
    r-   r   N)r2   r@   r   )r–   r+   Úrr(   r(   r)   ÚswapÐ  s   2r›   c                 C   s4   |   ¡ ddd… }tt|ƒƒD ]}|| | |< qdS )zÈReverses the input list.

    Needs to do an in-place reversal so that the passed list gets changed.
    To accomplish this, we create a reversed copy, and then change each
    indvidual element.
    Nr   )Úcopyr1   r2   )r–   Úreverse_copyr8   r(   r(   r)   r~   â  s   ÿr~   ÚdÚec                 C   s   |   |¡ dS )zPushes an element onto a list.N)ry   ©rž   rŸ   r(   r(   r)   r   î  s   r   c                 C   s   |t | ƒ t | ƒ t | ƒ S )zÞPerform the modular function from the throttling array functions.

    In the javascript, the modular operation is as follows:
    e = (e % d.length + d.length) % d.length

    We simply translate this to python here.
    )r2   r    r(   r(   r)   Úthrottling_mod_funcó  s   r¡   c                 C   sF   t | |ƒ}| | d… | d| …  }|  ¡  |D ]}|  |¡ qdS )z©Rotates the elements of the list to the right.

    In the javascript, the operation is as follows:
    for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())
    N)r¡   Úclearry   )rž   rŸ   Únew_arrr‹   r(   r(   r)   r}   þ  s   
ÿr}   c           	      C   s€   t dƒ}d}t |ƒ}|  ¡ }t|ƒD ]+\}}| |¡| || ¡ | d | t|ƒ }| || ¡ || | |< |d8 }qdS )a“  This ciphers d with e to generate a new list.

    In the javascript, the operation is as follows:
    var h = [A-Za-z0-9-_], f = 96;  // simplified from switch-case loop
    d.forEach(
        function(l,m,n){
            this.push(
                n[m]=h[
                    (h.indexOf(l)-h.indexOf(this[m])+m-32+f--)%h.length
                ]
            )
        },
        e.split("")
    )
    z@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_é`   é    r-   N)r@   rœ   Ú	enumerateÚindexr2   ry   )	rž   rŸ   ÚhÚfÚthisÚcopied_listÚmÚlÚbracket_valr(   r(   r)   r     s   ,ÿ
úr   c                 C   s2   t | |ƒ}t| |d| d ƒ}t| dd|d ƒ dS )aè  Nested splice function in throttling js.

    In the javascript, the operation is as follows:
    function(d,e){
        e=(e%d.length+d.length)%d.length;
        d.splice(
            0,
            1,
            d.splice(
                e,
                1,
                d[0]
            )[0]
        )
    }

    While testing, all this seemed to do is swap element 0 and e,
    but the actual process is preserved in case there was an edge
    case that was not considered.
    r-   r   N)r¡   rƒ   )rž   rŸ   Úinner_splicer(   r(   r)   r‚   -  s   
üür‚   c                 C   sb   t | ƒ}t| |ƒ}| | d… | d| …  }|  ¡  |D ]}|  |¡ qt | ƒ}||ks/J ‚dS )a;  

    In the javascript, the operation is as follows:
    function(d,e){
        e=(e%d.length+d.length)%d.length;
        d.splice(-e).reverse().forEach(
            function(f){
                d.unshift(f)
            }
        )
    }

    Effectively, this moves the last e elements of d to the beginning.
    N)r2   r¡   r¢   ry   )rž   rŸ   Ú	start_lenr£   r‹   Úend_lenr(   r(   r)   r„   Q  s   
r„   c                 C   s*   t | |ƒ}| d }| | | d< || |< dS )z6Swap positions of the 0'th and e'th elements in-place.r   N)r¡   )rž   rŸ   r©   r(   r(   r)   r€   p  s   
r€   Ústartc                 G   s¸   z|t | ƒkrt | ƒ}|dk rt | ƒ| }W n ty!   d}Y nw |r,|t | ƒ| kr2t | ƒ| }| ||| … }| d|… t|ƒ | || d…  }|  ¡  |D ]}|  |¡ qR|S )a¬  Implementation of javascript's splice function.

    :param list arr:
        Array to splice
    :param int start:
        Index at which to start changing the array
    :param int delete_count:
        Number of elements to delete from the array
    :param *items:
        Items to add to the array

    Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice  # noqa:E501
    r   N)r2   Ú	TypeErrorr@   r¢   ry   )r–   r²   Údelete_countÚitemsÚdeleted_elementsr£   r‹   r(   r(   r)   rƒ   x  s"   €þ$rƒ   rC   c                 C   sJ   dt fdtfdtfdtff}|D ]\}}t || ¡r|  S qtddd‚)z For a given JavaScript transform function, return the Python equivalent.

    :param str js_func:
        The JavaScript version of the transform function.
    rx   z{\w\.splice\(0,\w\)}z9{var\s\w=\w\[0\];\w\[0\]=\w\[\w\%\w.length\];\w\[\w\]=\w}zD{var\s\w=\w\[0\];\w\[0\]=\w\[\w\%\w.length\];\w\[\w\%\w.length\]=\w}r`   rS   r   )r˜   r™   r›   r   r   r
   )rC   rb   r   re   r(   r(   r)   r`   ¢  s   þøÿr`   )N)1Ú__doc__Úloggingr   Ú	itertoolsr   Útypingr   r   r   r   r   r   Úpytube.exceptionsr	   r
   Úpytube.helpersr   r   Úpytube.parserr   r   Ú	getLoggerrL   r5   r   rO   rR   r   rZ   r   rl   ru   r!   r   r˜   r3   r™   r›   r@   r~   r   r¡   r}   r   r‚   r„   r€   rƒ   r`   r(   r(   r(   r)   Ú<module>   s>     
o$ .B#"$*