
    ij                        U 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m	Z	m
Z
 ddlmZ ddlmZmZ ddlmZ ddlmZ ddlmZ dd	lmZmZmZmZ dd
lmZ ddlmZ ddlmZ ddl m!Z!m"Z"m#Z# ddl m$Z$m%Z% ddl&m'Z' ddl(m)Z)m*Z* ddl+m,Z, ddl-m.Z.m/Z/ ddl&m0Z0  e0jb                  d      Z0e2e!z  Z3ejh                  e5d<   	 e$e%z  Z6ejh                  e5d<   dZ7 ejp                  dejr                        Z: ejp                  dejr                        Z; ejp                  d      Z< ejp                  d      Z= ejp                  d      Z> ejp                  d      Z? ejp                  d      Z@ ejp                  d      ZA ejp                  d       ZBd!ZCi ZDeEe2e!f   e5d"<   i ZFeEe2eEe2e2f   f   e5d#<    G d$ d%      ZG eG       ZHd&e2fd'ZIdfd(e2dz  d&e2fd)ZJd&e2fd*ZK G d+ d,e      ZLd-e2d&e2fd.ZMd/e2d&e2fd0ZN	 dgd1eOe6   e6z  e2z  ez  ePz  dz  d2ePd&e2dz  fd3ZQd4e2d5e2d&e2fd6ZRd1eOe6   e6z  e2z  ez  ePz  dz  d5e2d&e2fd7ZSd8e	ej                  ej                  f   d9eUe2   d&e	e2ej                  f   fd:ZVdhd;eWeXz  d<eWfd=ZYdid;eWeXz  d<eWfd>ZZd?e2d&eWfd@Z[djdAe2dBe2dCe2dDe2d&e2f
dEZ\dFeOe2   e2z  d&eWfdGZ]dHe2dIe2d&ej                  fdJZ_dKej                  d&e2fdLZ`dMe2d&e2fdNZadMe2fdOZbdPeEe2e2f   d&e
e2ge2f   fdQZcdRe2d&eEe2eEe2e2f   f   fdSZddTe3d&e!fdUZedVe6dTe3d&ej                  fdWZfdfdVe6dTe3dXeWdz  d&eOej                     fdYZgeHfdVe6dTe3dZeWdDej                  d&ej                  f
d[Zhd4e2fd\Zid]ej                  e2   d&e2fd^Zkd]ej                  e2   d&e2fd_Zld]ej                  e2   d&e2fd`Zmdae2d&ej                  fdbZndae2d&e2fdcZodde2d&edz  fdeZpy)kz!Utility functions for the engines    N)MutableMappingCallable)Number)splitextjoin)choice)
HTMLParser)escape)urljoinurlparseparse_qs	urlencode)	timedelta)
MarkdownIt)html)XPath
XPathErrorXPathSyntaxError)ElementBase_Elementsettings)USER_AGENTSgsa_useragents_loader)VERSION_TAG)SearxXPathSyntaxExceptionSearxEngineXPathException)loggerutilsXPathSpecTypeElementType)scriptstylez%u([0-9a-fA-F]{4})z%([0-9a-fA-F]{2})z(["\'`])z ([\{\s,])([\$_\w][\$_\w0-9]*)(:)z)void\s+[0-9]+|void\s*\([0-9]+\)|undefinedz(([\[\,:])\s*(\-?)\s*([0-9_]*)\.([0-9_]*)z([\[\,:])\s*(\-?)\s*([0-9_]+)z\s*,\s*([\]\}])z\\(.)z"\bfnrtu_XPATH_CACHE_LANG_TO_LC_CACHEc                       e Zd ZdZy)_NotSetClasszInternal class for this module, do not create instance of this class.
    Replace the None value, allow explicitly pass None as a function argumentN)__name__
__module____qualname____doc__     /root/searxng/searx/utils.pyr'   r'   <   s    Qr-   r'   returnc                  J    dt          dt        d   d    j                         S )zReturn the SearXNG User AgentzSearXNG/ outgoinguseragent_suffix)r   r   stripr,   r-   r.   searxng_useragentr5   D   s*    k]!HZ$89K$L#MNTTVVr-   	os_stringc                 ~    t         d   j                  | xs t        t         d         t        t         d               S )zKReturn a random browser User Agent

    See searx/data/useragents.json
    uaosversions)r9   version)r   formatr   )r6   s    r.   gen_useragentr=   I   s@    
 t##1{401{:./ $  r-   c                  .    t        t                     dz   S )zjReturn a random "Google Go App" User Agent suitable for Google

    See searx/data/gsa_useragents.txt
    z NSTNWV)r   r   r,   r-   r.   gen_gsa_useragentr?   T   s    
 ')*Y66r-   c                       e Zd ZdZd Zdedeeeedz  f      ddfdZdeddfdZ	d	 Z
