
    ljt              	       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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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mZ d dlZd d
lm Z! d dl"m#Z#m$Z$m%Z% 	 d dl&m&Z&  ejP                  d      Z)i ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2Z*e*jW                         D  ci c]  \  } }|| 
 c}} Z,i d3d d4dd.dd5dd6dd7dd8dd9dd:dd;d!d<d#d=d%d>d0d?d@dAdBdCdDdEdFi dGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdndodpZ-e-jW                         D  ci c]  \  } }|| 
 c}} Z.i Z/da0 G dq drejb                        Z2ds Z3dt Z4du Z5dv Z6dw Z7ddxZ8dy Z9dz Z:d{ Z;d| Z<d} Z=d~ Z>d Z?ddZ@d ZAddZBddZC	 	 ddZD	 	 ddZEddZFddZGddZHddZId ZJd ZKd ZLdeMdeNfdZOddZPddZQd ZRd ZSd ZTg dZUej                  dk\  reUj                  g d       eUD cg c]  \  }} eX|       d eX|        c}}ZY ej                  ddj                  eY       d      Z\d Z]deNfdZ^deNfdZ_y# e'$ r dZ&Y !w xY wc c}} w c c}} w c c}}w )    N)deque)datetime	timedelta)getpass)sha1)EventThread)quote)ElementTree)ZoneInfoZoneInfoNotFoundError)_codes)
BadRequestNotFoundUnauthorized)tqdmplexapimovie   show   season   episode   trailer   comic   person   artist   album	   track
   picture   clip   photo   
photoalbum   playlist   playlistFolder   
collection   *   i  )optimizedVersionuserPlaylistItemtaggenredirectorwriterroleproducercountrychapterreviewlabelmarkermediaProcessingTargetmake   model   aperture   exposure   iso   lens   device   autotag   moodi,  stylei-  formati.  	subformati/  similari1  concerti2  banneri7  posteri8  arti9  guidi:  ratingImagei<  themei=  studioi>  i?  iB  iC  iD  iE  i  i  )networkshowOrdering	clearLogocommonSenseMedia	squareArtplacesharedWidthc                   $    e Zd ZdZddZd Zd Zy)SecretsFilterz! Logging filter to hide secrets. Nc                 *    |xs
 t               | _        y N)setsecrets)selfrn   s     :/DATA/.local/lib/python3.12/site-packages/plexapi/utils.py__init__zSecretsFilter.__init__r   s    '#%    c                 J    | |dk7  r| j                   j                  |       |S N )rn   add)ro   secrets     rp   
add_secretzSecretsFilter.add_secretu   s%    &B,LLV$rr   c                     t        |j                        }t        t        |            D ]?  }t	        ||   t
              s| j                  D ]  }||   j                  |d      ||<    A t        |      |_        y)Nz<hidden>T)	listargsrangelen
isinstancestrrn   replacetuple)ro   record	cleanargsirw   s        rp   filterzSecretsFilter.filterz   sj    %	s9~&A)A,,"llF#,Q<#7#7
#KIaL + ' I&rr   rl   )__name__
__module____qualname____doc__rq   rx   r    rr   rp   rj   rj   o   s    +(
rr   rj   c                 l   t        | dt        | d| j                              }|r| j                   d| n| j                  }t        | dd      r| d}nt        | dd      r| d}|t        v r<t	        d	| j
                   d
| j                   d| dt        |   j
                         | t        |<   | S )z Registry of library types we may come across when parsing XML. This allows us to
        define a few helper functions to dynamically convert the XML into objects. See
        buildItem() below for an example.
    
STREAMTYPETAGTYPE._SESSIONTYPENz.session_HISTORYTYPEz.historyz Ambiguous PlexObject definition z(tag=z, type=z) with )getattrTYPETAGPLEXOBJECTS	Exceptionr   )clsetypeehashs      rp   registerPlexObjectr      s    
 CwsIsxx'HIE$)swwiq swwEsND)'"	nd	+'":3<<.cggYV]^c]d e  +E 2 ; ;<> ? 	?KJrr   c                     t         j                  |       }||S d| v r"| j                  dd      d   } t        | |      S t         j                  |      S )z Return the PlexObject class for the specified ehash. This recursively looks up the class
        with the highest specificity, falling back to the default class if not found.
    r   r   r   )default)r   getrsplitgetPlexObject)r   r   r   s      rp   r   r      sT     //%
 C


