
    :jS                       d Z ddlmZ ddlmZ ddlmZ ddlZddlZddl	m
Z
mZmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZ ddlmZmZ ddlmZ ddlmZ e
rddlmZ ddlm Z  ddl!m"Z" ddl#m$Z$ dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/dZ0d Z1d!Z2d"Z3d#Z4d$Z5ddddd%d%d&d&d%d'd%d%d(d%de&d)d*ddd%ddddd+fdZdQZ6 G dR dSe          Z7e8d[dU            Z9 G dV dWe          Z: G dX dYe:          Z;dS )\z,
Controller to interface with the Plex-app.
    )annotations)deepcopy)partialN)TYPE_CHECKINGAnycast)urlparse   )CallbackTypeBaseController)MediaStatus   )MESSAGE_TYPE)ControllerNotRegisteredRequestFailed)CastMessage)chain_on_success)Playable)Media)	PlayQueue)
PlexServerUNKNOWNBUFFEREDLIVEcurrentTimePLAYPAUSESTOPSTEPFORWARDSTEPBACKPREVIOUSNEXTLOADSHOWDETAILSSEEKMEDIA_STATUS
GET_STATUSEDIT_TRACKS_INFOTd   Fvideoi~  httpz1.10.1.4602mediaPlayable | Nonetypestr	requestIdintoffset
directPlaybooldirectStreamsubtitleSize
audioBoosttranscoderVideotranscoderVideoRemuxOnlytranscoderAudioisVerifiedHostnamecontentTypemyPlexSubscription	contentId
str | None
streamTypeportprotocoladdressusernameautoplay	playQueuePlayQueue | NoneplayQueueID
int | None	startItemMedia | Noneversionkwargsr   returndict[str, Any]c                F   d}d}| t          | t                    r| d         j        n| j        }t          |j                  }|j        }|j        }|j        }|j        }|j	        }|j
        }|j        }t          | dd          dk    r|r| j        } n| }||                    | |          }|j        }|j        j        }|j        d         j        }|j        }|dk    r|}|||||||||||||	|