d
eddfdZdeddfdZdeddfdZd ZdeddfdZy)HTMLTextExtractorz(Internal class to extract text from HTMLc                 J    t        j                  |        g | _        g | _        y N)r	   __init__resulttagsselfs    r.   rD   zHTMLTextExtractor.__init___   s    D!!#!	r-   tagattrsNr/   c                 |    | j                   j                  |       |dk(  r| j                  j                  d       y y )Nbrr1   )rF   appendrE   )rH   rI   rJ   s      r.   handle_starttagz!HTMLTextExtractor.handle_starttagd   s2    		$;KKs# r-   c                     | j                   sy || j                   d   k7  r | j                  j                  d| d       y | j                   j                          y )Nz</>)rF   rE   rM   pop)rH   rI   s     r.   handle_endtagzHTMLTextExtractor.handle_endtagi   sF    yy$))B-KKC5{+		r-   c                 J    | j                    xs | j                   d   t        vS )NrP   )rF   _BLOCKED_TAGSrG   s    r.   is_valid_tagzHTMLTextExtractor.is_valid_tags   s     99}B		"] BBr-   datac                 \    | j                         sy | j                  j                  |       y rC   rV   rE   rM   )rH   rW   s     r.   handle_datazHTMLTextExtractor.handle_datav   s#      "4 r-   namec                     | j                         sy |d   dv rt        |dd  d      }nt        |      }| j                  j                  t	        |             y )Nr   )xX      )rV   intrE   rM   chr)rH   r[   	codepoints      r.   handle_charrefz HTMLTextExtractor.handle_charref{   sN      "7j DHb)ID	I3y>*r-   c                 \    | j                         sy | j                  j                  |       y rC   rY   )rH   r[   s     r.   handle_entityrefz"HTMLTextExtractor.handle_entityref   s%      " 	4 r-   c                 T    dj                  | j                        j                         S )N )r   rE   r4   rG   s    r.   get_textzHTMLTextExtractor.get_text   s    wwt{{#))++r-   messagec                     t        |      rC   )AssertionError)rH   rj   s     r.   errorzHTMLTextExtractor.error   s     W%%r-   )r(   r)   r*   r+   rD   strlisttuplerN   rS   rV   rZ   rd   rf   ri   rm   r,   r-   r.   rA   rA   \   s    2"
$3 $tE#sTz/4J/K $PT $
  C! ! !
+3 +4 +!S !T !,&S &T &r-   rA   html_strc                    | sy| j                  dd      j                  dd      } dj                  | j                               } t               }	 |j	                  |        |j                          |j                         S # t        $ rH t               }|j	                  t        | d             |j                          Y |j                         S w xY w)aR  Extract text from a HTML string

    Args:
        * html_str (str): string HTML

    Returns:
        * str: extracted text

    Examples:
        >>> html_to_text('Example <span id="42">#2</span>')
        'Example #2'

        >>> html_to_text('<style>.span { color: red; }</style><span>Example</span>')
        'Example'

        >>> html_to_text(r'regexp: (?&lt;![a-zA-Z]')
        'regexp: (?<![a-zA-Z]'

        >>> html_to_text(r'<p><b>Lorem ipsum </i>dolor sit amet</p>')
        'Lorem ipsum </i>dolor sit amet</p>'

        >>> html_to_text(r'&#x3e &#x3c &#97')
        '> < a'

    rh   
r1   T)quote)	replacer   splitrA   feedcloserl   r
   ri   )rq   ss     r.   html_to_textr{      s    4 c*224=Hxx()HA	x		
 ::<	  	vhd+,		::<	s   !B ?CCmarkdown_strc                 t    t        dddi      j                  ddg      j                  |       }t        |      S )a-  Extract text from a Markdown string

    Args:
        * markdown_str (str): string Markdown

    Returns:
        * str: extracted text

    Examples:
        >>> markdown_to_text('[example](https://example.com)')
        'example'

        >>> markdown_to_text('## Headline')
        'Headline'
    