e|S!$Q'UG44??7##rr   c                     ||S | t         k(  r|dv ry|dv ryt        |      | t        t        fv r		  | |      S  | |      S # t        $ r t        d      cY S w xY w)aB   Cast the specified value to the specified type (returned by func). Currently this
        only support str, int, float, bool. Should be extended if needed.

        Parameters:
            func (func): Callback function to used cast to type (int, bool, float).
            value (any): value to be cast and returned.
    )r   T1trueT)r   F0falseFnan)bool
ValueErrorintfloat)funcvalues     rp   castr      sz     }t|**,,U|	 ; ;  	 <	 s   A AAc           	          | syg }t        | d       D ]1  }t        | |         }|j                  | dt        |d              3 ddj	                  |       S )z Returns a query string (uses for HTTP URLs) where only the value is URL encoded.
        Example return value: '?genre=action&type=1337'.

        Parameters:
            args (dict): Arguments to include in query string.
    ru   c                 "    | j                         S rl   lowerxs    rp   <lambda>zjoinArgs.<locals>.<lambda>   s
    !'')rr   )key=)safe?&)sortedr   appendr
   join)r{   arglistr   r   s       rp   joinArgsr      sf     Gd 34DI#ae" 5678 5 sxx !""rr   c                 4    | d   j                         | dd  z   S )Nr   r   r   ss    rp   
lowerFirstr      s    Q4::<!AB%rr   c                 r   	 |j                  |d      }|d   }t        |      dk(  r|d   nd}t        | t              r| |   }nZt        | t              r| t        |         }n;t        | t              r| t        |         }nt        | t              rt        | |      }|rt        |||      S S #  |cY S xY w)ag   Returns the value at the specified attrstr location within a nested tree of
        dicts, lists, tuples, functions, classes, etc. The lookup is done recursively
        for each key in attrstr (split by by the delimiter) This function is heavily
        influenced by the lookups used in Django templates.

        Parameters:
            obj (any): Object to start the lookup in (dict, obj, list, tuple, etc).
            attrstr (str): String to lookup (ex: 'foo.bar.baz.value')
            default (any): Default value to return if not found.
            delim (str): Delimiter separating keys in attrstr.
    r   r   r   N)
splitr}   r~   dictrz   r   r   objectr   rget)objattrstrr   delimpartsattrr   s          rp   r   r      s    eQ'Qx!%jAo%(4c4 IET"D	NEU#D	NEV$C&Ew77s   B+B0 .B0 0B6c                     t        |       } 	 t        |    S # t        $ r9 | t        D cg c]  }t        |       nc c}w c}v r| cY S t	        d|        dw xY w)z Returns the integer value of the library string type.

        Parameters:
            libtype (str): LibType to lookup (See :data:`~plexapi.utils.SEARCHTYPES`)

        Raises:
            :exc:`~plexapi.exceptions.NotFound`: Unknown libtype
    Unknown libtype: N)r   SEARCHTYPESKeyErrorREVERSESEARCHTYPESr   )libtypeks     rp   