|||||||d|idd| d	d
||ddd}|                    |           |S )a  Create the message that chromecast requires. Use pass of plexapi media object or
       set all the needed kwargs manually. See the code for what to set.

    Args:
        media (None, optional): a :class:`~plexapi.base.Playable
        type (str): Default LOAD, SHOWDETAILS.
        requestId (int): The requestId, Chromecasts may use this.
        offset (int): Offset of the playback in seconds.
        directPlay (bool): Default True
        directStream (bool): Default True
        subtitleSize (int): Set the subtitle size, possibly only 100 & 200.
        audioBoost (int): Default 100
        transcoderVideo (bool): Default True
        transcoderVideoRemuxOnly (bool): Default False
        transcoderAudio (bool): Default True
        isVerifiedHostname (bool): Default True
        contentType (str): Default 'video', 'audio'
        myPlexSubscription (bool): True if user has a PlexPass.
        contentId (str): The key Chromecasts use to start playback.
        streamType (str): Default BUFFERED, LIVE
        port (int): PMS port
        address (str): PMS host, without scheme.
        username (None): Username of the user that started playback.
        autoplay (bool): Auto play after the video is done.
        currentTime (int): Set playback from this time. default 0
        version (str): PMS version. Default 1.10.1.4602
        startItem (:class:`~plexapi.media.Media`, optional): Media item in list/playlist/playqueue where playback should
                                                             start. Overrides existing startItem for playqueues if set.
        **kwargs: To allow overrides, this will be merged with the rest of the msg.

    Returns:
        dict: Returs a dict formatted correctly to start playback on a Chromecast.
    Nr   TYPE	playqueue)rJ   rD   )machineIdentifierr8   r9   r:   rL   r=   r;   rB   rC   rA   accessTokenuserz/playQueues/z?own=1&window=200)r2   r3   r5   r6   r7   servercontainerKey)r>   r@   r<   
customDatarE   r   activeTrackIds)r.   r0   r,   )
isinstancelist_serverr	   _baseurlschemehostnamerA   rS   _tokenmyPlexUsernamer=   getattritemscreatePlayQueuerH   selectedItemkeylistTyperL   update) r,   r.   r0   r2   r3   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r@   rA   rB   rC   rD   rE   r   rF   rH   rJ   rL   rM   rS   tokenrV   
server_urlmsgs                                    S/home/user/adhan/venv/lib/python3.11/site-packages/pychromecast/controllers/plex.pymedia_to_chromecast_commandrm   0   s   ~ E !+5$ 7 7JE!HU] 	 fo..
$%"4(#65&$'';66 "!	..u	.JJI+*.	oa(1. {{ "$& ( , ,():'60H'6&*<*< (& #('2  !N{ M M M) , !&"9
 
! !CH JJvJ    c                  *    e Zd ZdZedd            ZdS )PlexMediaStatuszClass to hold the media status.rN   r?   c                6    | j                             d          S zReturn episode title.subtitlemedia_metadatagetselfs    rl   episode_titlezPlexMediaStatus.episode_title   s     "&&z222rn   N)rN   r?   )__name__
__module____qualname____doc__propertyry    rn   rl   rp   rp      s8        ))3 3 3 X3 3 3rn   rp   rx   c                6    | j                             d          S rr   rt   rw   s    rl   ry   ry      s     "":...rn   c                  $    e Zd ZdZdA fdZ	 	 	 	 dBdCdZdDdZdAdZdEdZdddFdZ	dAdZ
dAdZdAdZdAdZdAdZdGdHd$ZdAd%ZdId(ZdJdKd+ZdJdKd,ZdLdMd/ZdLdNd4ZdAd5ZedOd7            ZdLdPd:ZdLdNd;Z	 dQdRd=ZdLdNd>ZdLdSd?ZdLdSd@Z xZS )TPlexControllerz+Controller to interact with Plex namespace.rN   Nonec                    t                                          dd           d| _        d| _        d| _        t          j                    | _        i | _        d S )Nzurn:x-cast:plex9AC194DCr   )	super__init__app_id	namespace
request_id	threadingEventplay_media_event_last_play_msg)rx   	__class__s    rl   r   zPlexController.__init__   sQ    *J777 * ) 1 1.0rn   NFTrk   dictr   r?   inc_session_idr4   callback_functionCallbackType | Noneincc                   | j                             d|||||           |r|                                  |r<| j        }	 || _        |                     |||           || _        dS # || _        w xY w|                     |||           dS )a  Wrapper for the commands.

        Args:
            msg (dict): The actual command that will be sent.
            namespace (None, optional): What namespace should be used to send this.
            inc_session_id (bool, optional): Include session ID.
            callback_function (None, optional): If callback is provided it is
                                                executed after the command.
            inc (bool, optional): Increase the requestsId.
        zSending msg %r %s %s %s %s.)r   r   N)loggerdebug_inc_requestr   send_message)rx   rk   r   r   r   r   olds          rl   	_send_cmdzPlexController._send_cmd   s    $ 	)	
 	
 	
  	  	.C%!*!!#1&7 "    "%$$$$NFW      s    A( (	A1r1   c                0    | xj         dz  c_         | j         S )Nr
   )r   rw   s    rl   r   zPlexController._inc_request  s    1rn   c                .    |                                   dS )z1Updates status when a media channel is connected.N)update_statusrw   s    rl   channel_connectedz PlexController.channel_connected	  s    rn   _messager   datac                l    |t                    t          k    r| j                            d|           dS dS )az  Called when a message from Plex to our controller is received.

        I haven't seen any message for it, but lets keep for for now.
        I have done minimal testing.

        Args:
            message (dict): Description
            data (dict): message.payload_utf8 interpreted as a JSON dict.

        Returns:
            bool: True if the message is handled.


        z&(PlexController) MESSAGE RECEIVED: %r.TF)r   TYPE_MEDIA_STATUSr   r   )rx   r   r   s      rl   receive_messagezPlexController.receive_message  s8     !222KFMMM4urn   r   c               L    |                      t          t          i|           dS )zSend message to update status.r   N)r   r   TYPE_GET_STATUS)rx   r   s     rl   r   zPlexController.update_status"  s4    ?+?P 	 	
 	
 	
 	
 	
rn   c                H    |                      t          t          i           dS )zSend stop command.N)r   r   	TYPE_STOPrw   s    rl   stopzPlexController.stop(      i011111rn   c                H    |                      t          t          i           dS )zSend pause command.N)r   r   
TYPE_PAUSErw   s    rl   pausezPlexController.pause,  s    j122222rn   c                H    |                      t          t          i           dS )zSend play command.N)r   r   	TYPE_PLAYrw   s    rl   playzPlexController.play0  r   rn   c                H    |                      t          t          i           dS )zSend previous command.N)r   r   TYPE_PREVIOUSrw   s    rl   previouszPlexController.previous4  s    m455555rn   c                H    |                      t          t          i           dS )zSend next command.N)r   r   	TYPE_NEXTrw   s    rl   nextzPlexController.next8  r   rn   PLAYBACK_STARTpositionresume_stater/   c                Z    |                      t          t          t          |d|i           dS )zSend seek command.

        Args:
            position (int): Offset in seconds.
            resume_state (str, default): PLAYBACK_START
        resumeStateN)r   r   	TYPE_SEEKSEEK_KEY)rx   r   r   s      rl   seekzPlexController.seek<  s4     	9h-V	
 	
 	
 	
 	
rn   c                0    |                      d           dS )zRewind back to the start.r   N)r   rw   s    rl   rewindzPlexController.rewindG  s    		!rn   percentfloatc                b    | j         t          | j         j                            |dz            S )zrSet the volume in percent (1-100).

        Args:
            percent (int): Percent of volume to be set.
        Nr)   )_socket_clientr   receiver_controller
set_volume)rx   r   s     rl   r   zPlexController.set_volumeK  s1     &))"6AA'C-PPPrn   皙?deltac                v    |dk    rt          d|           |                     | j        j        |z             S )zZIncrement volume by 0.1 (or delta) unless at max.
        Returns the new volume.
        r   ,volume delta must be greater than zero, not 
ValueErrorr   statusvolume_levelrx   r   s     rl   	volume_upzPlexController.volume_upV  @     A::SESSTTTt{7%?@@@rn   c                v    |dk    rt          d|           |                     | j        j        |z
            S )z\Decrement the volume by 0.1 (or delta) unless at 0.
        Returns the new volume.
        r   r   r   r   s     rl   volume_downzPlexController.volume_down^  r   rn   r   bool | Nonec                ~    | j         t          || j        j         }| j         j                            |           dS )ziToggle muting of audio.

        Args:
            status (None, optional): Override for on/off.
        N)r   r   r   volume_mutedr   set_volume_mutedrx   r   s     rl   mutezPlexController.mutef  sE     &))>11F/@@HHHHHrn   r,   r-   rM   r   c           
         t          |ft          |                                 d|}dd}|                     t	          t          | j        |d	d
          |                     dS )z!Show media item's info on screen.)r.   r0   msg_sentr4   	_responsedict | NonerN   r   c                (    | st          d          d S )NzPlexController.show_media)r   )r   r   s     rl   callbackz+PlexController.show_media.<locals>.callbackz  s&     A#$?@@@A Arn   TF)r   r   r   Nr   r4   r   r   rN   r   )rm   TYPE_DETAILSr   launchr   r   r   )rx   r,   rM   rk   r   s        rl   
show_mediazPlexController.show_mediat  s    )
$0A0A0C0C
 
GM
 
	A 	A 	A 	A 	.DeLLLh  	 	
 	
 	
 	
 	
rn   c                ^    | j         t          | j         j                                         dS )zQuit the Plex app.N)r   r   r   stop_apprw   s    rl   quit_appzPlexController.quit_app  s/    &))/88:::::rn   rp   c                    | j         t          | j         j        j        }t          |_        t          t          |          S )zGet the Chromecast's playing status.

        Returns:
            pychromecast.controllers.media.MediaStatus: Slightly modified status with patched
                                                        method for episode_title.
        )r   r   media_controllerr   ry   r   rp   r   s     rl   r   zPlexController.status  s9     &))$5<,OV,,,rn   r2   float | Nonec                    | j         rU| j        j        }t          | j                   }||n||d         d         d<   ||d<   |                     |ddd	           dS | j                            d
           dS )zReset playback.

        Args:
            offset (None, optional): Start playback from this offset in seconds,
                                     otherwise playback will start from current time.

        Nr,   rX   r2   current_time urn:x-cast:com.google.cast.mediaTFr   r   r   zKCan not reset the stream, _last_play_msg was not set with _send_start_play.)r   r   adjusted_current_timer   r   r   r   )rx   r2   
offset_nowrk   s       rl   _reset_playbackzPlexController._reset_playback  s      	:J4.//C %n

& L&x0 #-CNN<#	       K5    rn   c                    t          |fd|                                 i|}| j                            dt	          j        |d                     || _        |                     |ddd           d	S )
zHelper to send a playback command.

        Args:
            media (None, optional): :class:`~plexapi.base.Playable
            **kwargs: media_to_chromecast_command docs string.
        