commonmarktypographerTreplacementssmartquotes)r   enablerenderr{   )r|   rq   s     r.   markdown_to_textr      sB    $ 	<-!67>>P]?^_ffgst  !!r-   xpath_results
allow_nonec                    t        | t              r+d}| D ]  }|t        |      xs dz   } |j                         S t        | t              rXt        j                  | ddd      }|j                         j                  dd      }dj                  |j                               S t        | t        t        t        f      rt        |       S | |ry| |st        d	      t        d
      )ai  Extract text from a lxml result

    - If ``xpath_results`` is a list of :py:obj:`ElementType` objects, extract
      the text from each result and concatenate the list in a string.

    - If ``xpath_results`` is a :py:obj:`ElementType` object, extract all the
      text node from it ( :py:obj:`lxml.html.tostring`, ``method="text"`` )

    - If ``xpath_results`` is of type :py:obj:`str` or :py:obj:`Number`,
      :py:obj:`bool` the string value is returned.

    - If ``xpath_results`` is of type ``None`` a :py:obj:`ValueError` is raised,
      except ``allow_none`` is ``True`` where ``None`` is returned.

    rh   unicodetextF)encodingmethod	with_tailrs   r1   Nz$extract_text(None, allow_none=False)zunsupported type)
isinstancero   extract_textr4   r!   r   tostringrv   r   rw   rn   r   bool
ValueError)r   r   rE   er   s        r.   r   r      s    & -& 	6A|A4"5F	6||~--MM	
 zz|##D#.xx

%%-#vt!45=!!Z?@@
'
((r-   urlbase_urlc                 @   | j                  d      r,t        |      }dj                  |j                  xs d|       } n| j                  d      rt	        ||       } d| vrt	        ||       } t        |       }|j
                  st        d      |j                  s| dz  } | S )a\  Normalize URL: add protocol, join URL with base_url, add trailing slash if there is no path

    Args:
        * url (str): Relative URL
        * base_url (str): Base URL, it must be an absolute URL.

    Example:
        >>> normalize_url('https://example.com', 'http://example.com/')
        'https://example.com/'
        >>> normalize_url('//example.com', 'http://example.com/')
        'http://example.com/'
        >>> normalize_url('//example.com', 'https://example.com/')
        'https://example.com/'
        >>> normalize_url('/path?a=1', 'https://example.com')
        'https://example.com/path?a=1'
        >>> normalize_url('', 'https://example.com')
        'https://example.com/'
        >>> normalize_url('/test', '/path')
        raise ValueError

    Raises:
        * lxml.etree.ParserError

    Returns:
        * str: normalized URL
    z//z{0}:{1}http/z://zCannot parse url)