searchTyper      sg     'lG@7## @'9:'9!s1v'9::N*7)454?@    A;AAc                     	 t         t        |          S # t        t        f$ r | t        v r| cY S t        d|        dw xY w)z Returns the string value of the library type.

        Parameters:
            libtype (int): Integer value of the library type.

        Raises:
            :exc:`~plexapi.exceptions.NotFound`: Unknown libtype
    r   N)r   r   r   r   r   r   )r   s    rp   reverseSearchTyper     sO    @!#g,//j! @k!N*7)454?@    ??c                     t        |       } 	 t        |    S # t        $ r9 | t        D cg c]  }t        |       nc c}w c}v r| cY S t	        d|        dw xY w)z Returns the integer value of the library tag type.

        Parameters:
            tag (str): Tag to lookup (See :data:`~plexapi.utils.TAGTYPES`)

        Raises:
            :exc:`~plexapi.exceptions.NotFound`: Unknown tag
    Unknown tag: N)r   TAGTYPESr   REVERSETAGTYPESr   )r9   r   s     rp   tagTyper     s_     c(C8} 8?3?a3q6?33Jse,-478r   c                     	 t         t        |          S # t        t        f$ r | t        v r| cY S t        d|        dw xY w)z Returns the string value of the library tag type.

        Parameters:
            tag (int): Integer value of the library tag type.

        Raises:
            :exc:`~plexapi.exceptions.NotFound`: Unknown tag
    r   N)r   r   r   r   r   r   )r9   s    rp   reverseTagTyper   $  sJ    8s3x((j! 8(?Jse,-478r   c           
         g g }}t               }|D ]g  }||t        |      gz  }|j                  d       |j                  t        | |t	        |                   d|d   _        |d   j                          i |j                         s9t        d |D              rn&t        j                  d       |j                         s9|D cg c]  }||	 c}S c c}w )aO   Returns the result of <callback> for each set of `*args` in listargs. Each call
        to <callback> is called concurrently in their own separate threads.

        Parameters:
            callback (func): Callback function to apply to each set of `*args`.
            listargs (list): List of lists; `*args` to pass each thread.
    N)job_is_done_event)targetr{   kwargsTc              3   >   K   | ]  }|j                            y wrl   )is_alive).0ts     rp   	<genexpr>zthreaded.<locals>.<genexpr>F  s     1A1::<s   g?)r   r}   r   r	   r   daemonstartis_setalltimesleep)callbacklistargsthreadsresultsr   r{   rs          rp   threadedr   5  s     2WG#g,''tvXDXiAjkl!   &&(111

4  &&(
 0w!!-Aw000s   CCc                 Z   | | du r
d}|at        S | du s*t        |       j                         j                         dk(  r4t        j                         j                         j                  }|at        S t        |       j                         }	 t        t        |j                               }|r,t        j                         j                         j                  nd}|at        S # t        $ r> 	 t        |      }n'# t        $ r d}t        j                  d|        Y nw xY wY |at        S w xY w)a   Sets the timezone to use when converting values with :func:`toDatetime`.

        Parameters:
            value (bool, str):
                - ``False`` or ``None`` to disable timezone (default).
                - ``True`` or ``"local"`` to use the local timezone.
                - A valid IANA timezone (e.g. ``UTC`` or ``America/New_York``).

        Returns:
            datetime.tzinfo: Resolved timezone object or ``None`` if disabled or invalid.
    NFTlocalz2Failed to set timezone to "%s", defaulting to None)r   stripr   r   now
astimezonetzinfor   r   r   r   r   logwarningDATETIME_TIMEZONE)r   r   setting
is_enableds       rp   setDatetimeTimezoner   M  s    }& % 
$#e***,224?**,33   e*""$		YdGMMO4J;EX\\^..0774F   	YY!'*( YPRWXY 	Ys7   AC# #	D*-C98D*9!DD*DD*)D*c                    	 t        |       } 	 |rt	        j
                  | |      S t	        j
                  |       S # t        $ r t        j                  d|        Y yw xY w# t        t        t        f$ rt 	 |r&t	        j
                  d|      t        |       z   cY S t	        j
                  d      t        |       z   cY S # t        $ r t        j                  d|        Y Y yw xY ww xY w)zD Helper function to parse a timestamp value into a datetime object. zAFailed to parse "%s" to datetime as timestamp, defaulting to NoneN)tzr   )secondszQFailed to parse "%s" to datetime as timestamp (out-of-bounds), defaulting to None)	r   r   r   infor   fromtimestampOSErrorOverflowErrorr   )r   r   s     rp   _parseTimestampr  t  s    E
))%F;;%%e,,  TV[\ ]J/ 	--aF;iPU>VVV))!,y/GGG 	HHhjop	sO   < A! A! AA!C)6%CC)!C?C)C%!C)$C%%C)c                    | bt         }|rN	 t        j                  | |      }|j                  |r|j	                  |      S |S |r|j                  |      S |S t        | |      S | S # t        $ r t        j                  d| |       Y yw xY w)z Returns a datetime object from the specified value.

        Parameters:
            value (str): value to return as a datetime
            format (str): Format to pass strftime (optional; if value is a str).
    N)r   zCFailed to parse "%s" to datetime as format "%s", defaulting to None)
r   r   strptimer   r   r   r   r   r  r  )r   rW   r   dts       rp   
toDatetimer    s     "	&&uf599(4:2==0BB8>2::V:4FBF
 #5&11L  ^`egmns#   4A' A' A' A' ' B
	B
