
    g>                     h   d dl Z d dlmZ d dlmZ d dlmZ d dlZd dlm	Z	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 d d
lmZ d dlmZmZmZ d dlmZmZmZ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* d dl+m,Z- d dlm.Z/ d dlm0Z1 d dlm2Z3 d dlm4Z5 d dlm6Z7 d dlm8Z9  G d de      Z: G d de      Z; G d de      Z<ejz                   G d d e             Z> G d! d"e      Z? G d# d$e      Z@ G d% d&e      ZA G d' d(e      ZBejz                   G d) d*e             ZC G d+ d,e      ZDy)-    N)cached_property)	urlencode)ElementTree)BASE_HEADERSCONFIGTIMEOUTlog	logfilter)utils)AlertListener)
PlexObject)
PlexClient)
Collection)
BadRequestNotFoundUnauthorized)HubLibraryPathFile)
Conversion	Optimized)Playlist)	PlayQueue)Settings)
deprecated)_codes)audio)
collection)media)photo)playlist)videoc                       e Zd ZdZdZdA fd	Zd Zd Zd Ze	d        Z
e	d        Zd	 Zd
 Zd Zd Zed        ZdBdZdCdZdDdZd Zd Zd Zd Zd Zd ZdEdZdBdZd Zd Zd Z	 	 dFdZ 	 	 dGdZ!d Z"dHdZ#dHd Z$d! Z%d" Z& e'd#      dId$       Z(dId%Z)d& Z*d' Z+d( Z,dJd)Z-dAd*Z.d+ Z/dBd,Z0 e'd-      d.        Z1dBd/Z2d0 Z3dAd1Z4dKd2Z5d3 Z6d4 Z7d5 Z8dDd6Z9	 	 dLd7Z:dBd8Z;d9 Z<d: Z=d; Z>dMd<Z?dBd=Z@d> ZAdDd?ZBdDd@ZC xZDS )N
PlexServera   This is the main entry point to interacting with a Plex server. It allows you to
        list connected clients, browse your library sections and perform actions such as
        emptying trash. If you do not know the auth token required to access your Plex
        server, or simply want to access your server with your username and password, you
        can also create an PlexServer instance from :class:`~plexapi.myplex.MyPlexAccount`.

        Parameters:
            baseurl (str): Base url for to access the Plex Media Server (default: 'http://localhost:32400').
            token (str): Required Plex authentication token to access the server.
            session (requests.Session, optional): Use your own session object if you want to
                cache the http responses from the server.
            timeout (int, optional): Timeout in seconds on initial connection to the server
                (default config.TIMEOUT).

        Attributes:
            allowCameraUpload (bool): True if server allows camera upload.
            allowChannelAccess (bool): True if server allows channel access (iTunes?).
            allowMediaDeletion (bool): True is server allows media to be deleted.
            allowSharing (bool): True is server allows sharing.
            allowSync (bool): True is server allows sync.
            backgroundProcessing (bool): Unknown
            certificate (bool): True if server has an HTTPS certificate.
            companionProxy (bool): Unknown
            diagnostics (bool): Unknown
            eventStream (bool): Unknown
            friendlyName (str): Human friendly name for this server.
            hubSearch (bool): True if `Hub Search <https://www.plex.tv/blog
                /seek-plex-shall-find-leveling-web-app/>`_ is enabled. I believe this
                is enabled for everyone
            machineIdentifier (str): Unique ID for this server (looks like an md5).
            multiuser (bool): True if `multiusers <https://support.plex.tv/hc/en-us/articles
                /200250367-Multi-User-Support>`_ are enabled.
            myPlex (bool): Unknown (True if logged into myPlex?).
            myPlexMappingState (str): Unknown (ex: mapped).
            myPlexSigninState (str): Unknown (ex: ok).
            myPlexSubscription (bool): True if you have a myPlex subscription.
            myPlexUsername (str): Email address if signed into myPlex (user@example.com)
            ownerFeatures (list): List of features allowed by the server owner. This may be based
                on your PlexPass subscription. Features include: camera_upload, cloudsync,
                content_filter, dvr, hardware_transcoding, home, lyrics, music_videos, pass,
                photo_autotags, premium_music_metadata, session_bandwidth_restrictions, sync,
                trailers, webhooks (and maybe more).
            photoAutoTag (bool): True if photo `auto-tagging <https://support.plex.tv/hc/en-us
                /articles/234976627-Auto-Tagging-of-Photos>`_ is enabled.
            platform (str): Platform the server is hosted on (ex: Linux)
            platformVersion (str): Platform version (ex: '6.1 (Build 7601)', '4.4.0-59-generic').
            pluginHost (bool): Unknown
            readOnlyLibraries (bool): Unknown
            requestParametersInCookie (bool): Unknown
            streamingBrainVersion (bool): Current `Streaming Brain <https://www.plex.tv/blog
                /mcstreamy-brain-take-world-two-easy-steps/>`_ version.
            sync (bool): True if `syncing to a device <https://support.plex.tv/hc/en-us/articles
                /201053678-Sync-Media-to-a-Device>`_ is enabled.
            transcoderActiveVideoSessions (int): Number of active video transcoding sessions.
            transcoderAudio (bool): True if audio transcoding audio is available.
            transcoderLyrics (bool): True if audio transcoding lyrics is available.
            transcoderPhoto (bool): True if audio transcoding photos is available.
            transcoderSubtitles (bool): True if audio transcoding subtitles is available.
            transcoderVideo (bool): True if audio transcoding video is available.
            transcoderVideoBitrates (bool): List of video bitrates.
            transcoderVideoQualities (bool): List of video qualities.
            transcoderVideoResolutions (bool): List of video resolutions.
            updatedAt (int): Datetime the server was updated.
            updater (bool): Unknown
            version (str): Current Plex version (ex: 1.3.2.3112-1751929)
            voiceSearch (bool): True if voice search is enabled. (is this Google Voice search?)
            _baseurl (str): HTTP address of the client.
            _token (str): Token used to access this client.
            _session (obj): Requests session object used to access this client.
    /c                 L   |xs t        j                  dd      | _        | j                  j                  d      | _        t	        j
                  |xs t        j                  d            | _        t        j                  dd      j                         dk(  | _        |xs t        j                         | _        |xs t        | _        d | _        d | _        d | _        | j#                  | j$                  | j                        }t&        t(        | W  | || j$                         y )	Nzauth.server_baseurlzhttp://localhost:32400r&   zauth.server_tokenzlog.show_secrets true)timeout)r   get_baseurlrstripr
   
add_secret_tokenlower_showSecretsrequestsSession_sessionr   _timeout_myPlexAccount_systemAccounts_systemDevicesquerykeysuperr%   __init__)selfbaseurltokensessionr*   data	__class__s         #/opt/Tautulli/lib/plexapi/server.pyr<   zPlexServer.__init__j   s    ^6::.CE]#^,,S1**5+SFJJ?R4ST"JJ'92>DDF&P58#3#3#5*7"#"zz$((DMMz:j$(tTXX>    c                    || _         t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _	        t        j                  t        |j                  j                  d            | _
        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        t        j                  |j                  j                  d	            | _        t        j                  t        |j                  j                  d
            | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        t        j                  t>        |j                  j                  d            | _         t        j                  t        |j                  j                  d            | _!        |j                  j                  d      | _"        t        j                  t        |j                  j                  d            | _#        t?        |j                  j                  dd            | _$        t        j                  t        |j                  j                  d            | _%        t        j                  t        |j                  j                  d             | _&        t        j                  t        |j                  j                  d!            | _'        t        j                  t        |j                  j                  d"            | _(        t        j                  t        |j                  j                  d#            | _)        t        j                  |j                  j                  d$            | _*        t        j                  |j                  j                  d%            | _+        t        j                  |j                  j                  d&            | _,        t        jZ                  |j                  j                  d'            | _.        t        j                  t        |j                  j                  d(            | _/        |j                  j                  d)      | _0        t        j                  t        |j                  j                  d*            | _1        y+),z/ Load attribute values from Plex XML response. allowCameraUploadallowChannelAccessallowMediaDeletionallowSharing	allowSyncbackgroundProcessingcertificatecompanionProxydiagnosticseventStreamfriendlyName	hubSearchmachineIdentifier	multiusermyPlexmyPlexMappingStatemyPlexSigninStatemyPlexSubscriptionmyPlexUsernameownerFeaturesphotoAutoTagplatformplatformVersion
pluginHostreadOnlyLibrariesrequestParametersInCookiestreamingBrainVersionsynctranscoderActiveVideoSessionsr   transcoderAudiotranscoderLyricstranscoderPhototranscoderSubtitlestranscoderVideotranscoderVideoBitratestranscoderVideoQualitiestranscoderVideoResolutions	updatedAtupdaterversionvoiceSearchN)2_datar   castboolattribr+   rF   rG   rH   rI   rJ   rK   rL   rM   toListrN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r\   r]   intr^   r_   r`   ra   rb   rc   rd   re   rf   rg   rh   ri   rj   
toDatetimerk   rl   rm   rn   r=   rA   s     rC   	_loadDatazPlexServer._loadDataw   s   
!&D$++//BU2V!W"'**T4;;??CW3X"Y"'**T4;;??CW3X"Y!JJtT[[__^-LMD$++//+*FG$)JJtT[[__E[5\$]! ::dDKKOOM,JK#jjt{{?O/PQ <<(FG ::dDKKOOM,JK KKOON;D$++//+*FG!%1D!ED$++//+*FGjjt{{x'@A"&++//2F"G!%1D!E"'**T4;;??CW3X"Y"kkoo.>?"\\$++///*JK!JJtT[[__^-LM
3#{{/@A**T4;;??<+HI!&CAT1U!V).D$++//Je:f)g&%)[[__5L%M"JJtT[[__V%<=	-0A`bc1d-e*$zz$@Q0RS %