startswithr   r<   schemer   netlocr   path)r   r   parsed_search_url
parsed_urls       r.   normalize_urlr      s    6 ~~d$X.077A63G		h$ Ch$#J +,,??s
Jr-   c                 j    | g k(  rt        d      t        |       }|rt        ||      S t        d      )a  Extract and normalize URL from lxml Element

    Example:
        >>> def f(s, search_url):
        >>>    return searx.utils.extract_url(html.fromstring(s), search_url)
        >>> f('<span id="42">https://example.com</span>', 'http://example.com/')
        'https://example.com/'
        >>> f('https://example.com', 'http://example.com/')
        'https://example.com/'
        >>> f('//example.com', 'http://example.com/')
        'http://example.com/'
        >>> f('//example.com', 'https://example.com/')
        'https://example.com/'
        >>> f('/path?a=1', 'https://example.com')
        'https://example.com/path?a=1'
        >>> f('', 'https://example.com')
        raise lxml.etree.ParserError
        >>> searx.utils.extract_url([], 'https://example.com')
        raise ValueError

    Raises:
        * ValueError
        * lxml.etree.ParserError

    Returns:
        * str: normalized URL
    zEmpty url resultsetzURL not found)r   r   r   )r   r   r   s      r.   extract_urlr   2  s=    8 .//
}
%C
S(++
_
%%r-   
dictionary
propertiesc                 >    |D ci c]  }|| v s|| |    c}S c c}w )zExtract a subset of a dict

    Examples:
        >>> dict_subset({'A': 'a', 'B': 'b', 'C': 'c'}, ['A', 'C'])
        {'A': 'a', 'C': 'c'}
        >>> >> dict_subset({'A': 'a', 'B': 'b', 'C': 'c'}, ['A', 'D'])
        {'A': 'a'}
    r,   )r   r   ks      r.   dict_subsetr   W  s'     '1DAOAz!}DDDs   	size	precisionc                 x    g d}t        |      }d}| dkD  r||k  r|dz  }| dz  } | dkD  r||k  rd|| ||   fz  S )zGDetermine the *human readable* value of bytes on 1024 base (1KB=1024B).)zB KBMBGBTBr   i   r_   g      @z%.*f %slenr   r   rz   r]   ps        r.   humanize_bytesr   c  s[    &AAA	A
+!a%	Qf} +!a% 	41...r-   c                 x    g d}t        |      }d}| dkD  r||k  r|dz  }| dz  } | dkD  r||k  rd|| ||   fz  S )z9Determine the *human readable* value of a decimal number.)rh   KMBTr   i  r_   g     @@z%.*f%sr   r   s        r.   humanize_numberr   o  s[     AAA	A
+!a%	Qf} +!a% y$!---r-   
number_strc                 :    | j                         rt        |       S y)z=Convert number_str to int or 0 if number_str is not a number.r   )isdigitra   )r   s    r.   convert_str_to_intr   {  s    :r-   txtbeginenddefaultc                     	 | j                  |      t        |      z   }| || j                  ||       S # t        $ r |cY S w xY w)a  Extract the string between ``begin`` and ``end`` from ``txt``

    :param txt:     String to search in
    :param begin:   First string to be searched for
    :param end:     Second string to be searched for after ``begin``
    :param default: Default value if one of ``begin`` or ``end`` is not
                    found.  Defaults to an empty string.
    :return: The string between the two search-strings ``begin`` and ``end``.
             If at least one of ``begin`` or ``end`` is not found, the value of
             ``default`` is returned.

    Examples:
      >>> extr("abcde", "a", "e")
      "bcd"
      >>> extr("abcde", "a", "z", deafult="nothing")
      "nothing"

    )indexr   r   )r   r   r   r   firsts        r.   extrr     sJ    ,		% 3u:-5399S%011 s   14 AAnumc                 `    t        | t              rt        |       dk  ry| d   } t        |       S )zConvert num to int or 0. num can be either a str or a list.
    If num is a list, the first element is converted to int (or return 0 if the list is empty).
    If num is a str, see convert_str_to_int
    r_   r   )r   ro   r   r   )r   s    r.   int_or_zeror     s0    
 #ts8a<!fc""r-   filename
module_dirc                 F   t        |       d   }t        ||       }t        j                  j	                  ||      }|st        d| d      t        j                  j                  |      }|j                  st        d| d      |j                  j                  |       |S )Nr   zError loading 'z' module)	r   r   	importlibutilspec_from_file_locationr   module_from_specloaderexec_module)r   r   modnamemodpathspecmodules         r.   load_moduler     s    x #G:x(G>>11'7CD?7)8<==^^,,T2F;;?7)8<==KKF#Mr-   objc                 j    t        | t              r| S t        | d      rt        |       S t        |       S )z)Convert obj to its string representation.__str__)r   rn   hasattrrepr)r   s    r.   	to_stringr     s.    #s
sI3x9r-   stringc                 b    t         j                  d |       } t        j                  d |       } | S )u  Python implementation of the unescape javascript function

    https://www.ecma-international.org/ecma-262/6.0/#sec-unescape-string
    https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/unescape

    Examples:
        >>> ecma_unescape('%u5409')
        '吉'
        >>> ecma_unescape('%20')
        ' '
        >>> ecma_unescape('%F3')
        'ó'
    c                 J    t        t        | j                  d      d            S Nr_   r`   rb   ra   groupr   s    r.   <lambda>zecma_unescape.<locals>.<lambda>      c#aggaj"2E.F r-   c                 J    t        t        | j                  d      d            S r   r   r   s    r.   r   zecma_unescape.<locals>.<lambda>  r   r-   )_ECMA_UNESCAPE4_REsub_ECMA_UNESCAPE2_RE)r   s    r.   ecma_unescaper     s/      ##$FOF##$FOFMr-   c                     d}g }| D ]3  }t        |      t        fd|D              r#|j                  |       5 dj                  |      S )zRemoves unicode's "PRIVATE USE CHARACTER"s (PUA_) from a string.

    .. _PUA: https://en.wikipedia.org/wiki/Private_Use_Areas
    ))i   i  )i   i )i   i c              3   D   K   | ]  \  }}|cxk  xr |k  nc   y wrC   r,   ).0abis      r.   	<genexpr>z&remove_pua_from_str.<locals>.<genexpr>  s     4v1qA{{{4s    rh   )ordanyrM   r   )r   
pua_rangesrz   cr   s       @r.   remove_pua_from_strr     sT    
 NJA F444		
 771:r-   replacesc                    | j                         D ci c]  \  }}t        j                  |      | c}}t        j                  dj	                  j                                     dt        ffd}|S c c}}w )N|r   c                 .    j                  fd|       S )Nc                 R    t        j                  | j                  d               S )Nr   )rer
   r   )mreps    r.   r   z<get_string_replaces_function.<locals>.func.<locals>.<lambda>  s    S1771:)>%? r-   )r   )r   patternr   s    r.   funcz*get_string_replaces_function.<locals>.func  s    {{?FFr-   )itemsr   r
   compiler   keysrn   )r   r   vr   r   r   s       @@r.   get_string_replaces_functionr    sa    '/~~'7