c           	         t        |       } | dk  rdt        t        |             z   S t        | d      \  }}t        |d      \  }}t        |d      \  }}t        |d      \  }}|dk(  rdn| d|dkD  rd	nd d
|dd|dd|dd|dz   S )z Returns human readable time duration [D day[s], ]HH:MM:SS.UUU from milliseconds.

        Parameters:
            milliseconds (str, int): time duration in milliseconds.
    r   -i  <      ru   z dayr   r   , 02d:r   03d)r   millisecondToHumanstrabsdivmod)millisecondssecsmsminshoursdayss         rp   r  r    s     |$La*3|+<===lD)HD"b!JD$r"KE4#KD%!)BD6TAXc2-Fb!IPUVY{Z[\`ad[eefgklofppqrtuxqyMzzzrr   c                     | xs d} |xs t         }| j                  |      D cg c]  }|dk7  s	 ||       c}S c c}w )a$   Returns a list of strings from the specified value.

        Parameters:
            value (str): comma delimited string to convert to list.
            itemcast (func): Function to cast each list item to (default str).
            delim (str): string delimiter (optional; default ',').
    ru   )r   r   )r   itemcastr   items       rp   toListr     sC     KRE3H',{{5'9H'9tTRZHTN'9HHHs   
<
<c                     dt         j                   t         j                   t        j                  d|       j                  dd      j                         }dj                  fd|D              }|S )Nz-_.()[] NFKDASCIIignoreru   c              3   .   K   | ]  }|v r|n  y wrl   r   )r   cr   	whitelists     rp   r   z cleanFilename.<locals>.<genexpr>  s     ZIYAANq?IYs   )stringascii_lettersdigitsunicodedata	normalizeencodedecoder   )filenamer   cleaned_filenamer'  s    ` @rp   cleanFilenamer1    sc    6//0@I",,VX>EEgxX__awwZIYZZrr   c           
         i }| j                         D ]  }d}|j                         D ]^  }	|j                  r|j                  }|	j                  s(d|	j                   d|	j                  j                          d|j                   }` |sy|C|j                         }
d|j                  d    d|
 dt        t        j                                }| j                  |||||      }t        || j                  |      }||d	|d
<    |S )a   Helper to download a bif image or thumb.url from plex.server.sessions.

       Parameters:
           filename (str): default to None,
           height (int): Height of the image.
           width (int): width of the image.
           opacity (int): Opacity of the resulting image (possibly deprecated).
           saturation (int): Saturating of the resulting image.

       Returns:
            {'hellowlol': {'filepath': '<filepath>', 'url': 'http://<url>'},
            {'<username>': {filepath, url}}, ...
    Nz/library/parts/z	/indexes//session_transcode_r   _)r/  )filepathurlusername)sessions	iterPartsthumbindexesidr   
viewOffset_prettyfilename	usernamesr   r   transcodeImagedownload_token)serverr/  heightwidthopacity
saturationr  mediar7  part
prettynamer6  s               rp   downloadSessionImagesrL    s    D"OO%D{{kk||'y	$,,:L:L:N9OqQVQaQaPbc	 &
 "224
/0B/C1ZLPQRUVZV_V_VaRbQcd''VUGZPCV]]XFH,4SAD # Krr   c	                    |xs t        j                         }d|i}	|j                  | |	d      }
|
j                  dvrt	        j                  |
j                        d   }|
j
                  j                  dd      }d|
j                   d	| d
|
j                   d| }|
j                  dk(  rt        |      |
j                  dk(  rt        |      t        |      |xs t        j                         }t        j                  |d       |sV|
j                  j                  d      r;t        j                   d|
j                  j                  d            }|d   r|d   nd}t        j"                  j%                  |      }t        j"                  j'                  ||      }t        j"                  j)                  |      d   }|s8|
j                  j                  d      }|rd|v r||j+                  d      d   z  }|rt,        j/                  d|       |S t,        j1                  d|       |r:t2        r4t5        |
j                  j                  dd            }t3        dd||      }t7        |d      5 }|
j9                  |      D ]7  }|j;                  |       |st2        sj=                  t?        |             9 	 ddd       |rt2        rjA                          |jC                  d      r4|r2tE        jF                  |d      5 }|jI                  |       ddd       |S |S # 1 sw Y   hxY w# 1 sw Y   |S xY w)a   Helper to download a thumb, videofile or other media item. Returns the local
        path to the downloaded file.

       Parameters:
            url (str): URL where the content be reached.
            token (str): Plex auth token to include in headers.
            filename (str): Filename of the downloaded file, default None.
            savepath (str): Defaults to current working dir.
            chunksize (int): What chunksize read/write at the time.
            mocked (bool): Helper to do everything except write the file.
            unpack (bool): Unpack the zip file.
            showstatus(bool): Display a progressbar.

        Example:
            >>> download(a_episode.getStreamURL(), a_episode.location)
            /path/to/file
    zX-Plex-TokenT)headersstream)rF   rH   rN   r   
 (z) z; i  i  )exist_okzContent-Dispositionzfilename=\"(.+)\"Nr   zcontent-typeimager3  r   zMocked download %szDownloading: %szcontent-lengthB)unit
unit_scaletotaldescwb)
chunk_sizezipr   )%requestsSessionr   status_codecodestextr   r7  r   r   r   osgetcwdmakedirsrN  refindallpathbasenamer   splitextr   r   debugr  r   r   openiter_contentwriteupdater}   closeendswithzipfileZipFile
extractall)r7  tokenr/  savepathsession	chunksizeunpackmocked
showstatusrN  responsecodenameerrtextmessagefullpath	extensioncontenttyperX  barhandlechunks                        rp   rB  rB    s   ( +))+Gu%G{{3{=H?299X11215--''c2h**+2hZr(,,q	R3&w''!!S(7##W%% &299;HKK4( ((,,-BC::2H4D4D4H4HI^4_`"*1+8A;4ww)Hww||Hh/H  *2.I&&**>:7k1))#.q11H 		&1 HH)dH$$(()91=>EI	h	**i*@ELLd