4AS1T U$zz$@Q0RS#(::dDKKOODY4Z#[ $zz$@Q0RS',||DKKOOD]4^'_$(-T[[__E_5`(a%*/,,t{{Gc7d*e'))$++//+*FGzz$	(BC{{y1 ::dDKKOOM,JKrD   c                     t        j                         }| j                  r| j                  |d<   |j                  |       |S )zF Returns dict containing base headers for all requests to the server. zX-Plex-Token)r   copyr/   update)r=   kwargsheaderss      rC   _headerszPlexServer._headers   s6    ##%;;&*kkGN#vrD   c                 "    d| j                    dS )Nz	server:///com.plexapp.plugins.library)rR   r=   s    rC   _uriRootzPlexServer._uriRoot   s    41122NOOrD   c                     	 | j                  t        j                        }t        | |      S # t        $ r | j                  d      }Y (w xY w)z) Library to browse or search your media. z/library/sections/)r9   r   r:   r   rv   s     rC   libraryzPlexServer.library   sJ    	4::gkk*D
 tT""	  	4 ::23D	4s   - A
	A
c                 X    | j                  t        j                        }t        | |      S )z( Returns a list of all server settings. )r9   r   r:   rv   s     rC   settingszPlexServer.settings   s#     zz(,,'d##rD   c                 <    | j                  d      }t        | |      S )z# Returns the Plex server identity. z	/identity)r9   Identityrv   s     rC   identityzPlexServer.identity   s    zz+&d##rD   c                 X    | j                  t        j                        }t        | |      S )zM Returns the :class:`~plexapi.server.Account` object this server belongs to. )r9   Accountr:   rv   s     rC   accountzPlexServer.account   s!    zz'++&tT""rD   c                     d}d|j                         i}| j                  || j                  j                  |      }t	        | |      S )a>   Claim the Plex server using a :class:`~plexapi.myplex.MyPlexAccount`.
            This will only work with an unclaimed server on localhost or the same subnet.

            Parameters:
                account (:class:`~plexapi.myplex.MyPlexAccount`): The account used to
                    claim the server.
        z/myplex/claimr?   )methodparams)
claimTokenr9   r4   postr   )r=   r   r:   r   rA   s        rC   claimzPlexServer.claim   sG     7--/0zz#dmm&8&8zHtT""rD   c                     | j                  t        j                  | j                  j                        }t        | |      S )z| Unclaim the Plex server. This will remove the server from your
            :class:`~plexapi.myplex.MyPlexAccount`.
        r   )r9   r   r:   r4   deleterv   s     rC   unclaimzPlexServer.unclaim   s1     zz'++dmm.B.BzCtT""rD   c                     g }| j                  t        j                        D ]  }|j                  t        | |              |S )z#Returns all current PMS activities.)r9   Activityr:   append)r=   
activitieselems      rC   r   zPlexServer.activities   s@     
JJx||, 	4DhtT23	4rD   c                 b    d}|r|dt        j                  |       z  }| j                  |      S )zT Returns a list of :class:`~plexapi.media.Agent` objects this server has available. z/system/agentsz?mediaType=)r   
searchType
fetchItems)r=   	mediaTyper:   s      rC   agentszPlexServer.agents   s6    [!1!1)!< =>>Cs##rD   c                     | j                   sy| j                  d| d|       }|j                  j                  d      S )z, Create a temp access token for the server. Nz/security/token?type=z&scope=r?   )r/   r9   rr   r+   )r=   typescopeqs       rC   createTokenzPlexServer.createToken   s;    {{JJ.tfGE7CDxx||G$$rD   c                    ddl m} t        ||      r|n| j                         j	                  |      }|j                  | j                        }|| j                  }|| j                  }t        | j                  |||      S )a   Returns a new :class:`~plexapi.server.PlexServer` object logged in as the given username.
            Note: Only the admin account can switch to other users.

            Parameters:
                user (:class:`~plexapi.myplex.MyPlexUser` or str): `MyPlexUser` object, username,
                    email, or user id of the user to log in to the server.
                session (requests.Session, optional): Use your own session object if you want to
                    cache the http responses from the server. This will default to the same
                    session as the admin account if no new session is provided.
                timeout (int, optional): Timeout in seconds on initial connection to the server.
                    This will default to the same timeout as the admin account if no new timeout
                    is provided.

            Example:

                .. code-block:: python

                    from plexapi.server import PlexServer
                    # Login to the Plex server using the admin token
                    plex = PlexServer('http://plexserver:32400', token='2ffLuB84dqLswk9skLos')
                    # Login to the same Plex server using a different account
                    userPlex = plex.switchUser("Username")

        r   )