8tq!299Q<?
8Cjj#((*-.GG3 G K 9s    A;r[   c                 X    dt         vri S t         d   D ]  }d|vr| |d   k(  s|c S  i S )zDReturn engine configuration from settings.yml of a given engine nameenginesr[   r   )r[   engines     r.   get_engine_from_settingsr    sH      	9% 6&>!M	 Ir-   
xpath_specc                    t        | t              r/t        j                  | d      }|	 t	        |       }|t        | <   |S t        | t              r| S t        d      # t
        $ r%}t        | t        |j                              |d}~ww xY w)a'  Return cached compiled :py:obj:`lxml.etree.XPath` object.

    ``TypeError``:
      Raised when ``xpath_spec`` is neither a :py:obj:`str` nor a
      :py:obj:`lxml.etree.XPath`.

    ``SearxXPathSyntaxException``:
      Raised when there is a syntax error in the *XPath* selector (``str``).
    Nz5xpath_spec must be either a str or a lxml.etree.XPath)	r   rn   r$   getr   r   r   msg	TypeError)r  rE   r   s      r.   	get_xpathr    s     *c"!!*d3>Oz* (.L$*e$
K
LL $ O/
CJGQNOs   A 	B& BBelementc           	          t        |      }	  ||       S # t        $ rJ}dj                  |j                  D cg c]  }t	        |       nc c}w c}      }t        ||      |d}~ww xY w)a  Equivalent of ``element.xpath(xpath_str)`` but compile ``xpath_str`` into
    a :py:obj:`lxml.etree.XPath` object once for all.  The return value of
    ``xpath(..)`` is complex, read `XPath return values`_ for more details.

    .. _XPath return values:
        https://lxml.de/xpathxslt.html#xpath-return-values

    ``TypeError``:
      Raised when ``xpath_spec`` is neither a :py:obj:`str` nor a
      :py:obj:`lxml.etree.XPath`.

    ``SearxXPathSyntaxException``:
      Raised when there is a syntax error in the *XPath* selector (``str``).

    ``SearxEngineXPathException:``
      Raised when the XPath can't be evaluated (masked
      :py:obj:`lxml.etree..XPathError`).
    r1   N)r  r   r   argsrn   r   )r  r  xpathr   r   args         r.   
eval_xpathr    sc    & Z(E@W~ @hh/1A//0'
C8a?@s    	A(A#A

	A##A(min_lenc                     t        | |      }t        |t              st        |d      |&|t	        |      kD  rt        |dt        |      z         |S )zSame as :py:obj:`searx.utils.eval_xpath`, but additionally ensures the
    return value is a :py:obj:`list`.  The minimum length of the list is also
    checked (if ``min_len`` is set).zthe result is not a listzlen(xpath_str) < )r  r   ro   r   r   rn   )r  r  r  rE   s       r.   eval_xpath_listr  5  sU    
 %Wj9Ffd#'