3u:& A 
 d		F__Xs+vh' , O8O 
	 , Os$   8)L-"L-)L-L9-L69Mc                    ddl m} ddlm} | rN| j                  rB| j
                  r6t        d| j                   d        || j                  | j
                        S |j                  d      }|j                  d      }|r|rt        d| d        |||      S |j                  d      }|rt        d	        ||
      S t        d      }t        d      }t        d| d        |||      S )aK   Helper function tries to get a MyPlex Account instance by checking
        the the following locations for a username and password. This is
        useful to create user-friendly command line tools.
        1. command-line options (opts).
        2. environment variables and config.ini
        3. Prompt on the command line.
    r   )CONFIG)MyPlexAccountzAuthenticating with Plex.tv as z..zauth.myplex_usernamezauth.myplex_passwordzauth.server_tokenz&Authenticating with Plex.tv with tokenrt  zWhat is your plex.tv username: zWhat is your plex.tv password: )
r   r  plexapi.myplexr  r8  passwordprintr   inputr   )optsr  r  config_usernameconfig_passwordconfig_tokenr8  r  s           rp   getMyPlexAccountr  6  s     ,$--/bABT]]DMM::jj!78Ojj!78O?//@CD_o>>::12L67<0067H89H	+H:R
898,,rr   c                 $   ddl m} | st               }d|i} t        d|        nd| vrt	        d      | d   } ||       }|j                  |       |j                  |j                         |j                          |j                  |      S )	a   Helper function to create a new MyPlexDevice. Returns a new MyPlexDevice instance.

        Parameters:
            headers (dict): Provide the X-Plex- headers for the new device.
                A unique X-Plex-Client-Identifier is required or one will be generated if not provided.
            account (MyPlexAccount): The Plex account to create the device on.
            timeout (int): Timeout in seconds to wait for device login.
    r   )MyPlexPinLoginX-Plex-Client-Identifier1No X-Plex-Client-Identifier provided, generated: 0The X-Plex-Client-Identifier header is required.)rN  timeout)clientId)
r  r  generateUUIDr  r   runlinkpinwaitForLoginrQ   )rN  accountr  r  client_identifierclientIdentifierpinlogins          rp   createMyPlexDevicer  U  s     .(N-/@AABSATUV	#7	2KLL9:g.HLLL!LL>>#3>44rr   c                 n   ddl m}m} | st               }d|i} t	        d|        nd| vrt        d       || d      }|j                  |       t	        d	|j                  |
              |j                          |j                  rt	        d        ||j                        S t	        d       y)a   Helper function for Plex OAuth login. Returns a new MyPlexAccount instance.

        Parameters:
            headers (dict): Provide the X-Plex- headers for the new device.
                A unique X-Plex-Client-Identifier is required or one will be generated if not provided.
            forwardUrl (str, optional): The url to redirect the client to after login.
            timeout (int, optional): Timeout in seconds to wait for user login. Default 120 seconds.
    r   )r  r  r  r  r  T)rN  oauthr  $Login to Plex at the following url:

forwardUrlzLogin successful!r  zLogin failed.N)
r  r  r  r  r  r   r  oauthUrlr  rt  )rN  r  r  r  r  r  r  s          rp   	plexOAuthr  q  s     =(N-/@AABSATUV	#7	2KLLgT:HLLL!	1(2C2Cz2C2Z1[
\]~~!"8>>22orr   c                    ddl m}m} | st               }d|i} t	        d|        nd| vrt        d       || d||      }|d   r|d   s|j                  d	
       t	        d       |j                  |       t	        d|j                  |              |j                          |j                  rt	        d        ||j                        S t	        d       y)a(   Helper function for Plex JWT authentication using Plex OAuth. Returns a new MyPlexAccount instance.

        Parameters:
            headers (dict, optional): Provide the X-Plex- headers for the new device.
                A unique X-Plex-Client-Identifier is required or one will be generated if not provided.
            forwardUrl (str, optional): The url to redirect the client to after login.
            timeout (int, optional): Timeout in seconds to wait for user login. Default 120 seconds.
            keypair (tuple, optional): A tuple of the ED25519 (privateKey, publicKey) to use for signing the JWT.
                If not provided, a new keypair will be generated and saved to 'private.key' and 'public.key'.
            scopes (list[str], optional): List of scopes to request in the JWT.
    r   )r  MyPlexJWTLoginr  r  r  T)rN  r  keypairscopesr   )zprivate.keyz
public.key)keyfileszJGenerated new ED25519 keypair and saved to "private.key" and "public.key".r  r  r  zJWT authentication successful!r  zJWT authentication failed.N)r  r  r  r  r  r   generateKeypairr  r  r  jwtToken)	rN  r  r  r  r  r  r  r  jwtlogins	            rp   plexJWTAuthr    s     =(N-/@AABSATUV	#7	2KLLgT7SYZH1:WQZ  *G HZ[LLL!	1(2C2Cz2C2Z1[
\]./8#4#455*+rr   c                    t        |      dk(  r|d   S t                t        |      D ]5  \  }}t        |      r ||      nt	        ||      }t        d| d|        7 t                	 	 t        |  d      t        fddD              r't        t        d j                  d             }||   S |t                 S # t        t        f$ r Y nw xY wn)	zm Command line helper to display a list of choices, asking the
        user to choose one of the options.
    r   r   z  z: c              3   &   K   | ]  }|v  
 y wrl   r   )r   r   inps     rp   r   zchoose.<locals>.<genexpr>  s     6%518%5s   )r  z::r  c                 X    | j                         rt        | j                               S d S rl   )r   r   r   s    rp   r   zchoose.<locals>.<lambda>  s    QWWY3qwwy>+PD+Prr   r  )r}   r  	enumeratecallabler   r  anyslicemapr   r   r   
IndexError)msgitemsr   indexr   nameidxr  s          @rp   chooser    s    
 5zQQx	Ge$q"4.tAwga.>5'D6"# % 
G
		3%r
#C6%566S!PRUR[R[\_R`abSz!SX&J' 		 s   .AC 7C CCc                     g }| j                         D ]<  }|j                  |j                  |j                  g}||v r|j                  c S ||z  }> t	        d| ddj                  |       d      )z] Return the full agent identifier from a short identifier, name, or confirm full identifier. zCould not find "z" in agents list (r  ))agents
identifiershortIdentifierr  r   r   )sectionagentr  agidentifierss        rp   getAgentIdentifierr    sw    Fnn}}b&8&8"''BK== +	 
 &ug-@6AR@SSTU
VVrr   c                 h    t        j                  | j                  d            j                  d      S )Nutf-8)base64	b64encoder-  r.  )ra  s    rp   	base64strr    s'    DKK0188AArr   datareturnc                 h    t        j                  |       j                  d      j                  d      S )N   =r  )r  urlsafe_b64encoderstripr.  )r  s    rp   base64urlEncoder    s)    ##D)006==gFFrr   c                       fd}|S )Nc                 H     t        j                          fd       }|S )zThis is a decorator which can be used to mark functions
        as deprecated. It will result in a warning being emitted
        when the function is used.c                      dj                    d d}t        j                  |t               t        j                  |        | i |S )Nz'Call to deprecated function or method "z", r   )category