MyPlexUser)r?   r@   r*   )plexapi.myplexr   
isinstancemyPlexAccountuser	get_tokenrR   r4   r5   r%   r,   )r=   r   r@   r*   r   	userTokens         rC   
switchUserzPlexServer.switchUser   sr    2 	.!$
3t9K9K9M9R9RSW9XNN4#9#9:	?mmG?mmG$--y'SZ[[rD   c                 l    | j                   d}| j                  |t              | _         | j                   S )zX Returns a list of :class:`~plexapi.server.SystemAccount` objects this server contains. z	/accounts)r7   r   SystemAccountr=   r:   s     rC   systemAccountszPlexServer.systemAccounts  s2    'C#'??3#FD ###rD   c                     	 t        fd| j                         D              S # t        $ r t        d       dw xY w)z Returns the :class:`~plexapi.server.SystemAccount` object for the specified account ID.

            Parameters:
                accountID (int): The :class:`~plexapi.server.SystemAccount` ID.
        c              3   B   K   | ]  }|j                   k(  s|  y wNid).0r   	accountIDs     rC   	<genexpr>z+PlexServer.systemAccount.<locals>.<genexpr>%  s     `G

V_H_`   zUnknown account with accountID=N)nextr   StopIterationr   )r=   r   s    `rC   systemAccountzPlexServer.systemAccount  sI    	T`t/B/B/D``` 	T<YKHItS	T   !% >c                 l    | j                   d}| j                  |t              | _         | j                   S )zW Returns a list of :class:`~plexapi.server.SystemDevice` objects this server contains. z/devices)r8   r   SystemDevicer   s     rC   systemDeviceszPlexServer.systemDevices)  s2    &C"&//#|"DD"""rD   c                     	 t        fd| j                         D              S # t        $ r t        d       dw xY w)z Returns the :class:`~plexapi.server.SystemDevice` object for the specified device ID.

            Parameters:
                deviceID (int): The :class:`~plexapi.server.SystemDevice` ID.
        c              3   B   K   | ]  }|j                   k(  s|  y wr   r   )r   devicedeviceIDs     rC   r   z*PlexServer.systemDevice.<locals>.<genexpr>7  s     [6VYYRZEZ[r   zUnknown device with deviceID=N)r   r   r   r   )r=   r   s    `rC   systemDevicezPlexServer.systemDevice0  sI    	Q[T-?-?-A[[[ 	Q:8*EFDP	Qr   c                     | j                   )ddlm}  || j                  | j                        | _         | j                   S )z Returns a :class:`~plexapi.myplex.MyPlexAccount` object using the same
            token to access this server. If you are not the owner of this PlexServer
            you're likely to receive an authentication error calling this.
        r   )MyPlexAccount)r?   r@   )r6   r   r   r/   r4   )r=   r   s     rC   r   zPlexServer.myPlexAccount;  s6    
 &4"/dkk4=="YD"""rD   c                 R   	 i }| j                         }|j                         D ]R  }|j                  sd|j                  d   dd v s%|j                  d   j                  d      d   ||j                  <   T |S # t
        $ r"}t        j                  d|       cY d}~S d}~ww xY w)a1   Sometimes the PlexServer does not properly advertise port numbers required
            to connect. This attempts to look up device port number from plex.tv.
            See issue #126: Make PlexServer.clients() more user friendly.
              https://github.com/pkkid/python-plexapi/issues/126
        :r      Nz,Unable to fetch client ports from myPlex: %s)r   devicesconnectionssplitclientIdentifier	Exceptionr	   warning)r=   portsr   r   errs        rC   _myPlexClientPortszPlexServer._myPlexClientPortsE  s    		E((*G!//+ Z%%#1C1CA1Fqr1J*J5;5G5G5J5P5PQT5UVX5YE&112Z L 	KKFLL	s(   1A; A; 	1A; ;	B&B!B&!B&c                     t        |t              r|j                  }n|t        j                  |      }d| }nd}|dt        |       z  }| j                  |      S )a   Browse the system file path using the Plex API.
            Returns list of :class:`~plexapi.library.Path` and :class:`~plexapi.library.File` objects.

            Parameters:
                path (:class:`~plexapi.library.Path` or str, optional): Full path to browse.
                includeFiles (bool): True to include files when browsing (Default).
                                     False to only return folders.
        z/services/browse/z/services/browsez?includeFiles=)r   r   r:   r   	base64strrt   r   )r=   pathincludeFilesr:   
base64paths        rC   browsezPlexServer.browseV  sb     dD!((C.J%j\2C$CL 1233s##rD   c              #   f  K   g }g }| j                  |      D ]F  }t        |t              r|j                  |       %t        |t              s6|j                  |       H t        |t              r|j
                  }|xs d||f |D ]#  }| j                  |      D ]  \  }}}|||f  % yw)a   Walk the system file tree using the Plex API similar to `os.walk`.
            Yields a 3-tuple `(path, paths, files)` where
            `path` is a string of the directory path,
            `paths` is a list of :class:`~plexapi.library.Path` objects, and
            `files` is a list of :class:`~plexapi.library.File` objects.

            Parameters:
                path (:class:`~plexapi.library.Path` or str, optional): Full path to walk.
        r(   N)r   r   r   r   r   r   walk)r=   r   pathsfilesitem_paths         rC   r   zPlexServer.walki  s      KK% 	#D$%T"D$'T"		# dD!99Djb%&& 	)E&*ii&6 )"eUE5(()	)s   AB1A#B1c                     t        |t              r|j                  }| j                  t        j                  j                  |      d      D cg c]  }|j                   }}||v S c c}w )z Returns True if the Plex server can browse the given path.

            Parameters:
                path (:class:`~plexapi.library.Path` or str): Full path to browse.
        F)r   )r   r   r   r   osdirname)r=   r   pr   s       rC   isBrowsablezPlexServer.isBrowsable  sY     dD!99D!%RWW__T-BQV!WXAXXu} Ys   A(c           
         g }d}| j                  d      D ]  }|j                  j                  d      }|smt        j                  d|j                  j                  d             || j                         n|}|j                  |j                  j                  d            }d|j                  d    d	| }|j                  t        || | j                  |d
              |S )zV Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. Nz/clientsportz.%s did not advertise a port, checking plex.tv.namerR   zhttp://hostr   F)r>   serverr?   rA   connect)	r9   rr   r+   r	   r   r   r   r   r/   )r=   itemsr   r   r   r>   s         rC   clientszPlexServer.clients  s    JJz* 	RD;;??6*DLdkkoo^dNef5:]//1yy1D!EFF 34AdV<GLLGD*.++D%Q R	R rD   c                     | j                         D ]'  }|s|j                  |k(  s|j                  |k(  s%|c S  t        d|       )aD   Returns the :class:`~plexapi.client.PlexClient` that matches the specified name
            or machine identifier.

            Parameters:
                name (str): Name or machine identifier of the client to return.

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: Unknown client name.
        zUnknown client name: )r   titlerR   r   )r=   r   clients      rC   r   zPlexServer.client  sN     lln 	F6<<4/63K3Kt3S	 .tf566rD   c	           
      @    t        j                  | ||f||||||d|	S )a
   Creates and returns a new :class:`~plexapi.collection.Collection`.

            Parameters:
                title (str): Title of the collection.
                section (:class:`~plexapi.library.LibrarySection`, str): The library section to create the collection in.
                items (List): Regular collections only, list of :class:`~plexapi.audio.Audio`,
                    :class:`~plexapi.video.Video`, or :class:`~plexapi.photo.Photo` objects to be added to the collection.
                smart (bool): True to create a smart collection. Default False.
                limit (int): Smart collections only, limit the number of items in the collection.
                libtype (str): Smart collections only, the specific type of content to filter
                    (movie, show, season, episode, artist, album, track, photoalbum, photo).
                sort (str or list, optional): Smart collections only, a string of comma separated sort fields
                    or a list of sort fields in the format ``column:dir``.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                filters (dict): Smart collections only, a dictionary of advanced filters.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                **kwargs (dict): Smart collections only, additional custom filters to apply to the
                    search results. See :func:`~plexapi.library.LibrarySection.search` for more info.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When no items are included to create the collection.
                :class:`plexapi.exceptions.BadRequest`: When mixing media types in the collection.

            Returns:
                :class:`~plexapi.collection.Collection`: A new instance of the created Collection.

            Example:

                .. code-block:: python

                    # Create a regular collection
                    movies = plex.library.section("Movies")
                    movie1 = movies.get("Big Buck Bunny")
                    movie2 = movies.get("Sita Sings the Blues")
                    collection = plex.createCollection(
                        title="Favorite Movies",
                        section=movies,
                        items=[movie1, movie2]
                    )

                    # Create a smart collection
                    collection = plex.createCollection(
                        title="Recently Aired Comedy TV Shows",
                        section="TV Shows",
                        smart=True,
                        sort="episode.originallyAvailableAt:desc",
                        filters={"episode.originallyAvailableAt>>": "4w", "genre": "comedy"}
                    )

        )r   smartlimitlibtypesortfilters)r   create)
r=   r   sectionr   r   r   r   r   r   r{   s
             rC   createCollectionzPlexServer.createCollection  s>    h   %C(-U%$C;AC 	CrD   c
                 B    t        j                  | |f||||||||	d|
S )a"   Creates and returns a new :class:`~plexapi.playlist.Playlist`.

            Parameters:
                title (str): Title of the playlist.
                section (:class:`~plexapi.library.LibrarySection`, str): Smart playlists and m3u import only,
                    the library section to create the playlist in.
                items (List): Regular playlists only, list of :class:`~plexapi.audio.Audio`,
                    :class:`~plexapi.video.Video`, or :class:`~plexapi.photo.Photo` objects to be added to the playlist.
                smart (bool): True to create a smart playlist. Default False.
                limit (int): Smart playlists only, limit the number of items in the playlist.
                libtype (str): Smart playlists only, the specific type of content to filter
                    (movie, show, season, episode, artist, album, track, photoalbum, photo).
                sort (str or list, optional): Smart playlists only, a string of comma separated sort fields
                    or a list of sort fields in the format ``column:dir``.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                filters (dict): Smart playlists only, a dictionary of advanced filters.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                m3ufilepath (str): Music playlists only, the full file path to an m3u file to import.
                    Note: This will overwrite any playlist previously created from the same m3u file.
                **kwargs (dict): Smart playlists only, additional custom filters to apply to the
                    search results. See :func:`~plexapi.library.LibrarySection.search` for more info.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When no items are included to create the playlist.
                :class:`plexapi.exceptions.BadRequest`: When mixing media types in the playlist.
                :class:`plexapi.exceptions.BadRequest`: When attempting to import m3u file into non-music library.
                :class:`plexapi.exceptions.BadRequest`: When failed to import m3u file.

            Returns:
                :class:`~plexapi.playlist.Playlist`: A new instance of the created Playlist.

            Example:

                .. code-block:: python

                    # Create a regular playlist
                    episodes = plex.library.section("TV Shows").get("Game of Thrones").episodes()
                    playlist = plex.createPlaylist(
                        title="GoT Episodes",
                        items=episodes
                    )

                    # Create a smart playlist
                    playlist = plex.createPlaylist(
                        title="Top 10 Unwatched Movies",
                        section="Movies",
                        smart=True,
                        limit=10,
                        sort="audienceRating:desc",
                        filters={"audienceRating>>": 8.0, "unwatched": True}
                    )

                    # Create a music playlist from an m3u file
                    playlist = plex.createPlaylist(
                        title="Favorite Tracks",
                        section="Music",
                        m3ufilepath="/path/to/playlist.m3u"
                    )

        )r   r   r   r   r   r   r   m3ufilepath)r   r   )r=   r   r   r   r   r   r   r   r   r   r{   s              rC   createPlaylistzPlexServer.createPlaylist  s>    | %\!(U%$[\TZ\ 	\rD   c                 0    t        j                  | |fi |S )z Creates and returns a new :class:`~plexapi.playqueue.PlayQueue`.

            Parameters:
                item (Media or Playlist): Media or playlist to add to PlayQueue.
                kwargs (dict): See `~plexapi.playqueue.PlayQueue.create`.
        )r   r   )r=   r   r{   s      rC   createPlayQueuezPlexServer.createPlayQueue)  s     d5f55rD   c           	          | j                  d      }t        j                  || j                  d|| j                  ||      }|S )z Download databases.

            Parameters:
                savepath (str): Defaults to current working dir.
                unpack (bool): Unpack the zip file.
                showstatus(bool): Display a progressbar.
        z/diagnostics/databasesNunpack
showstatusurlr   downloadr/   r4   r=   savepathr  r  r  filepaths         rC   downloadDatabaseszPlexServer.downloadDatabases2  s<     hh/0>>#t{{D(DMMZ`mwxrD   c           	          | j                  d      }t        j                  || j                  d|| j                  ||      }|S )z Download server logs.

            Parameters:
                savepath (str): Defaults to current working dir.
                unpack (bool): Unpack the zip file.
                showstatus(bool): Display a progressbar.
        z/diagnostics/logsNr  r  r  s         rC   downloadLogszPlexServer.downloadLogs>  s<     hh*+>>#t{{D(DMMZ`mwxrD   c                 $    | j                  d      S )z= Return a list of :class:`~plexapi.base.ButlerTask` objects. z/butlerr   r   s    rC   butlerTaskszPlexServer.butlerTasksJ  s    y))rD   c                     | j                         D cg c]  }|j                   }}||vrt        d| d|       | j                  d| | j                  j
                         | S c c}w )a   Manually run a butler task immediately instead of waiting for the scheduled task to run.
            Note: The butler task is run asynchronously. Check Plex Web to monitor activity.

            Parameters:
                task (str): The name of the task to run. (e.g. 'BackupDatabase')

            Example:

                .. code-block:: python

                    availableTasks = [task.name for task in plex.butlerTasks()]
                    print("Available butler tasks:", availableTasks)

        zInvalid butler task: z. Available tasks are: z/butler/r   )r  r   r   r9   r4   r   )r=   task_task
validTaskss       rC   runButlerTaskzPlexServer.runButlerTaskN  sx     /3.>.>.@AUejjA
Az!'v-DZLQ  	

XdV$T]]-?-?
@ Bs   A)zuse "checkForUpdate" insteadc                 (    | j                  ||      S )Nforcer  checkForUpdate)r=   r  r  s      rC   check_for_updatezPlexServer.check_for_updatee  s    """BBrD   c                     d|rdnd }|r'| j                  || j                  j                         | j                  d      }t	        |      r|d   S y)a>   Returns a :class:`~plexapi.server.Release` object containing release info
            if an update is available or None if no update is available.

            Parameters:
                force (bool): Force server to check for new releases
                download (bool): Download if a update is available.
        z/updater/check?download=   r   r   /updater/statusN)r9   r4   putr   len)r=   r  r  partreleasess        rC   r  zPlexServer.checkForUpdatei  sW     *x!Q)?@JJtDMM$5$5J6??#45x=A; rD   c                 .    | j                  d      }|du S )zK Returns True if the installed version of Plex Media Server is the latest. T)r  Nr  r=   releases     rC   isLatestzPlexServer.isLatestx  s    %%D%1$rD   c                 v    | j                  d      }t        j                  t        |j	                  d            S )z Returns True if the newest version of Plex Media Server can be installed automatically.
            (e.g. Windows and Mac can install updates automatically, but Docker and NAS devices cannot.)
        r  