4NOOwV4'
4G#g,4VWWMr-   r   c                     t        | |      }t        |       |cxk  rt        |      k  r||   S  |t        k(  rt        |dt	        |      z   dz         |S )aD  Same as :py:obj:`searx.utils.eval_xpath_list`, but returns item on
    position ``index`` from the list (index starts with ``0``).

    The exceptions known from :py:obj:`searx.utils.eval_xpath` are thrown. If a
    default is specified, this is returned if an element at position ``index``
    could not be determined.
    zindex z
 not found)r  r   _NOTSETr   rn   )r  r  r   r   rE   s        r.   eval_xpath_getindexr  B  s`     Wj1FF|u*s6{*e} +' (
Hs5z4IL4XYYNr-   c                 4   t        |       }d}|j                  dv rL|j                  dk(  r=|j                  r1t	        |j                        j                  dg       }|rd|d   z   }|S |j                  dv rt        d| i      }d	|z   }|S |j                  d
v rD|j                  j                  d      r)|j                  j                  d      r| dz   }|S | dz   }|S |j                  dv rP|j                  j                  d      r5d|j                  v r'|j                  j                  d      }|d   }d|z   }|S |j                  dv rP|j                  j                  d      r5|j                  j                  d      }t        |      dk(  r
|d   }d|z   }|S |j                  dv rr|j                  j                  d      rW|j                  j                  d      }|d   }d}|j                  d      r|dd }d}n|j                  d      rd}d| d| d}|S ) z
    Converts a standard video URL into its embed format. Supported services include Youtube,
    Facebook, Instagram, TikTok, Dailymotion, and Bilibili.
    N)zwww.youtube.comzyoutube.comz/watchr  z'https://www.youtube-nocookie.com/embed/r   )zwww.facebook.comzfacebook.comhrefz@https://www.facebook.com/plugins/video.php?allowfullscreen=true&)zwww.instagram.comzinstagram.comz/p/r   embedz/embed)zwww.tiktok.comz
tiktok.comz/@z/video/r_   zhttps://www.tiktok.com/embed/)zwww.dailymotion.comzdailymotion.com      z(https://www.dailymotion.com/embed/video/)zwww.bilibili.comzbilibili.comavaidBVbvidz(https://player.bilibili.com/player.html?=z(&high_quality=1&autoplay=false&danmaku=0)r   r   r   queryr   r
  r   r   endswithrw   r   )r   r   
iframe_srcvideo_idencoded_href
path_parts	param_keys          r.   get_embeded_stream_urlr+  Z  sT   
 #JJ >>:??V^C^cmcscsJ,,-11#r:BXa[PJ^ Y 
		B	B &#/WZff
T O 
		D	DIcIcdiIj??##C(wJJ G xJF ? 	==OO&&t,(__**95
a=4x?
2 - 
		H	HZ__MgMghqMr__**3/
z?a!!}HChNJ$  
		B	BzGaGabkGl__**3/
a=	t$|HI  &I 7yk8*Ltu 	 r-   matchc                     | j                  d      xs | j                  d      }|t        v rd| S |dk(  rdS |dk(  rdS |S )Nr_   r  \r]   z\u00rs   rh   )r   _JSON_PASSTHROUGH_ESCAPES)r,  _escapes     r.   _j2p_process_escaper1    sc    kk!n.AG // WI  3W 3:T/B HOr-   c                     | j                  d      | j                  d      z   | j                  d      j                  dd      xs dz   dz   | j                  d      j                  dd      xs dz   S )	Nr_   r  r  _rh   0.   r   rv   r,  s    r.   _j2p_decimalr9    sr    A
++a.	;;q>!!#r*1c	3 	 ;;q>!!#r*1c		3r-   c                     | j                  d      | j                  d      z   | j                  d      j                  dd      z   S )Nr_   r  r  r3  rh   r7  r8  s    r.   _j2p_decimal2r;    s7    ;;q>EKKN*U[[^-C-CC-LLLr-   
js_obj_strc                     t        |       }|dk(  rt        d      	 t        j                  |      S # t        j                  $ r'}t        j                  d|       t        d      |d}~ww xY w)zConvert a javascript variable into JSON and then load the value

    It does not deal with all cases, but it is good enough for now.
    chompjs has a better implementation.
    rh   #js_obj_str can't be an empty stringz=Internal error: js_obj_str_to_python creates invalid JSON:
%sz)js_obj_str_to_python creates invalid JSONN)js_obj_str_to_json_strr   jsonloadsJSONDecodeErrorr   debug)r<  rz   r   s      r.   js_obj_str_to_pythonrD    sk     	z*ABw>??Mzz!} MUWXYDE1LMs   2 A,"A''A,c                 p   t        | t              st        d      | dk(  rt        d      d }t        j	                  |       }d}t        |      D ]  \  }}||k(  r
|sd }d||<   n|rm|j                  dt        d            }t        j                  t        |      }|dk(  r|j                  dd	      }|||<   |r|d d dk(  r||dz
     d d
 ||dz
  <   nv||dv r|}d||<   nh|ft        j                  d|      }t        j                  t        |      }t        j                  t        |      }t         j                  d |      }|||<   t#        |      dkD  xr |d
   dk(  } dj%                  |      }t&        j                  d|      }|j                  t        d      d      j)                         }|S )Nzjs_obj_str must be of type strrh   r>  F":r_   'z\"rP   )rF  rH  `nullc                 $    | j                  d      S )Nr_   )r   r8  s    r.   r   z(js_obj_str_to_json_str.<locals>.<lambda>  s    EKKN r-   r   r.  z\1"\2"\3)r   rn   r   _JS_STRING_DELIMITERSrw   	enumeraterv   rb   _JS_STRING_ESCAPE_REr   r1  _JS_VOID_OR_UNDEFINED_RE_JS_DECIMAL_REr9  _JS_DECIMAL2_REr;  _JS_EXTRA_COMA_REr   r   _JS_QUOTE_KEYS_REr4   )r<  	in_stringpartsblackslash_just_beforer   r   rz   s          r.   r?  r?    s   j#&9::R>?? I
 "''