stacklevel)r   warningswarnDeprecationWarningr   r   )r{   r   r  r   r~  r  s      rp   wrapperz.deprecated.<locals>.decorator.<locals>.wrapper  sI    ;DMM?#gYVWXCMM#(:zRKK(((rr   )	functoolswraps)r   r  r~  r  s   ` rp   	decoratorzdeprecated.<locals>.decorator  s'     
		) 
	)
 rr   r   )r~  r  r  s   `` rp   
deprecatedr    s    
 rr   c              #      K   t        | g      }|rC|j                         }||j                  |k(  r| |j                  t	        |             |rByyw)z} Iterate through an XML tree using a breadth-first search.
        If tag is specified, only return nodes with that tag.
    N)r   popleftr9   extendrz   )rootr9   queuenodes       rp   
iterXMLBFSr    sJ      4&ME
}};$((c/JT$Z 	 s   AAAc                 8    d }t        j                  | fd|i|S )z Convert an object to a JSON string.

        Parameters:
            obj (object): The object to convert.
            **kwargs (dict): Keyword arguments to pass to ``json.dumps()``.
    c                     t        | t              r| j                         S | j                  j	                         D ci c]  \  }}|j                  d      r|| c}}S c c}}w )Nr5  )r~   r   	isoformat__dict__r  
startswith)r   r   vs      rp   	serializeztoJson.<locals>.serialize  sR    c8$==?"!$!3!3!5O!5AQ\\#=N1!5OOOs   A!A!r   )jsondumps)r   r   r  s      rp   toJsonr    s#    P ::c79777rr   c                     t        | t              r| S t        | d      r| j                         S t	        | d      5 }|j                         cd d d        S # 1 sw Y   y xY w)Nreadrb)r~   byteshasattrr  rk  )filefs     rp   
openOrReadr    sH    $tVyy{	dD	Qvvx 
		s   AAc                 R    t        | j                  d            j                         S )z! Return the SHA1 hash of a guid. r  )r   r-  	hexdigest)r^   s    rp   sha1hashr    s    G$%//11rr   ))r   r#   )r)   r+   )r/      )      )      )i  i  )i  i  i   ))i i )i i )i i )i i )i i )i i )i i )i i )i	 i	 )i
 i
 )i i )i i )i i )i i )i i )i i r  [ru   ]c                 .    t         j                  d|       S rt   )_illegal_XML_resubr   s    rp   cleanXMLStringr  @  s    r1%%rr   r   c                 &   | j                         sy	 t        j                  | j                  d            S # t        j                  $ rF t        |       j                  d      }|j                         rt        j                  |      cY S dcY S w xY w)z7 Parse an XML string and return an ElementTree object. Nr  )r   r   
fromstringr-  
ParseErrorr  )r   	cleaned_ss     rp   parseXMLStringr  D  sy    779P%%ahhw&788!! P"1%,,W5	4=OO4E{%%i0O4OPs   #7 ABBBc                  <    t        t        j                               S rl   )r   uuiduuid4r   rr   rp   r  r  O  s    tzz|rr   )Nr   rl   )N,)r5  )N   r  d   r  )NNNi   FFF)NNr'   )Nx   )NNr  )NNN)r   )`r  r  r  loggingrb  re  r(  sysr   r+  r  r  rq  collectionsr   r   r   r   hashlibr   	threadingr   r	   urllib.parser
   	xml.etreer   zoneinfor   r   r]  requests.status_codesr   r`  plexapi.exceptionsr   r   r   r   ImportError	getLoggerr   r   r  r   r   r   r   r   Filterrj   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r   r1  rL  rB  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  _illegal_XML_characters
maxunicoder  chr_illegal_XML_rangescompiler   r  r  r  r  )r   r  lowhighs   0000rp   <module>r.     s       	 	  
       (   #  ! 4  1 A A g	"Q
A a q	
 q Q a a Q R r B R "   b!" "#$ '* (3'8'8':;':tq!ad':; *	1*Q* !* 	*
 a* A* * q* q* b* R* b* R* C* S*  !*" #*$ 
3%*& C'*( c)** s+*, C-*. S/*0 c1*2 3*4 s5*6 s7*8 c9*: c;*< 
3=*> C?*@ 3A*B SC*D cE*F S*V %-NN$45$4DAq1a4$45   GNN *$
$2#  >@$@"8$8"10$N*2{ 
I DG25B PT49L^->58<#,L6WBG% GC G	!82  >>W""	
, /.d 	Cz3t9+.  "**"''*=">!?qAB&Pc Pc e  D6 <\ 6fs$    J %J+=J1J7J('J(