canInstall)r9   r   rp   rq   r+   r#  s     rC   canInstallUpdatezPlexServer.canInstallUpdate}  s-     **./zz$L 9::rD   c                     d}| j                  dd      }|rA|j                  | j                  k7  r'| j                  || j                  j                        S yy)z@ Automatically install the newest version of Plex Media Server. z/updater/applyTr  r   N)r  rm   r9   r4   r  )r=   r   r$  s      rC   installUpdatezPlexServer.installUpdate  sT      %%D4%@w$,,6::d4==+<+<:== 77rD   c                     ddi}|r||d<   |r||d<   |r||d<   |rt        |j                               |d<   dt        j                  |       }| j	                  ||      S )	a   Returns a list of media items from watched history. If there are many results, they will
            be fetched from the server in batches of X_PLEX_CONTAINER_SIZE amounts. If you're only
            looking for the first <num> results, it would be wise to set the maxresults option to that
            amount so this functions doesn't iterate over all results on the server.

            Parameters:
                maxresults (int): Only return the specified number of results (optional).
                mindate (datetime): Min datetime to return results from. This really helps speed
                    up the result listing. For example: datetime.now() - timedelta(days=7)
                ratingKey (int/str) Request history for a specific ratingKey item.
                accountID (int/str) Request history for a specific account ID.
                librarySectionID (int/str) Request history for a specific library section ID.
        r   zviewedAt:descmetadataItemIDr   librarySectionIDz	viewedAt>z/status/sessions/history/all)