requestiIdzCreate command: 
%r
   )indentr   TFr   N)rm   r   r   r   jsondumpsr   r   )rx   r,   rM   rk   s       rl   _send_start_playzPlexController._send_start_play  s     *
 
"//11
5;
 
 	2DJs14M4M4MNNN!8	 	 	
 	
 	
 	
 	
rn   timeoutc                    | j                                           | j        |fi | | j                             |           | j                                          dS )a  Block until media is playing, typically useful in a script.

        Another way to do the same is to check if the
        controller is_active or by using self.status.player_state.

        Args:
            media (None, optional): Can also be :class:`~plexapi.base.Playable
                                    if not, you need to fill out all the kwargs.
            timeout (None, int): default None
            **kwargs: See media_to_chromecast_command docs string.

        N)r   clear
play_mediawait)rx   r,   r   rM   s       rl   block_until_playingz"PlexController.block_until_playing  se      	##%%%(((((""7+++##%%%%%rn   c                z      j                                          d
 fd}                     |           d	S )a  Start playback on the Chromecast.

        Args:
            media (None, optional): Can also be :class:`~plexapi.base.Playable
                                    if not, you need to fill out all the kwargs.
            **kwargs: See media_to_chromecast_command docs string.
        r   r4   r   r   rN   r   c                    | st          d          	  j        fi  j                                         d S # j                                         w xY w)NzPlexController.play_media)r   r   r   set)r   r   rM   r,   rx   s     rl   app_launched_callbackz8PlexController.play_media.<locals>.app_launched_callback  sq     A#$?@@@,%%e66v666%))+++++%))++++s	   = Ar   Nr   )r   r   r   )rx   r,   rM   r  s   ``` rl   r   zPlexController.play_media  sa     	##%%%	, 	, 	, 	, 	, 	, 	, 	, 	&;<<<<<rn   c                X    | j         t          | j                             |           dS )zJoin the thread.Nr   )r   r   joinrx   r   s     rl   r  zPlexController.join  s1    &))   11111rn   c                    | j         t          | j                                          |                     |           dS )zDisconnect the controller.

        :param timeout: A floating point number specifying a timeout for the
                        operation in seconds (or fractions thereof). Or None
                        to block forever. Set to 0 to not block.
        Nr  )r   r   