3E"%  9>1	>"8 I E!H 		#s1v&A$(()<a@A
 CIIc5)E!H &!BQ%3,$QU|CR0a!e1#7 I E!H ),,VQ7A""<3A##M15A "%%&BAFAE!H "%Q!!="s9>x 	A
 	k1-A			#a&#$$&AHr-   duration_strc                     | j                         } | sy	 dg| j                  d      z   dd }t        t        |      \  }}}t	        |||      S # t
        t        f$ r Y yw xY w)zParse a time string in format MM:SS or HH:MM:SS and convert it to a `timedelta` object.

    Returns None if the provided string doesn't match any of the formats.
    N00rG  r  )hoursminutesseconds)r4   rw   mapra   r   r   r  )rW  
time_partsrZ  r[  r\  s        r.   parse_duration_stringr_    sw    
  %%'Lf|11#66;
"%c:"6wugwGG	" s   9A A! A!rC   )F)r  )r   )rh   )qr+   r   r   importlib.utilr@  typestypingtcollections.abcr   r   numbersr   os.pathr   r   randomr   html.parserr	   r   r
   urllib.parser   r   r   r   datetimer   markdown_itr   lxml
lxml.etreer   r   r   r   r   searxr   
searx.datar   r   searx.versionr   searx.exceptionsr   r   r   getChildrn   r    	TypeAlias__annotations__r!   rU   r   UNICODEr   r   rL  rS  rO  rP  rQ  rR  rN  r/  r$   dictr%   r'   r  r5   r=   r?   rA   r{   r   ro   r   r   r   r   Anysetr   ra   floatr   r   r   r   r   
ModuleTyper   r   r   r   r  r  r  r  r  r  r+  Matchr1  r9  r;  rD  r?  r_  r,   r-   r.   <module>r|     sQ   ' 
      4  "  "  ? ?  "  : : ,  9 % Q 		! 5[q{{ (? '1Q[[ 1 $RZZ 5rzzB RZZ 4bjjA "

;/ BJJBC %2::&RS GH"**=>BJJ12 !rzz(+ ' !#d3: #/1 4T#s(^+, 1Q Q
 .W3 W
S4Z 3 73 75&
 5&p&3 &3 &R"3 "3 "2 ))${2S86ADH4O)))) 	4Z))X/s /c /c /d"&tK0;>DvMPTTW[[ "&gj "&or "&J	EN155!%%<8 	Ec#h 	ESabeghglglblSm 	E	/u 	/ 	/	.#+ 	.# 	.3 3 c # C # s :	#T#Y_ 	# 	## 3 53C3C 155 S # # * 4S> hucz>R 3 4T#s(^0C+D M- ME M4@ @ @155 @8
[ 
m 
cTXj 
dhijinindo 
" 	  UU	
 UU0; ;|rxx}   # M# M3 MMS MQUU M"Ts Ts Tn 	D0@ r-   