maxresults)rt   	timestampr   joinArgsr   )r=   r.  mindate	ratingKeyr   r-  argsr:   s           rC   historyzPlexServer.history  s{     (%.D!" )D'7D#$ #G$5$5$7 8D,U^^D-A,BCsz::rD   c                     i }|||d<   |||d<   |||d<   |||d<   dt        j                  |       } | j                  |fi |S )aO   Returns a list of all :class:`~plexapi.playlist.Playlist` objects on the server.

            Parameters:
                playlistType (str, optional): The type of playlists to return (audio, video, photo).
                    Default returns all playlists.
                sectionId (int, optional): The section ID (key) of the library to search within.
                title (str, optional): General string query to search for. Partial string matches are allowed.
                sort (str or list, optional): A string of comma separated sort fields in the format ``column:dir``.
        playlistType	sectionIDr   r   z
/playlists)r   r0  r   )r=   r6  	sectionIdr   r   r{   r3  r:   s           rC   	playlistszPlexServer.playlists  ss     ##/D   )D!DMDL5>>$/01ts-f--rD   c                 j    	 | j                  ||      d   S # t        $ r t        d| d      dw xY w)a   Returns the :class:`~plexapi.client.Playlist` that matches the specified title.

            Parameters:
                title (str): Title of the playlist to return.

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: Unable to find playlist.
        )r   title__iexactr   z$Unable to find playlist with title "z".N)r9  
IndexErrorr   )r=   r   s     rC   r"   zPlexServer.playlist  sI    	W>>U>CAFF 	WA%KLRVV	Ws    2c                     |du r4d}| j                  || j                  j                  j                         y| j	                  d      }| j                  |j                   dt              S )zT Returns list of all :class:`~plexapi.media.Optimized` objects connected to server. Tz/playlists/generators?type=42r   /playlists?type=42/itemsclsN)r9   _serverr4   r   	fetchItemr   r:   r   )r=   	removeAllr:   rK   s       rC   optimizedItemszPlexServer.optimizedItems  sa    1CJJs4<<#8#8#?#?J@#'>>2F#G ??&:&>&>%?v#FI?VVrD   z-use "plexapi.media.Optimized.items()" insteadc                 f    | j                  d      }| j                  |j                   d| d      S )z Returns single queued optimized item :class:`~plexapi.media.Video` object.
            Allows for using optimized item ID to connect back to source item.
        r>  z/items/r?  )rC  r:   )r=   optimizedIDrK   s      rC   optimizedItemzPlexServer.optimizedItem  s8      $~~.BC~~!5!9!9 :'+fUVVrD   c                    |du r2| j                  d| j                  j                  j                         y|du r2| j                  d| j                  j                  j                         y| j	                  dt
              S )	zU Returns list of all :class:`~plexapi.media.Conversion` objects connected to server. Tz$/:/prefs?BackgroundQueueIdlePaused=1r   Fz$/:/prefs?BackgroundQueueIdlePaused=0z/playQueues/1r@  N)r9   rB  r4   r  r   r   )r=   pauses     rC   conversionszPlexServer.conversions  se    D=JJ=dllF[F[F_F_J`e^JJ=dllF[F[F_F_J`???
?CCrD   c                 $    | j                  d      S )z_ Returns list of all :class:`~plexapi.media.TranscodeJob` objects running or paused on server. z/status/sessions/backgroundr  r   s    rC   currentBackgroundProcessz#PlexServer.currentBackgroundProcess  s    <==rD   c                     | j                  |      }|xs | j                  j                  }|xs | j                  }t	        j
                  d|j                  j                         |        | j                  di |xs i } ||f|||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        |      t!        j"                  |j                        j%                  d      }|j'                         rt)        j*                  |      S dS )z Main method used to handle HTTPS requests to the Plex server. This method helps
            by encoding the response to utf-8 and parsing the returned XML into and
            ElementTree object. Returns None if no data exists in the response.
        z%s %s)r|   r   r*   )         r   
 (z) z; i  i  utf8N )r  r4   r+   r5   r	   debug__name__upperr}   status_codecodestextreplacer   r   r   r   cleanXMLStringencodestripr   
fromstring)r=   r:   r   r|   r   r*   r{   r  responsecodenameerrtextmessagerA   s                rC   r9   zPlexServer.query  s`   
 hhsm,4==,,*T]]		'6??002C8$--0'-R0#YwvwYRXY6yy!5!56q9Hmm++D#6G(../r(2hll^1WIVG##s*"7++%%,w'' ))##HMM299&A/3zz|{%%d+EErD   c                     g }|ddd}|r||d<   |r||d<   dt        |       }| j                  |t              D ]1  }|r|j                  |k(  s|j                  c S ||j                  z  }3 |S )uq   Returns a list of media items or filter categories from the resulting
            `Hub Search <https://www.plex.tv/blog/seek-plex-shall-find-leveling-web-app/>`_
            against all items in your Plex library. This searches genres, actors, directors,
            playlists, as well as all the obvious media titles. It performs spell-checking
            against your search terms (because KUROSAWA is hard to spell). It also provides
            contextual search results. So for example, if you search for 'Pernice', it’ll
            return 'Pernice Brothers' as the artist result, but we’ll also go ahead and
            return your most-listened to albums and tracks from the artist. If you type
            'Arnold' you’ll get a result for the actor, but also the most recently added
            movies he’s in.

            Parameters:
                query (str): Query to use when searching your library.
                mediatype (str, optional): Limit your search to the specified media type.
                    actor, album, artist, autotag, collection, director, episode, game, genre,
                    movie, photo, photoalbum, place, playlist, shared, show, tag, track
                limit (int, optional): Limit to the specified number of results per Hub.
                sectionId (int, optional): The section ID (key) of the library to search within.
        r  )r9   includeCollectionsincludeExternalMediar   r8  z/hubs/search?)r   r   r   r   r   )	r=   r9   	mediatyper   r8  resultsr   r:   hubs	            rC   searchzPlexServer.search  s    ( "#$%' #F7O"+F;i/01??3, 	%C88y(99$399$	% rD   c                 $    | j                  d      S )z: Return a list of all items in the Continue Watching hub. z/hubs/continueWatching/itemsr  r   s    rC   continueWatchingzPlexServer.continueWatching,  s    =>>rD   c                 $    | j                  d      S )zI Returns a list of all active session (currently playing) media objects. z/status/sessionsr  r   s    rC   sessionszPlexServer.sessions0  s    122rD   c                 $    | j                  d      S )zP Returns a list of all active :class:`~plexapi.media.TranscodeSession` objects. z/transcode/sessionsr  r   s    rC   transcodeSessionszPlexServer.transcodeSessions4  s    455rD   c                 @    t        | ||      }|j                          |S )a   Creates a websocket connection to the Plex Server to optionally receive
            notifications. These often include messages from Plex about media scans
            as well as updates to currently running Transcode Sessions.

            Returns a new :class:`~plexapi.alert.AlertListener` object.

            Note: ``websocket-client`` must be installed in order to use this feature.

            .. code-block:: python

                >> pip install websocket-client

            Parameters:
                callback (func): Callback function to call on received messages.
                callbackError (func): Callback function to call on errors.

            Raises:
                :exc:`~plexapi.exception.Unsupported`: Websocket-client not installed.
        )r   start)r=   callbackcallbackErrornotifiers       rC   startAlertListenerzPlexServer.startAlertListener8  s!    ( !x?rD   c           	         |||t        t        |	            t        t        |
            d}|||d<   |||d<   |||d<   |t        |      j                  d      |d<   |t        |      j                  d      |d<   ||j	                         |d<   d	t        j                  |       }| j                  |d
      S )a   Returns the URL for a transcoded image.

            Parameters:
                imageUrl (str): The URL to the image
                    (eg. returned by :func:`~plexapi.mixins.PosterUrlMixin.thumbUrl`
                    or :func:`~plexapi.mixins.ArtUrlMixin.artUrl`).
                    The URL can be an online image.
                height (int): Height to transcode the image to.
                width (int): Width to transcode the image to.
                opacity (int, optional): Change the opacity of the image (0 to 100)
                saturation (int, optional): Change the saturation of the image (0 to 100).
                blur (int, optional): The blur to apply to the image in pixels (e.g. 3).
                background (str, optional): The background hex colour to apply behind the opacity (e.g. '000000').
                blendColor (str, optional): The hex colour to blend the image with (e.g. '000000').
                minSize (bool, optional): Maintain smallest dimension. Default True.
                upscale (bool, optional): Upscale the image if required. Default True.
                imageFormat (str, optional): 'jpeg' (default) or 'png'.
        )r  heightwidthminSizeupscaleopacity
