
    gm                         d dl Z d dlZd dlmZ d dlZd dlmZmZmZm	Z	m
Z
mZ d dlmZ d dlmZmZmZmZ d dlmZ d dlmZ dZej2                   G d	 d
e             Z G d de      Zy)    N)ElementTree)BASE_HEADERSCONFIGTIMEOUTlog	logfilterutils)
PlexObject)
BadRequestNotFoundUnauthorizedUnsupported)	PlayQueue)_codesvideoc                       e Zd ZdZdZdZ	 	 	 d4 fd	Zd Zd5dZd Z	d	 Z
d
 Zd6dZd7dZd5dZd8dZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZefdZ efdZ!efd Z"efd!Z#efd"Z$efd#Z%efd$Z&efd%Z'efd&Z(efd'Z)efd(Z*efd)Z+efd*Z,efd+Z-efd,Z.efd-Z/d9d.Z0dddefd/Z1dddefd0Z2d9d1Z3e4d2        Z5d:d3Z6 xZ7S );
PlexClientah
   Main class for interacting with a Plex client. This class can connect
        directly to the client and control it or proxy commands through your
        Plex Server. To better understand the Plex client API's read this page:
        https://github.com/plexinc/plex-media-player/wiki/Remote-control-API

        Parameters:
            server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional).
            data (ElementTree): Response from PlexServer used to build this object (optional).
            initpath (str): Path used to generate data.
            baseurl (str): HTTP URL to connect directly to this client.
            identifier (str): The resource/machine identifier for the desired client.
                May be necessary when connecting to a specific proxied client (optional).
            token (str): X-Plex-Token used for authentication (optional).
            session (:class:`~requests.Session`): requests.Session object if you want more control (optional).
            timeout (int): timeout in seconds on initial connect to client (default config.TIMEOUT).

        Attributes:
            TAG (str): 'Player'
            key (str): '/resources'
            device (str): Best guess on the type of device this is (PS, iPhone, Linux, etc).
            deviceClass (str): Device class (pc, phone, etc).
            machineIdentifier (str): Unique ID for this device.
            model (str): Unknown
            platform (str): Unknown
            platformVersion (str): Description
            product (str): Client Product (Plex for iOS, etc).
            protocol (str): Always seems ot be 'plex'.
            protocolCapabilities (list<str>): List of client capabilities (navigation, playback,
                timeline, mirror, playqueues).
            protocolVersion (str): Protocol version (1, future proofing?)
            server (:class:`~plexapi.server.PlexServer`): Server this client is connected to.
            session (:class:`~requests.Session`): Session object used for connection.
            state (str): Unknown
            title (str): Name of this client (Johns iPhone, etc).
            token (str): X-Plex-Token used for authentication
            vendor (str): Unknown
            version (str): Device version (4.6.1, etc).
            _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.
            _proxyThroughServer (bool): Set to True after calling
                :func:`~plexapi.client.PlexClient.proxyThroughServer` (default False).
    Playerz
/resourcesNc                    t         t        |   |||       |r|j                  d      nd | _        || _        t        j                  |      | _        t        j                  dd      j                         dk(  | _        |r|j                  nd }|xs |xs t        j                         | _        |	xs t         | _        d| _        d| _        d| _        g | _        d| _        |
t/        j0                  |
      nd | _        t5        |d u|||g      sHt        j                  dd      | _        t        j                  t        j                  d	            | _        |r | j                  r| j7                  |	
       y y y )N/zlog.show_secrets trueFr   zauth.client_baseurlzhttp://localhost:32433zauth.client_tokentimeout)superr   __init__strip_baseurl_clientIdentifierr   