disconnectr  r  s     rl   r  zPlexController.disconnect  sB     &))&&(((		'	"""""rn   rN   r   )NFNT)rk   r   r   r?   r   r4   r   r   r   r4   rN   r   )rN   r1   )r   r   r   r   rN   r4   )r   r   rN   r   )r   )r   r1   r   r/   rN   r   )r   r   rN   r   )r   )r   r   rN   r   N)r   r   rN   r   r,   r-   rM   r   rN   r   )rN   rp   )r2   r   rN   r   )NN)r,   r-   r   r   rM   r   rN   r   )r   r   rN   r   ) rz   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   r   r  r  __classcell__r   s   @rl   r   r      s       551 1 1 1 1 1 !%$15, , , , ,\   
      * IM 
 
 
 
 
 
2 2 2 23 3 3 32 2 2 26 6 6 62 2 2 2	
 	
 	
 	
 	
   	Q 	Q 	Q 	QA A A A AA A A A AI I I I I
 
 
 
 
 ; ; ; ; - - - X-    :
 
 
 
 
( FJ& & & & &*= = = = =(2 2 2 2 2# # # # # # # # #rn   r   c                  ^     e Zd ZdZd fdZddZ	 dddZddZd dZd!dZ	d"d# fdZ
 xZS )$PlexApiControllerz"A controller that can use PlexAPI.pmsr   rN   r   c                V    t                                                       || _        d S r
  )r   r   r  )rx   r  r   s     rl   r   zPlexApiController.__init__  s$    rn   tuple[Any, Any, Any]c                   t          t          t          | j        j                                      d          d                   }| j                            |                                          }| j        j	        
                    dd          }| j        j	        
                    dd          }|j        |         }|j        |         }|||fS )z.Get current media_item, media, & part for PMS./