saturationblur#
background
blendColorformatz/photo/:/transcodeT)includeToken)rt   rq   strr`  r0   r   r0  r  )r=   imageUrlrz  r{  r~  r  r  r  r  r|  r}  imageFormatr   r:   s                 rC   transcodeImagezPlexServer.transcodeImageP  s    , 4=)4=)
  'F9!#-F< !F6N!#&z?#8#8#=F< !#&z?#8#8#=F< "*002F8"5>>&#9":;xx$x//rD   c                     | j                   r5|s| j                  r'd|v rdnd}| j                   | | d| j                    S | j                   | S )z Build a URL string with proper token argument.  Token will be appended to the URL
            if either includeToken is True or CONFIG.log.show_secrets is 'true'.
        ?&zX-Plex-Token=)r/   r1   r,   )r=   r:   r  delims       rC   r  zPlexServer.url|  sV     ;;LD,=,=#:C3Emm_SE%dkk]KK--&&rD   c                 N    | j                  d| j                  j                        S )z2 Force PMS to download new SyncList from Plex.tv. z/sync/refreshSynclistsr9   r4   r  r   s    rC   refreshSynclistzPlexServer.refreshSynclist  s    zz2DMM4E4EFFrD   c                 N    | j                  d| j                  j                        S )z3 Force PMS to refresh content for known SyncLists. z/sync/refreshContentr  r   s    rC   refreshContentzPlexServer.refreshContent  s    zz0$--2C2CDDrD   c                 D    | j                          | j                          y)z Calls :func:`~plexapi.server.PlexServer.refreshSynclist` and
            :func:`~plexapi.server.PlexServer.refreshContent`, just like the Plex Web UI does when you click 'refresh'.
        N)r  r  r   s    rC   refreshSynczPlexServer.refreshSync  s     	rD   c                    | j                   r|du rt        j                  d       nv| j                   r$|du r t        j                  d       t        d      | j                   |du rt        j                  d       n t        j                  d       t        d      |du rdnd}| j	                  d	| | j
                  j                        S )
z Toggle allowMediaDeletion.
            Parameters:
                toggle (bool): True enables Media Deletion
                               False or None disable Media Deletion (Default)
        Fz8Plex is currently allowed to delete media. Toggling off.TzHPlex is currently allowed to delete media. Toggle set to allow, exiting.zCPlex is currently not allowed to delete media. Toggle set to allow.zPPlex is currently not allowed to delete media. Toggle set to not allow, exiting.r  r   z/:/prefs?allowMediaDeletion=)rH   r	   rW  r   r9   r4   r  )r=   togglevalues      rC   _allowMediaDeletionzPlexServer._allowMediaDeletion  s     ""vIIPQ$$4II`aghh$$,4II[\IIhioppt^zz8@$--BSBSTTrD   c           
         i }|d|d<   ndddddd}	 ||   |d<   h d}|j	                         D ]  \  }}||vrt        d| d|       |j                  d      r*	 t        j                  t        |j                               }nU|j                  d      s|dk(  rt        j                  t        |      }n$|dk(  r|| j                         j                  k(  rd}|||<    dt        |       }| j                  |t              S # t         $ r/ t        d| d	d
j                  |j                                      w xY w# t        $ r t        d| d|       w xY w)a8   Returns a list of :class:`~plexapi.server.StatisticsBandwidth` objects
            with the Plex server dashboard bandwidth data.

            Parameters:
                timespan (str, optional): The timespan to bin the bandwidth data. Default is seconds.
                    Available timespans: seconds, hours, days, weeks, months.
                **kwargs (dict, optional): Any of the available filters that can be applied to the bandwidth data.
                    The time frame (at) and bytes can also be filtered using less than or greater than (see examples below).

                    * accountID (int): The :class:`~plexapi.server.SystemAccount` ID to filter.
                    * at (datetime): The time frame to filter (inclusive). The time frame can be either:
                        1. An exact time frame (e.g. Only December 1st 2020 `at=datetime(2020, 12, 1)`).
                        2. Before a specific time (e.g. Before and including December 2020 `at<=datetime(2020, 12, 1)`).
                        3. After a specific time (e.g. After and including January 2021 `at>=datetime(2021, 1, 1)`).
                    * bytes (int): The amount of bytes to filter (inclusive). The bytes can be either:
                        1. An exact number of bytes (not very useful) (e.g. `bytes=1024**3`).
                        2. Less than or equal number of bytes (e.g. `bytes<=1024**3`).
                        3. Greater than or equal number of bytes (e.g. `bytes>=1024**3`).
                    * deviceID (int): The :class:`~plexapi.server.SystemDevice` ID to filter.
                    * lan (bool): True to only retrieve local bandwidth, False to only retrieve remote bandwidth.
                        Default returns all local and remote bandwidth.

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: When applying an invalid timespan or unknown filter.

            Example:

                .. code-block:: python

                    from plexapi.server import PlexServer
                    plex = PlexServer('http://localhost:32400', token='xxxxxxxxxxxxxxxxxxxx')

                    # Filter bandwidth data for December 2020 and later, and more than 1 GB used.
                    filters = {
                        'at>': datetime(2020, 12, 1),
                        'bytes>': 1024**3
                    }

                    # Retrieve bandwidth data in one day timespans.
                    bandwidthData = plex.bandwidth(timespan='days', **filters)

                    # Print out bandwidth usage for each account and device combination.
                    for bandwidth in sorted(bandwidthData, key=lambda x: x.at):
                        account = bandwidth.account()
                        device = bandwidth.device()
                        gigabytes = round(bandwidth.bytes / 1024**3, 3)
                        local = 'local' if bandwidth.lan else 'remote'
                        date = bandwidth.at.strftime('%Y-%m-%d')
                        print(f'{account.name} used {gigabytes} GB of {local} bandwidth on {date} from {device.name}')

        r   timespan         r  )secondshoursdaysweeksmonthszInvalid timespan specified: z. Available timespans: z, >	   at<at>bytes<bytes>atlanbytesr   r   zUnknown filter: =r  z-Time frame filter must be a datetime object: r  r  r   z/statistics/bandwidth?)KeyErrorr   joinkeysr   