add_secret_tokenr   getlower_showSecrets_sessionrequestsSessionr   _timeout_proxyThroughServer
_commandId
_last_call_timeline_cache_timeline_cache_timestampweakrefref_parentanyconnect)selfserverdatainitpathbaseurl
identifiertokenr2   sessionr   parentserver_session	__class__s               #/opt/Tautulli/lib/plexapi/client.pyr   zPlexClient.__init__A   s<    	j$(x@.5c*4!+**51"JJ'92>DDF&P,2G>GX5E5E5G*7#( !)*&.4.@w{{6*dD$h?@"JJ'<>VWDM#..vzz:M/NODKt}}LLL) %7    c                 D    | xj                   dz  c_         | j                   S )N   )r*   r3   s    r>   _nextCommandIdzPlexClient._nextCommandIdX   s    1r?   c                      j                   st        d       j                    _         j                   j                   |      }|t	        d j
                          j                  r<t         fd|D        d      }|*t	        d j                   d j
                         |d   } j                  |        S )	z Alias of reload as any subsequent requests to this client will be
            made directly to the device even if the object attributes were initially
            populated from a PlexServer.
        z-Cannot reload an object not built from a URL.r   NzClient not found at c              3   r   K   | ].  }|j                   j                  d       j                  k(  r| 0 yw)machineIdentifierN)attribr"   r   ).0xr3   s     r>   	<genexpr>z%PlexClient.connect.<locals>.<genexpr>i   s5      xx||$78D<R<RR s   47zClient with identifier z not found at r   )	keyr   	_initpathqueryr   r   r   next	_loadData)r3   r   r5   clients   `   r>   r2   zPlexClient.connect\   s    
 xxMNNzz$((Gz4<1$--ABB!!!
 F ~-d.D.D-E^TXTaTaSbc  !WFvr?   c                 "    | j                         S )z Alias to self.connect(). )r2   rB   s    r>   reloadzPlexClient.reloady   s    ||~r?   c                 B   || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  dd      j                  d      | _        |j                  j                  d      | _	        |j                  j                  d	      | _
        |j                  j                  d
      | _        |j                  j                  d      xs |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        t'        j(                  t*        |j                  j                  dd            | _        t'        j(                  t*        |j                  j                  dd            | _        t'        j(                  t*        |j                  j                  dd            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        y)z/ Load attribute values from Plex XML response. deviceClassrF   productprotocolprotocolCapabilitiesr   ,protocolVersionplatformplatformVersiontitlenamedeviceprofilemodelstatevendorversionlocalr   relayedsecureaddressremotePublicAddressuserIDN)_datarG   r"   rT   rF   rU   rV   splitrW   rY   rZ   r[   r\   r^   r_   r`   ra   rb   rc   r	   castboolrd   re   rf   rg   rh   ri   r3   r5   s     r>   rO   zPlexClient._loadData}   s   
;;??=9!%1D!E{{y1
3$(KKOO4JB$O$U$UVY$Z!#{{/@A
3#{{/@A[[__W-H1H
 kkooh/{{y1[[__W-
[[__W-
kkooh/{{y1ZZdkkoogq&AB
zz$	1(EFjjt{{x'CD{{y1#';;??3H#I kkooh/r?   c                 j    t         }| j                  r| j                  |d<   |j                  |       |S )z< Returns a dict of all default headers for Client requests. zX-Plex-Token)r   r!   update)r3   kwargsheaderss      r>   _headerszPlexClient._headers   s-    ;;&*kkGN#vr?   c                 Z    |r|| _         |du r| j                   st        d      || _        y)a   Tells this PlexClient instance to proxy all future commands through the PlexServer.
            Useful if you do not wish to connect directly to the Client device itself.

            Parameters:
                value (bool): Enable or disable proxying (optional, default True).

            Raises:
                :exc:`~plexapi.exceptions.Unsupported`: Cannot use client proxy with unknown server.
        Tz,Cannot use client proxy with unknown server.N)_serverr   r)   )r3   valuer4   s      r>   proxyThroughServerzPlexClient.proxyThroughServer   s/     !DLD=LMM#( r?   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 client. 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)rr   r   )         r   
 (z) z; i  i  utf8N )urlr%   r"   r(   r   debug__name__upperrs   status_codecodestextreplacer   r   r   r	   cleanXMLStringencoder   r   
fromstring)r3   pathmethodrr   r   rq   r   responsecodenameerrtextmessager5   s               r>   rM   zPlexClient.query   s]   
 hhtn,4==,,*T]]		'6??002C8$--0'-R0#JwJ6J6yy!5!56q9Hmm++D#6G(../r(2hll^1WIVG##s*"7++%%,w'' ))##HMM299&A/3zz|{%%d+EEr?   c                    |j                  d      }|j                  d      d   }d| j                  i}|| j                  vr!t	        j
                  d| j                  |       || j                  n|}|r| j                  j                  n| j                  }t        j                         }|dk(  r|| _        nH|| j                  z
  dk\  r6| j                  dv r(|| _        | j                  t        j                  d	       | j!                         |d
<   d| t#        j$                  |       }	  |||      S # t&        j(                  $ r | j                  dv rY y w xY w)aw   Convenience wrapper around :func:`~plexapi.client.PlexClient.query` to more easily
            send simple commands to the client. Returns an ElementTree object containing
            the response.

            Parameters:
                command (str): Command to be sent in for format '<controller>/<command>'.
                proxy (bool): Set True to proxy this command through the PlexServer.
                **params (dict): Additional GET parameters to include with the command.

            Raises:
                :exc:`~plexapi.exceptions.Unsupported`: When we detect the client doesn't support this capability.
        r   r   zX-Plex-Target-Client-IdentifierzHClient %s doesn't support %s controller. What your trying might not workNtimeline/pollP   )ptpzPlex Media Playerwait	commandIDz/player/)rr   )PlexampzPlex for Android (TV)zPlex for Android (Mobile)zPlex for Samsung)r   rk   rF   rW   r   r   r\   r)   ru   rM   timer+   rU   sendCommandClientTimelinerK   rC   r	   joinArgsr   
ParseError)	r3   commandproxyparams
controllerrr   rM   trK   s	            r>   r   zPlexClient.sendCommand   sL    --$]]3'*
4d6L6LMT666II`bfblblnxy,1M((u&+"" IIKo%DO B&4<<;W+WDO^//a8"113{	%.."8!9:	g..%% 	 ||    	s   .	D8 8!EEc                     | j                   st        d      | 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"PlexClient object missing baseurl.?&zX-Plex-Token=)r   r   r!   r$   )r3   rK   includeTokendelims       r>   r   zPlexClient.url   si     }}ABB;;LD,=,=#:C3Emm_SE%dkk]KK--&&r?   c                 &    | j                  d       y)z& Open the context menu on the client. znavigation/contextMenuNr   rB   s    r>   contextMenuzPlexClient.contextMenu	  s    12r?   c                 &    | j                  d       y)z Navigate back one position. znavigation/backNr   rB   s    r>   goBackzPlexClient.goBack      *+r?   c                 &    | j                  d       y)z! Go directly to the home screen. znavigation/homeNr   rB   s    r>   goToHomezPlexClient.goToHome  r   r?   c                 &    | j                  d       y)z) Go directly to the playing music panel. znavigation/musicNr   rB   s    r>   	goToMusiczPlexClient.goToMusic  s    +,r?   c                 &    | j                  d       y)z! Move selection down a position. znavigation/moveDownNr   rB   s    r>   moveDownzPlexClient.moveDown      ./r?   c                 &    | j                  d       y)z! Move selection left a position. znavigation/moveLeftNr   rB   s    r>   moveLeftzPlexClient.moveLeft  r   r?   c                 &    | j                  d       y)z" Move selection right a position. znavigation/moveRightNr   rB   s    r>   	moveRightzPlexClient.moveRight!      /0r?   c                 &    | j                  d       y)z Move selection up a position. znavigation/moveUpNr   rB   s    r>   moveUpzPlexClient.moveUp%      ,-r?   c                 &    | j                  d       y)z& Jump to next letter in the alphabet. znavigation/nextLetterNr   rB   s    r>   
nextLetterzPlexClient.nextLetter)  s    01r?   c                 &    | j                  d       y)z" Move selection down a full page. znavigation/pageDownNr   rB   s    r>   pageDownzPlexClient.pageDown-  r   r?   c                 &    | j                  d       y)z  Move selection up a full page. znavigation/pageUpNr   rB   s    r>   pageUpzPlexClient.pageUp1  r   r?   c                 &    | j                  d       y)z* Jump to previous letter in the alphabet. znavigation/previousLetterNr   rB   s    r>   previousLetterzPlexClient.previousLetter5  s    45r?   c                 &    | j                  d       y)z) Select element at the current position. znavigation/selectNr   rB   s    r>   selectzPlexClient.select9  r   r?   c                 &    | j                  d       y)z/ Toggle the on screen display during playback. znavigation/toggleOSDNr   rB   s    r>   	toggleOSDzPlexClient.toggleOSD=  r   r?   c                 4   |j                   j                  j                  d      }|j                   j                  |d   j	                  d      |d   |j
                  |d   d|}|j                   j                         }|r||d<    | j                  d	i | y)
z Navigate directly to the specified media page.

            Parameters:
                media (:class:`~plexapi.media.Media`): Media object to navigate to.
                **params (dict): Additional GET parameters to include with the command.
        :rA   r   r   )rF   rg   portrK   rV   r9   N)zmirror/details)ru   r   rk   rF   r   rK   createTokenr   )r3   mediar   
server_urlr   r9   s         r>   	goToMediazPlexClient.goToMediaA  s     ]]++11#6
!&!@!@!!}**3/rN99"1
 
 ))+$GG5W5r?   c                 *    | j                  d|       y)z Pause the currently playing media type.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/pausetypeNr   r3   mtypes     r>   pausezPlexClient.pause]  s     	)6r?   c                 *    | j                  d|       y)z Start playback for the specified media type.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/playr   Nr   r   s     r>   playzPlexClient.playe       	u5r?   c                 ,    | j                  d||       y)z Refresh the specified Playqueue.

            Parameters:
                playQueueID (str): Playqueue ID.
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/refreshPlayQueue)playQueueIDr   Nr   )r3   r   r   s      r>   refreshPlayQueuezPlexClient.refreshPlayQueuem  s     	'[u 	 	Nr?   c                 ,    | j                  d||       y)z Seek to the specified offset (ms) during playback.

            Parameters:
                offset (int): Position to seek to (milliseconds).
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/seekTo)offsetr   Nr   )r3   r   r   s      r>   seekTozPlexClient.seekTow  s     	*6Fr?   c                 *    | j                  d|       y)z Skip to the next playback item.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/skipNextr   Nr   r   s     r>   skipNextzPlexClient.skipNext       	,59r?   c                 *    | j                  d|       y)z Skip to previous playback item.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/skipPreviousr   Nr   r   s     r>   skipPreviouszPlexClient.skipPrevious  s     	0u=r?   c                 ,    | j                  d||       y)z Skip to the playback item with the specified key.

            Parameters:
                key (str): Key of the media item to skip to.
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/skipTo)rK   r   Nr   )r3   rK   r   s      r>   skipTozPlexClient.skipTo  s     	*%@r?   c                 *    | j                  d|       y)z Step backward a chunk of time in the current playback item.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/stepBackr   Nr   r   s     r>   stepBackzPlexClient.stepBack  r   r?   c                 *    | j                  d|       y)z Step forward a chunk of time in the current playback item.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/stepForwardr   Nr   r   s     r>   stepForwardzPlexClient.stepForward  s     	/e<r?   c                 *    | j                  d|       y)z Stop the currently playing item.

            Parameters:
                mtype (str): Media type to take action against (music, photo, video).
        zplayback/stopr   Nr   r   s     r>   stopzPlexClient.stop  r   r?   c                 *    | j                  ||       y)z Enable repeat for the specified playback items.

            Parameters:
                repeat (int): Repeat mode (0=off, 1=repeatone, 2=repeatall).
                mtype (str): Media type to take action against (music, photo, video).
        )repeatr   NsetParameters)r3   r   r   s      r>   	setRepeatzPlexClient.setRepeat       	&6r?   c                 *    | j                  ||       y)z Enable shuffle for the specified playback items.

            Parameters:
                shuffle (int): Shuffle mode (0=off, 1=on)
                mtype (str): Media type to take action against (music, photo, video).
        )shuffler   Nr   )r3   r   r   s      r>   
setShufflezPlexClient.setShuffle  s     	7%8r?   c                 *    | j                  ||       y)z Enable volume for the current playback item.

            Parameters:
                volume (int): Volume level (0-100).
                mtype (str): Media type to take action against (music, photo, video).
        )volumer   Nr   )r3   r   r   s      r>   	setVolumezPlexClient.setVolume  r   r?   c                 *    | j                  ||       y)a   Select the audio stream for the current playback item (only video).

            Parameters:
                audioStreamID (str): ID of the audio stream from the media object.
                mtype (str): Media type to take action against (music, photo, video).
        )audioStreamIDr   N
setStreams)r3   r   r   s      r>   setAudioStreamzPlexClient.setAudioStream       	m5Ar?   c                 *    | j                  ||       y)a   Select the subtitle stream for the current playback item (only video).

            Parameters:
                subtitleStreamID (str): ID of the subtitle stream from the media object.
                mtype (str): Media type to take action against (music, photo, video).
        )subtitleStreamIDr   Nr   )r3   r  r   s      r>   setSubtitleStreamzPlexClient.setSubtitleStream  s     	)9Gr?   c                 *    | j                  ||       y)a   Select the video stream for the current playback item (only video).

            Parameters:
                videoStreamID (str): ID of the video stream from the media object.
                mtype (str): Media type to take action against (music, photo, video).
        )videoStreamIDr   Nr   )r3   r  r   s      r>   setVideoStreamzPlexClient.setVideoStream  r   r?   c                    |j                   j                  j                  d      }|d   j                  d      }t	        |d      r|j
                  }n6t        |t              r|j                  d   j                  }n|j                  }|dk(  rd}t        |t              r|n|j                   j                  |      }d|j                   j                  |d   |d	   j                  d      |||j                  xs |j                  j                  |d
|j                   dd	|}|j                   j                         }	|	r|	|d<    | j                   di | y)aZ   Start playback of the specified media item. See also:

            Parameters:
                media (:class:`~plexapi.media.Media`): Media item to be played back
                    (movie, music, photo, playlist, playqueue).
                offset (int): Number of milliseconds at which to start playing with zero
                    representing the beginning (default 0).
                **params (dict): Optional additional parameters to include in the playback request. See
                    also: https://github.com/plexinc/plex-media-player/wiki/Remote-control-API#modified-commands
        r   r   r   playlistTyper   audiomusiczcom.plexapp.plugins.libraryrA   z/playQueues/z?window=100&own=1)	providerIdentifierrF   rV   rg   r   r   rK   r   containerKeyr9   N)zplayback/playMedia)ru   r   rk   r   hasattrr  
isinstancer   itemslistTypecreatePlayQueuerF   rK   selectedItemr   r   r   )
r3   r   r   r   r   server_port	mediatype	playqueuer   r9   s
             r>   	playMediazPlexClient.playMedia  s?    ]]++11#6
 n**3/5.)**I%+!KKN33	!NN	 I'y9Eu}}?\?\]b?c	"?!&!@!@"1!!}**3/99:	 6 6 : :*9+@+@*AARS
 
 ))+$GG99r?   c                 d    i }|||d<   |||d<   |||d<   |||d<    | j                   di | y)a   Set multiple playback parameters at once.

            Parameters:
                volume (int): Volume level (0-100; optional).
                shuffle (int): Shuffle mode (0=off, 1=on; optional).
                repeat (int): Repeat mode (0=off, 1=repeatone, 2=repeatall; optional).
                mtype (str): Media type to take action against (optional music, photo, video).
        Nr   r   r   r   )zplayback/setParametersr   )r3   r   r   r   r   r   s         r>   r   zPlexClient.setParameters  s[     %F8 'F9%F8"F6N<V<r?   c                 d    i }|||d<   |||d<   |||d<   |||d<    | j                   di | y)a   Select multiple playback streams at once.

            Parameters:
                audioStreamID (str): ID of the audio stream from the media object.
                subtitleStreamID (str): ID of the subtitle stream from the media object.
                videoStreamID (str): ID of the video stream from the media object.
                mtype (str): Media type to take action against (optional music, photo, video).
        Nr   r  r  r   )zplayback/setStreamsr   )r3   r   r  r  r   r   s         r>   r   zPlexClient.setStreams(  s\     $&3F?#')9F%&$&3F?#"F6N9&9r?   c                    t        j                          }|| j                  z
  dkD  rK|| _        | j                  t        j                  |      xs g }|D cg c]  }t        | |       c}| _        | j
                  S c c}w )zPoll the client's timelines, create, and return timeline objects.
           Some clients may not always respond to timeline requests, believe this
           to be a Plex bug.
        rA   r   )r   r-   r   r   rK   r,   )r3   r   r   	timelinesr5   s        r>   r  zPlexClient.timelines>  sv    
 IIKt---1-.D*((););$(GM2IKT#U4N4$>#UD ### $Vs   A>c                 D    t        d | j                         D        d      S )z#Returns the active timeline object.c              3   @   K   | ]  }|j                   d k7  s|  yw)stoppedN)ra   )rH   rI   s     r>   rJ   z&PlexClient.timeline.<locals>.<genexpr>N  s     I1AGGy4HQIs   N)rN   r  rB   s    r>   timelinezPlexClient.timelineK  s     I 0I4PPr?   c                 b    t        | j                  dd      }t        |dk(  xs	 |xr |dk(        S )zReturns True if any media is currently playing.

            Parameters:
                includePaused (bool): Set True to treat currently paused items
                                      as playing (optional; default True).
        ra   Nplayingpaused)getattrr  rm   )r3   includePausedra   s      r>   isPlayingMediazPlexClient.isPlayingMediaP  s5     w5EY&O=+NUh=NPPr?   )
NNNNNNTNNN)N)TN)NNN)F)r   )T)8r   
__module____qualname____doc__TAGrK   r   rC   r2   rR   rO   rs   rw   rM   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   DEFAULT_MTYPEr   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r   r   r  propertyr  r#  __classcell__)r=   s   @r>   r   r      s   *V C
CFJKO*.:0<) F0.`	'3,,-001.20.6.168 ( 7 ' 6 3@ N $1 G + : "/ > !. A + : !. = ' 6 '4 7 )6 9 '4 7 3@ B 9F H 3@ B+:Z $(d- =( (,dRV^k :,$ Q QQr?   r   c                       e Zd ZdZdZd Zy)r   zGet the timeline's attributes.r   c                 "
   || _         |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      | _        |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            | _        t	        j
                  t        |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            | _        t	        j
                  t        |j                  j                  d            | _        |j                  j                  d      | _        t	        j
                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        t	        j
                  t        |j                  j                  d            | _         t	        j
                  t        |j                  j                  d            | _!        |j                  j                  d      | _"        t	        j
                  t        |j                  j                  d            | _#        y )Nrg   audioStreamIdautoPlayr  controllabledurationitemTyperK   locationrF   	partCount	partIndexr   playQueueItemIDplayQueueVersionr   rV   r
  	ratingKeyr   	seekRanger   ra   subtitleColorsubtitlePositionsubtitleSizer   r   r   )$rj   rG   r"   rg   r	   rl   intr-  rm   r.  r  r/  r0  r1  rK   r2  rF   r3  r4  r   r5  r6  r   rV   r
  r7  r   r8  r   ra   r9  r:  r;  r   r   r   rn   s     r>   rO   zClientTimeline._loadData`  s   
{{y1"ZZT[[___-MN

4)DE KKOON; KKOON;

3
(CD
3;;??5)
3!%1D!EC)EFC)EF ::c4;;??=+IJ$zz#t{{?P/QR %

3@R0S TJJsDKKOOF$;<	
3"&++//2F"GC)EFjjdkkooh&?@5zz$	(BC[[__W-
![[___= $0B C!JJsDKKOON,KLJJsDKKOOF$;<	KKOOF+	jjdkkooh&?@r?   N)r   r$  r%  r&  rK   rO   r   r?   r>   r   r   [  s    (
CAr?   r   )r   r.   	xml.etreer   r&   plexapir   r   r   r   r   r	   plexapi.baser
   plexapi.exceptionsr   r   r   r   plexapi.playqueuer   requests.status_codesr   r   r(  registerPlexObjectr   r   r   r?   r>   <module>rD     sa      !  H H # N N ' 1 F	Q F	Q F	QR#AZ #Ar?   