mediaIndexr   	partIndex)r1   r   r/   r   
content_idsplitr  	fetchItemreloadmedia_custom_datarv   r,   parts)rx   rf   
media_item	media_idxpart_idxr,   parts          rl   _get_current_mediaz$PlexApiController._get_current_media  s     $sDK23399#>>rBCCX'',,3355
K155lAFF	;044[!DD +{8$5$&&rn   rs   Ttrackr   type_r/   reset_playbackr4   c                   |                                  \  }}}|dk    r|                                }|j        }n1|dk    r|                                }|j        }nt          d          |D ]A}	||	j        |	j        |	j        fv r)| j	        
                    d||            ||	            nB|                                 |r|                                  dS dS )am  Sets a new default audio/subtitle track.

        Args:
            track (None): The chosen track.
            type_ (str): The type of track.
            reset_playback (bool, optional): Reset playback after the track has
                                             been changed.

        Raises:
            ValueError: If type isn't subtitle or audio.
        rs   audioz(Set type parameter as subtitle or audio.zChange %s to %s.N)r"  subtitleStreamssetDefaultSubtitleStreamaudioStreamssetDefaultAudioStreamr   indexlanguagelanguageCoder   r   r  r   )
rx   r#  r$  r%  item_r!  methoddefaulttrack_s
             rl   _change_trackzPlexApiController._change_track  s
    //11aJ))++F3GGg&&((F0GGGHHH 	 	Fv8KLLL!!"4eUCCC M
 	 	#  """""	# 	#rn   r'  c                2    |                      |d           dS )znEnable an audiotrack.

        Args:
            audio (str): Can be index, language or languageCode.
        r'  Nr4  )rx   r'  s     rl   enable_audiotrackz#PlexApiController.enable_audiotrack@  s      	5'*****rn   c                    |                                  \  }}}|                                 |                                  dS )zDisable a subtitle track.N)r"  resetDefaultSubtitleStreamr   )rx   r0  __r!  s       rl   disable_subtitlez"PlexApiController.disable_subtitleH  sK     ##%%		
'')))rn   c                0    |                      |           dS )ztEnable a subtitle track.

        Args:
            subtitle (str): Can be index, language or languageCode.
        Nr6  )rx   rs   s     rl   enable_subtitlez!PlexApiController.enable_subtitleR  s     	8$$$$$rn   Nr,   r-   rM   c                    d| j         j        i}|                    |            t                      j        |fi | dS )a}  Start playback on the Chromecast.

        Args:
            media (None, optional): Can also be :class:`~plexapi.base.Playable
                                    if not, you need to fill out all the kwargs.
            **kwargs: See media_to_chromecast_command docs string. `version` is set
                      to the version of the PMS reported by the API by default.
        rL   N)r  rL   rh   r   r   )rx   r,   rM   argsr   s       rl   r   zPlexApiController.play_mediaZ  sK     48+,F5))D)))))rn   )r  r   rN   r   )rN   r  )rs   T)r#  r   r$  r/   r%  r4   rN   r   )r'  r/   rN   r   r	  )rs   r/   rN   r   r
  r  )rz   r{   r|   r}   r   r"  r4  r7  r;  r=  r   r  r  s   @rl   r  r  	  s        ,,     ' ' ' ' KO!# !# !# !# !#F+ + + +   % % % %* * * * * * * * * * *rn   r  )8r,   r-   r.   r/   r0   r1   r2   r1   r3   r4   r5   r4   r6   r1   r7   r1   r8   r4   r9   r4   r:   r4   r;   r4   r<   r/   r=   r4   r>   r?   r@   r/   rA   r1   rB   r/   rC   r?   rD   r?   rE   r4   r   r1   rF   rG   rH   rI   rJ   rK   rL   r/   rM   r   rN   rO   )rx   rp   rN   r?   )<r}   
__future__r   copyr   	functoolsr   r   r   typingr   r   r   urllib.parser	    r   r   r,   r   constr   errorr   r   generated.cast_channel_pb2r   response_handlerr   plexapi.baser   plexapi.mediar   plexapi.playqueuer   plexapi.serverr   STREAM_TYPE_UNKNOWNSTREAM_TYPE_BUFFEREDSTREAM_TYPE_LIVEr   r   r   r   TYPE_STEPFORWARDTYPE_STEPBACKWARDr   r   	TYPE_LOADr   r   r   r   TYPE_EDIT_TRACKS_INFOrm   rp   r~   ry   r   r  r   rn   rl   <module>rU     s    # " " " " "                  + + + + + + + + + + ! ! ! ! ! ! * * * * * * * *                   : : : : : : : :      0 / / / / / *%%%%%%######++++++)))))) !  	
	   			" *  " %* ## *"&"" 5G G G G GT3 3 3 3 3k 3 3 3 
/ / / 
/
{# {# {# {# {#^ {# {# {#~	\* \* \* \* \* \* \* \* \* \*rn   