startswithr   rp   rt   r/  AttributeErrorr   r   r   r   StatisticsBandwidth)r=   r  r{   r   	timespansr   r:   r  s           rC   	bandwidthzPlexServer.bandwidth  s   h !"F: IX%.x%8z"
 d ,,. 	 JC'! #3C5%!ABB~~d#d!JJsEOO,=>E (C5L

3.#D..0333EF3K	  'y'8&9:s$788-  X #?z J99=9>>CS9T8U"W X XX & d$'TUXTYYZ[`Za%bccds   D (E8D>Ec                 2    d}| j                  |t              S )z Returns a list of :class:`~plexapi.server.StatisticsResources` objects
            with the Plex server dashboard resources data. z /statistics/resources?timespan=6)r   StatisticsResourcesr   s     rC   	resourceszPlexServer.resources  s     1s$788rD   c                     |d}|r)| d| j                    d| t        j                  |       S | d| j                    dt        j                  |       S )a   Build the Plex Web URL for the object.

            Parameters:
                base (str): The base URL before the fragment (``#!``).
                    Default is https://app.plex.tv/desktop.
                endpoint (str): The Plex Web URL endpoint.
                    None for server, 'playlist' for playlists, 'details' for all other media types.
                **kwargs (dict): Dictionary of URL parameters.
        zhttps://app.plex.tv/desktop/z
#!/server/r&   z	#!/media/r   )rR   r   r0  )r=   baseendpointr{   s       rC   _buildWebURLzPlexServer._buildWebURL  sk     <1DV:d&<&<%=QxjX^I_H`aaV9T%;%;$<<XY^YgYghnYoXpqqrD   c                 J    |	dd| d}nddd} | j                   dd|i|S )	a9   Returns the Plex Web URL for the server.

            Parameters:
                base (str): The base URL before the fragment (``#!``).
                    Default is https://app.plex.tv/desktop.
                playlistTab (str): The playlist tab (audio, video, photo). Only used for the playlist URL.
        r9  z
playlists.)sourcepivotz/hubsrk  )r:   pageTyper  rV  )r  )r=   r  playlistTabr   s       rC   	getWebURLzPlexServer.getWebURL  s@     " +
;-6PQF$%8F t  5d5f55rD   )NNNNr   )
delegationall)NN)NT)NFNNNN)NNFNNNNN)NFF)TF)NNNNN)NNN)NNNNNTTN)F)ErX  
__module____qualname____doc__r:   r<   rw   r}   r   r   r   r   r   r   r   r   propertyr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r
  r  r  r  r   r  r  r%  r(  r*  r4  r9  r"   rE  rH  rK  rM  r9   rl  rn  rp  rr  rx  r  r  r  r  r  r  r  r  r  r  __classcell__)rB   s   @rC   r%   r%   !   s   EL C?+LZP # # $ $
$
#
##  $% \D$	T#	Q#"$&)6	 7  OS:>6Cp RVJN@\D6

*. ./C 0C
;>;6.0WW ?@W AWD>F0$L?362 ^b?C*0X'GEU&X9t9r$6rD   r%   c                       e Zd ZdZdZd Zy)r   a4   Contains the locally cached MyPlex account information. The properties provided don't
        match the :class:`~plexapi.myplex.MyPlexAccount` object very well. I believe this exists
        because access to myplex is not required to get basic plex information. I can't imagine
        object is terribly useful except unless you were needed this information while offline.

        Parameters:
            server (:class:`~plexapi.server.PlexServer`): PlexServer this account is connected to (optional)
            data (ElementTree): Response from PlexServer used to build this object (optional).

        Attributes:
            authToken (str): Plex authentication token to access the server.
            mappingError (str): Unknown
            mappingErrorMessage (str): Unknown
            mappingState (str): Unknown
            privateAddress (str): Local IP address of the Plex server.
            privatePort (str): Local port of the Plex server.
            publicAddress (str): Public IP address of the Plex server.
            publicPort (str): Public port of the Plex server.
            signInState (str): Signin state for this account (ex: ok).
            subscriptionActive (str): True if the account subscription is active.
            subscriptionFeatures (str): List of features allowed by the server for this account.
                This may be based on your PlexPass subscription. Features include: camera_upload,
                cloudsync, content_filter, dvr, hardware_transcoding, home, lyrics, music_videos,
                pass, photo_autotags, premium_music_metadata, session_bandwidth_restrictions,
                sync, trailers, webhooks' (and maybe more).
            subscriptionState (str): 'Active' if this subscription is active.
            username (str): Plex account username (user@example.com).
    z/myplex/accountc                    || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _	        |j                  j                  d      | _
        |j                  j                  d	      | _        |j                  j                  d
      | _        t        j                  |j                  j                  d            | _        t        j                   t"        |j                  j                  d            | _        |j                  j                  d      | _        y )N	authTokenusernamemappingStatemappingErrormappingErrorMessagesignInStatepublicAddress
publicPortprivateAddressprivatePortsubscriptionFeaturessubscriptionActivesubscriptionState)ro   rr   r+   r  r  r  r  r  r  r  r  r  r  r   rs   r  rp   rq   r  r  rv   s     rC   rw   zAccount._loadDataG  s0   
5
3 KKOON; KKOON;#';;??3H#I ;;??=9![[___=++//,7"kkoo.>?;;??=9$)LLAW1X$Y!"'**T4;;??CW3X"Y!%1D!ErD   NrX  r  r  r  r:   rw   rV  rD   rC   r   r   (  s    8 CFrD   r   c                       e Zd ZdZdZd Zy)r   z/A currently running activity on the PlexServer.z/activitiesc                    || _         t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _	        |j                  j                  d      | _
        |j                  j                  d      | _        |j                  j                  d      | _        y )Ncancellableprogressr   subtitler   uuid)ro   r   rp   rq   rr   r+   r  rt   r  r   r  r   r  rv   s     rC   rw   zActivity._loadData\  s    
 ::dDKKOOM,JK

3
(CD[[__W-

3KKOOF+	KKOOF+	rD   Nr  rV  rD   rC   r   r   X  s    9
C,rD   r   c                       e Zd Zd ZdZd Zy)Releaser  c                    |j                   j                  d      | _        |j                   j                  d      | _        |j                   j                  d      | _        |j                   j                  d      | _        |j                   j                  d      | _        |j                   j                  d      | _        y )Nr:   rm   addedfixeddownloadURLstate)rr   r+   download_keyrm   r  r  r  r  rv   s     rC   rw   zRelease._loadDatak  s|     KKOOE2{{y1[[__W-
[[__W-
;;??=9[[__W-
rD   N)rX  r  r  TAGr:   rw   rV  rD   rC   r  r  f  s    
C
C.rD   r  c                       e Zd ZdZdZd Zy)r   a   Represents a single system account.

        Attributes:
            TAG (str): 'Account'
            autoSelectAudio (bool): True or False if the account has automatic audio language enabled.
            defaultAudioLanguage (str): The default audio language code for the account.
            defaultSubtitleLanguage (str): The default subtitle language code for the account.
            id (int): The Plex account ID.
            key (str): API URL (/accounts/<id>)
            name (str): The username of the account.
            subtitleMode (bool): The subtitle mode for the account.
            thumb (str): URL for the account thumbnail.
    r   c                    || _         t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _
        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        | j                  | _        | j                  | _        y )	NautoSelectAudiodefaultAudioLanguagedefaultSubtitleLanguager   r:   r   subtitleModethumb)ro   r   rp   rq   rr   r+   r  r  r  rt   r   r:   r   r  r  r   
accountKeyrv   s     rC   rw   zSystemAccount._loadData  s    
$zz$@Q0RS$(KKOO4J$K!'+{{7P'Q$**S$++//$"78;;??5)KKOOF+	!JJsDKKOON,KL[[__W-
((rD   NrX  r  r  r  r  rw   rV  rD   rC   r   r   t  s     C#rD   r   c                       e Zd ZdZdZd Zy)r   a   Represents a single system device.

        Attributes:
            TAG (str): 'Device'
            clientIdentifier (str): The unique identifier for the device.
            createdAt (datetime): Datetime the device was created.
            id (int): The ID of the device (not the same as :class:`~plexapi.myplex.MyPlexDevice` ID).
            key (str): API URL (/devices/<id>)
            name (str): The name of the device.
            platform (str): OS the device is running (Linux, Windows, Chrome, etc.)
    Devicec                    || _         |j                  j                  d      | _        t	        j
                  |j                  j                  d            | _        t	        j                  t        |j                  j                  d            | _	        d| j                   | _
        |j                  j                  d      | _        |j                  j                  d      | _        y )Nr   	createdAtr   z	/devices/r   r[   )ro   rr   r+   r   r   ru   r  rp   rt   r   r:   r   r[   rv   s     rC   rw   zSystemDevice._loadData  s    
 $0B C))$++//+*FG**S$++//$"78twwi(KKOOF+	
3rD   Nr  rV  rD   rC   r   r     s    
 C4rD   r   c                   ,    e Zd ZdZd Zd Zd Zd Zd Zy)r  a   Represents a single statistics bandwidth data.

        Attributes:
            TAG (str): 'StatisticsBandwidth'
            accountID (int): The associated :class:`~plexapi.server.SystemAccount` ID.
            at (datetime): Datetime of the bandwidth data.
            bytes (int): The total number of bytes for the specified time span.
            deviceID (int): The associated :class:`~plexapi.server.SystemDevice` ID.
            lan (bool): True or False whether the bandwidth is local or remote.
            timespan (int): The time span for the bandwidth data.
                1: months, 2: weeks, 3: days, 4: hours, 6: seconds.

    c                    || _         t        j                  t        |j                  j                  d            | _        t        j                  |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _	        t        j                  t        |j                  j                  d            | _
        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        y )Nr   r  r  r   r  r  )ro   r   rp   rt   rr   r+   r   ru   r  r  r   rq   r  r  rv   s     rC   rw   zStatisticsBandwidth._loadData  s    
C)EF""4;;??4#89ZZT[[__W%=>


3
(CD::dDKKOOE$:;

3
(CDrD   c                 `   dj                  dj                  | j                  j                  | j	                  | j
                        | j	                  | j                        | j	                  t        | j                  j                                     fD cg c]  }|r| c}            S c c}w )Nz<{}>r   )
r  r  rB   rX  _cleanr   r   rt   r  r/  r=   r   s     rC   __repr__zStatisticsBandwidth.__repr__  s    }}HH''DNN+DMM*C 1 1 345	" A
    
 	
s   B+c                 L    | j                   j                  | j                        S )zX Returns the :class:`~plexapi.server.SystemAccount` associated with the bandwidth data. )rB  r   r   r   s    rC   r   zStatisticsBandwidth.account  s    ||))$..99rD   c                 L    | j                   j                  | j                        S )zW Returns the :class:`~plexapi.server.SystemDevice` associated with the bandwidth data. )rB  r   r   r   s    rC   r   zStatisticsBandwidth.device  s    ||((77rD   N)	rX  r  r  r  r  rw   r  r   r   rV  rD   rC   r  r    s#      CE
:8rD   r  c                        e Zd ZdZd Zd Zd Zy)r  a    Represents a single statistics resources data.

        Attributes:
            TAG (str): 'StatisticsResources'
            at (datetime): Datetime of the resource data.
            hostCpuUtilization (float): The system CPU usage %.
            hostMemoryUtilization (float): The Plex Media Server CPU usage %.
            processCpuUtilization (float): The system RAM usage %.
            processMemoryUtilization (float): The Plex Media Server RAM usage %.
            timespan (int): The time span for the resource data (6: seconds).
    c                    || _         t        j                  |j                  j	                  d            | _        t        j                  t        |j                  j	                  d            | _        t        j                  t        |j                  j	                  d            | _	        t        j                  t        |j                  j	                  d            | _
        t        j                  t        |j                  j	                  d            | _        t        j                  t        |j                  j	                  d            | _        y )Nr  hostCpuUtilizationhostMemoryUtilizationprocessCpuUtilizationprocessMemoryUtilizationr  )ro   r   ru   rr   r+   r  rp   floatr  r  r  r   rt   r  rv   s     rC   rw   zStatisticsResources._loadData  s    
""4;;??4#89"'**UDKKOODX4Y"Z%*ZZt{{G^7_%`"%*ZZt{{G^7_%`"(-

5$++//Jd:e(f%

3
(CDrD   c           
          ddj                  | j                  j                  | j                  t	        | j
                  j                                     fD cg c]  }|s|	 c}       dS c c}w N<r   >)r  rB   rX  r  rt   r  r/  r  s     rC   r  zStatisticsResources.__repr__  sZ    388)@)@$++cRVRYRYRcRcReNfBg(hn1lmQnoppqrrns   A-
A-
N)rX  r  r  r  r  rw   r  rV  rD   rC   r  r    s    
  CEsrD   r  c                       e Zd ZdZd Zd Zy)
ButlerTaska   Represents a single scheduled butler task.

        Attributes:
            TAG (str): 'ButlerTask'
            description (str): The description of the task.
            enabled (bool): Whether the task is enabled.
            interval (int): The interval the task is run in days.
            name (str): The name of the task.
            scheduleRandomized (bool): Whether the task schedule is randomized.
            title (str): The title of the task.
    c                 "   || _         |j                  j                  d      | _        t	        j
                  t        |j                  j                  d            | _        t	        j
                  t        |j                  j                  d            | _	        |j                  j                  d      | _
        t	        j
                  t        |j                  j                  d            | _        |j                  j                  d      | _        y )Ndescriptionenabledintervalr   scheduleRandomizedr   )ro   rr   r+   r	  r   rp   rq   r
  rt   r  r   r  r   rv   s     rC   rw   zButlerTask._loadData  s    
;;??=9zz$	(BC

3
(CDKKOOF+	"'**T4;;??CW3X"Y[[__W-
rD   Nr  rV  rD   rC   r  r    s    
 C.rD   r  c                       e Zd ZdZd Zd Zy)r   z Represents a server identity.

        Attributes:
            claimed (bool): True or False if the server is claimed.
            machineIdentifier (str): The Plex server machine identifier.
            version (str): The Plex server version.
    c                 P    d| j                   j                   d| j                   dS r  )rB   rX  rR   r   s    rC   r  zIdentity.__repr__  s)    4>>**+1T-C-C,DAFFrD   c                    || _         t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        y )NclaimedrR   rm   )	ro   r   rp   rq   rr   r+   r  rR   rm   rv   s     rC   rw   zIdentity._loadData  sR    
zz$	(BC!%1D!E{{y1rD   N)rX  r  r  r  r  rw   rV  rD   rC   r   r     s    G2rD   r   )Er   	functoolsr   urllib.parser   	xml.etreer   r2   plexapir   r   r   r	   r
   r   plexapi.alertr   plexapi.baser   plexapi.clientr   plexapi.collectionr   plexapi.exceptionsr   r   r   plexapi.libraryr   r   r   r   plexapi.mediar   r   plexapi.playlistr   plexapi.playqueuer   plexapi.settingsr   plexapi.utilsr   requests.status_codesr   r[  r   _audior   _collectionr    _mediar!   _photor"   	_playlistr#   _videor%   r   r   registerPlexObjectr  r   r   r  r  r  r   rV  rD   rC   <module>r(     s   	 % " !  A A  ' # % ) A A 4 4 / % ' % $ 1 $ - # # ) #D6 D6N -Fj -F`,z , 
.j 
. 
.#J #>4: 40)8* )8Xs* s6 . . .02z 2rD   