
    g¿                        d dl mZ d dlmZ d dlmZmZmZmZ d dlm	Z	m
Z
mZmZmZmZ d dlmZmZmZ d dlmZmZ d dlmZmZ  G d d	      Z G d
 d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d de!e"      Z# G d d      Z$ G d  d!      Z% G d" d#e$e%      Z& G d$ d%      Z' G d& d'      Z( G d( d)e'e(      Z) G d* d+      Z* G d, d-      Z+ G d. d/e*e+      Z, G d0 d1      Z- G d2 d3e-      Z. G d4 d5e-      Z/ G d6 d7e-      Z0 G d8 d9e-      Z1 G d: d;e-      Z2 G d< d=e-      Z3 G d> d?e-      Z4 G d@ dAe-      Z5 G dB dCe-      Z6 G dD dEe-      Z7 G dF dGe-      Z8 G dH dIe-      Z9 G dJ dKe-      Z: G dL dMe-      Z; G dN dOe-      Z< G dP dQe-      Z= G dR dSe-      Z> G dT dU      Z? G dV dWe?      Z@ G dX dYe?      ZA G dZ d[e?      ZB G d\ d]e?      ZC G d^ d_e?      ZD G d` dae?      ZE G db dce?      ZF G dd dee?      ZG G df dge?      ZH G dh die?      ZI G dj dke?      ZJ G dl dm      ZK G dn doe"e(e+e.e/e0e1e2e3e4e5e6e7e8e9e>e@eAeBeCeDeFeJ      ZL G dp dqe"e(e+e.e/e0e1e3e4e5e6e7e8e9e>e@eCeD      ZM G dr dse"e(e+e.e/e1e7e9e>e@eD      ZN G dt due"e(e+e.e/e0e1e3e5e7e9e>e@eBeDeJ      ZO G dv dwe"e(e+e.e/e1e5e7e9e>e@eAeCeDeEeGeH      ZP G dx dye"e(e+e.e/e1e3e5e6e7e9e>e@eCeDeEeH      ZQ G dz d{e"e(e+e.e/e1e9e:e;e<e>e@eCeDeE      ZR G d| d}e"e(e.e5e7e9e>	      ZS G d~ de"e(e.e=e5e7e9e>eI      ZT G d de"e(e+e.e/e0e1e5e7e9e>eD      ZU G d de"e(e5e7e9      ZVy)    )deque)datetime)DequeSetTupleUnion)	parse_qslquote
quote_plusunquote	urlencodeurlsplit)mediasettingsutils)
BadRequestNotFound)
deprecated
openOrReadc                   (    e Zd ZdZd Zd Zd Zd Zy)AdvancedSettingsMixinz9 Mixin for Plex objects that can have advanced settings. c                 d    | j                    d}| j                  |t        j                  d      S )zC Returns a list of :class:`~plexapi.settings.Preferences` objects. z?includePreferences=1Preferences)clsrtag)key
fetchItemsr   r   selfr   s     #/opt/Tautulli/lib/plexapi/mixins.pypreferencesz!AdvancedSettingsMixin.preferences   s.    
/0s(<(<=QQ    c           	          | j                         }	 t        fd|D              S # t        $ r? |D cg c]  }|j                   nc c}w }}t	        d d| j
                   d|       dw xY w)z Returns a :class:`~plexapi.settings.Preferences` object for the specified pref.

            Parameters:
                pref (str): The id of the preference to return.
        c              3   B   K   | ]  }|j                   k(  s|  y wN)id).0pprefs     r    	<genexpr>z3AdvancedSettingsMixin.preference.<locals>.<genexpr>   s     9aADDDL9s   zUnknown preference "z" for z. Available preferences: N)r!   nextStopIterationr&   r   TYPE)r   r)   prefsr(   availablePrefss    `   r    
preferencez AdvancedSettingsMixin.preference   s       "	Q95999 	Q,12qadd22N21$vdii[ I55C4DF GLPQ	Qs   ' A/A(A/c           
      z   i }| j                    d}| j                         D ci c]  }|j                  s|j                  | }}|j	                         D ]_  \  }}	 ||   }|j                  }|j                  ||j                  t        |                  r|||<   Ht        | dt        |              |t        |      z   }	| j                  j                  |	| j                  j                  j                         | S c c}w # t
        $ r( t        | dt        |j                                      w xY w)z) Edit a Plex object's advanced settings. /prefs?z not found in method)r   r!   
enumValuesr&   itemsKeyErrorr   listkeysgetstrr   _serverquery_sessionput)
r   kwargsdatar   r)   r!   	settingIDvaluer5   urls
             r    editAdvancedz"AdvancedSettingsMixin.editAdvanced"   s2   
'"151A1A1CWttww}WW & 
	KIuS"9- J~~eZ^^CJ%?@"'Y%tJ7G6HIJJ
	K IdO#3t||'<'<'@'@A X  S%tK<L<L<N7O6PQRRSs   DDD		1D:c                    i }| j                    d}| j                         D ]  }|j                  ||j                  <    |t	        |      z   }| j
                  j                  || j
                  j                  j                         | S )z; Edit all of a Plex object's advanced settings to default. r2   r3   )	r   r!   defaultr&   r   r<   r=   r>   r?   )r   rA   r   r0   rD   s        r    defaultAdvancedz%AdvancedSettingsMixin.defaultAdvanced6   s}    
'"**, 	5J","4"4D	5IdO#3t||'<'<'@'@Ar"   N)__name__
__module____qualname____doc__r!   r0   rE   rH    r"   r    r   r      s    CR
Q(r"   r   c                   \    e Zd ZdZd
deeeef      deee   df   de	fdZ
ddde	fdZd	 Zy)SmartFilterMixinz5 Mixin for Plex objects that can have smart filters. NfeedreturnOnreturnc                    g }d}|t        d      }n|j                  d       ddg}|r|j                         \  }}|dk(  r"|j                  | j	                  ||             nI||v r|dk(  s|j                  ||f       n/||v r|r||k(  st        d      |}n|j                  ||i       |r|st        |      dkD  r|d   }|r||iS |j                         S )	z< Parse filter groups from input lines between push and pop. NpopandorpushzAcannot have different logical operators for the same filter group   r   )	setaddpopleftappend_parseFilterGroups
appendleft
ValueErrorlenrT   )r   rP   rQ   currentFiltersStackoperatorForStackallowedLogicalOperatorsr   rC   s           r    r]   z#SmartFilterMixin._parseFilterGroupsD   s   *,5zHLL#($-JCf}#**++D(; e|OOS%L1//#,<,C$(  $'  $**C<81 4  C(;$<q$@6q9$&9::"&&((r"   zdeque[Tuple[str, str]]c                    i }ddh}ddh}ddh}||z  |z  }|r|j                         \  }}||v rt        |      ||<   n~||v r|||<   nt|dk(  rt        j                  |      |d<   nV|dk(  r|j	                  d      |d<   n<|j                  ||f       | j                  ||	      }	d
|v rd|d
   |	gi|d
<   n|	|d
<   |r|S )z% Parse the query string into a dict. typesortincludeGuidslimitgrouphavinglibtype,)rQ   filtersrU   )r[   intr   reverseSearchTypesplitr^   r]   )
r   rP   filtersDictspecial_keysinteger_keys
as_is_keysreserved_keysr   rC   filter_groups
             r    _parseQueryFeedz SmartFilterMixin._parseQueryFeedp   s   '&0x(
$|3j@JCl"#&u:C 
"#(C ).)@)@)GI&&+kk#&6F#e-#66=  7   +I 6E.K	* .:K	*) , r"   c                     t        t        |            }t               }t        |j                        D ]3  \  }}|j                  d      r
| d|dd }}|j                  ||f       5 | j                  |      S )z7 Parse the content string and returns the filter dict. =rX   N)r   r   r   r	   r=   
startswithr\   rw   )r   contentrP   r   rC   s        r    _parseFilterszSmartFilterMixin._parseFilters   sz    77+,w#GMM2 	&JC$ #uAYab	UKKe%	& ##D))r"   r%   )rI   rJ   rK   rL   r   r   r;   r   r   dictr]   rw   r|   rM   r"   r    rO   rO   A   sV    ?*)uU38_'= *)sSVxY]~I^ *)jn *)X$<  >*r"   rO   c                       e Zd ZdZd Zd Zy)SplitMergeMixinz6 Mixin for Plex objects that can be split and merged. c                     | j                    d}| j                  j                  || j                  j                  j                         | S )z5 Split duplicated Plex object into separate objects. z/splitr3   r   r<   r=   r>   r?   r   s     r    rp   zSplitMergeMixin.split   s>    
&!3t||'<'<'@'@Ar"   c                    t        |t              st        |      j                  d      }| j                   ddj                  d |D               }| j                  j                  || j                  j                  j                         | S )z Merge other Plex objects into the current object.

            Parameters:
                ratingKeys (list): A list of rating keys to merge.
        rl   z/merge?ids=c              3   2   K   | ]  }t        |        y wr%   )r;   )r'   rs     r    r*   z(SplitMergeMixin.merge.<locals>.<genexpr>   s     .J!s1v.Js   r3   )

isinstancer8   r;   rp   r   joinr<   r=   r>   r?   )r   
ratingKeysr   s      r    mergezSplitMergeMixin.merge   sr     *d+Z..s3J
+chh.Jz.J&J%KL3t||'<'<'@'@Ar"   N)rI   rJ   rK   rL   rp   r   rM   r"   r    r   r      s    @r"   r   c                   &    e Zd ZdZd ZddZddZy)UnmatchMatchMixinz; Mixin for Plex objects that can be unmatched and matched. c                     | j                    d}| j                  j                  || j                  j                  j                         y)z' Unmatches metadata match from object. z/unmatchr3   Nr   r   s     r    unmatchzUnmatchMatchMixin.unmatch   s9    
(#3t||'<'<'@'@Ar"   Nc                    | j                    d}ddi}|rSt        |||g      sE| j                         j                  |d<   t	        j
                  | j                         |      |d<   nt        d ||||fD              r|| j                  |d<   n||d<   |t        | dd	      |d<   n||d<   |xs | j                         j                  |d<   || j                         j                  |d<   n't	        j
                  | j                         |      |d<   |d
z   t        |      z   }| j                  |t        j                        S )a   Return list of (:class:`~plexapi.media.SearchResult`) metadata matches.

             Parameters:
                agent (str): Agent name to be used (imdb, thetvdb, themoviedb, etc.)
                title (str): Title of item to search for
                year (str): Year of item to search in
                language (str) : Language of item to search in

            Examples:
                1. video.matches()
                2. video.matches(title="something", year=2020)
                3. video.matches(title="something")
                4. video.matches(year=2020)
                5. video.matches(title="something", year="")
                6. video.matches(title="", year=2020)
                7. video.matches(title="", year="")

                1. The default behaviour in Plex Web = no params in plexapi
                2. Both title and year specified by user
                3. Year automatically filled in
                4. Title automatically filled in
                5. Explicitly searches for title with blank year
                6. Explicitly searches for blank title with year
                7. I don't know what the user is thinking... return the same result as 1

                For 2 to 7, the agent and language is automatically filled in
        z/matchesmanualrX   languageagentc              3   $   K   | ]  }|d u 
 y wr%   rM   )r'   xs     r    r*   z,UnmatchMatchMixin.matches.<locals>.<genexpr>   s     IQ1D=Is   titleyear ?r   )r   anysectionr   r   getAgentIdentifierr   getattrr   r   r   r   SearchResult)r   r   r   r   r   r   paramss          r    matcheszUnmatchMatchMixin.matches   s/   8 
(#AeT845!%!8!8F:#66t||~uMF7OI5%x*HII=&*jjF7O&+F7O<%,T62%>F6N%)F6N%-%H1H1Hz"=&*lln&:&:F7O&+&>&>t||~u&UF7OCi)F++s(:(:;;r"   c                 d   | j                    d}|r,| j                  |      }|r|d   }nt        d| d| d      |st        d      |j                  |j                  d}|d	z   t        |      z   }| j                  j                  || j                  j                  j                  
       | S )a   Use match result to update show metadata.

            Parameters:
                auto (bool): True uses first match from matches
                    False allows user to provide the match
                searchResult (:class:`~plexapi.media.SearchResult`): Search result from
                    ~plexapi.base.matches()
                agent (str): Agent name to be used (imdb, thetvdb, themoviedb, etc.)
        z/match)r   r   z$No matches found using this agent: (:)zZfixMatch() requires either auto=True or searchResult=:class:`~plexapi.media.SearchResult`.)guidnamer   r3   )
r   r   r   r   r   r   r<   r=   r>   r?   )r   searchResultautor   r   	autoMatchr   rA   s           r    fixMatchzUnmatchMatchMixin.fixMatch   s     
&!51I(|!EeWAi[XYZ[[ P Q Q '++&++- Sy9V,,4(=(=(A(ABr"   )NNNN)NFN)rI   rJ   rK   rL   r   r   r   rM   r"   r    r   r      s    EB
6<pr"   r   c                       e Zd ZdZd Zy)ExtrasMixinz. Mixin for Plex objects that can have extras. c                 R    ddl m} | j                   d}| j                  ||      S )z: Returns a list of :class:`~plexapi.video.Extra` objects. r   )Extraz/extrasr   )plexapi.videor   r   r   )r   r   r   s      r    extraszExtrasMixin.extras  s(    '
'"s..r"   N)rI   rJ   rK   rL   r   rM   r"   r    r   r     s
    8/r"   r   c                       e Zd ZdZd Zy)	HubsMixinz4 Mixin for Plex objects that can have related hubs. c                 R    ddl m} | j                   d}| j                  ||      S )z: Returns a list of :class:`~plexapi.library.Hub` objects. r   )Hubz/relatedr   )plexapi.libraryr   r   r   )r   r   r   s      r    hubszHubsMixin.hubs  s(    '
(#s,,r"   N)rI   rJ   rK   rL   r   rM   r"   r    r   r     s
    >-r"   r   c                   H    e Zd ZdZed        Zd Zd Zed        Zd Z	d Z
y)	PlayedUnplayedMixinz@ Mixin for Plex objects that can be marked played and unplayed. c                 N    | j                   rt        | j                   dkD        S dS )z' Returns True if this video is played. r   F)	viewCountboolr   s    r    isPlayedzPlayedUnplayedMixin.isPlayed)  s#     ,0>>tDNNQ&'DuDr"   c                 b    d}| j                   dd}| j                  j                  ||       | S )z! Mark the Plex object as played. z/:/scrobblecom.plexapp.plugins.libraryr   
identifierr   	ratingKeyr<   r=   r   r   r   s      r    
markPlayedzPlayedUnplayedMixin.markPlayed.  s2    7TU3v.r"   c                 b    d}| j                   dd}| j                  j                  ||       | S )z# Mark the Plex object as unplayed. z/:/unscrobbler   r   r   r   r   s      r    markUnplayedz PlayedUnplayedMixin.markUnplayed5  s2    7TU3v.r"   c                     | j                   S )z Alias to self.isPlayed. )r   r   s    r    	isWatchedzPlayedUnplayedMixin.isWatched<       }}r"   c                 $    | j                          y)zB Alias to :func:`~plexapi.mixins.PlayedUnplayedMixin.markPlayed`. N)r   r   s    r    markWatchedzPlayedUnplayedMixin.markWatchedA  s    r"   c                 $    | j                          y)zD Alias to :func:`~plexapi.mixins.PlayedUnplayedMixin.markUnplayed`. N)r   r   s    r    markUnwatchedz!PlayedUnplayedMixin.markUnwatchedE  s    r"   N)rI   rJ   rK   rL   propertyr   r   r   r   r   r   rM   r"   r    r   r   &  sA    JE E  r"   r   c                       e Zd ZdZddZy)RatingMixinz9 Mixin for Plex objects that can have user star ratings. Nc                     |d}n+t        |t        t        f      r
|dk  s|dkD  rt        d      d| j                   d| }| j
                  j                  || j
                  j                  j                         | S )aI   Rate the Plex object. Note: Plex ratings are displayed out of 5 stars (e.g. rating 7.0 = 3.5 stars).

            Parameters:
                rating (float, optional): Rating from 0 to 10. Exclude to reset the rating.

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: If the rating is invalid.
        r   
   zRating must be between 0 to 10.z/:/rate?key=z/&identifier=com.plexapp.plugins.library&rating=r3   )	r   rn   floatr   r   r<   r=   r>   r?   )r   ratingr   s      r    ratezRatingMixin.rateM  sz     >FFS%L1VaZ6B;>??T^^,,[\b[cd3t||'<'<'@'@Ar"   r%   )rI   rJ   rK   rL   r   rM   r"   r    r   r   J  s
    Cr"   r   c                        e Zd ZdZed        Zy)ArtUrlMixinz@ Mixin for Plex objects that can have a background artwork url. c                 h    | j                  dd      }|r| j                  j                  |d      S dS )z) Return the art url for the Plex object. artgrandparentArtTincludeTokenN	firstAttrr<   rD   r   r   s     r    artUrlzArtUrlMixin.artUrlb  s6     nnU$45;>t||$7HDHr"   N)rI   rJ   rK   rL   r   r   rM   r"   r    r   r   _  s    JI Ir"   r   c                       e Zd ZdZd Zd Zy)ArtLockMixinzC Mixin for Plex objects that can have a locked background artwork. c                 *     | j                   di ddiS )z0 Lock the background artwork for a Plex object. 
art.lockedrX   rM   _editr   s    r    lockArtzArtLockMixin.lockArtl      tzz.\1-..r"   c                 *     | j                   di ddiS )z2 Unlock the background artwork for a Plex object. r   r   rM   r   r   s    r    	unlockArtzArtLockMixin.unlockArtp  r   r"   N)rI   rJ   rK   rL   r   r   rM   r"   r    r   r   i  s    M//r"   r   c                   $    e Zd ZdZd ZddZd Zy)ArtMixinz: Mixin for Plex objects that can have background artwork. c                 `    | j                  d| j                   dt        j                        S )z@ Returns list of available :class:`~plexapi.media.Art` objects. /library/metadata//artsr   )r   r   r   Artr   s    r    artszArtMixin.artsx  s(    !3DNN3C5IuyyYYr"   Nc                 l   |rXd| j                    dt        |       }| j                  j                  || j                  j                  j
                         | S |rWd| j                    d}t        |      }| j                  j                  || j                  j                  j
                  |       | S )z Upload a background artwork from a url or filepath.

            Parameters:
                url (str): The full URL to the image to upload.
                filepath (str): The full file path the the image to upload or file-like object.
        r   z
/arts?url=r3   r   r4   rA   r   r   r<   r=   r>   postr   r   rD   filepathr   rA   s        r    	uploadArtzArtMixin.uploadArt|  s     &t~~&6jC@QRCLLs4<<+@+@+E+EF
 	 &t~~&6e<Ch'DLLs4<<+@+@+E+EDQr"   c                 &    |j                          | S )z Set the background artwork for a Plex object.

            Parameters:
                art (:class:`~plexapi.media.Art`): The art object to select.
        selectr   s     r    setArtzArtMixin.setArt  s     	

r"   NN)rI   rJ   rK   rL   r   r   r   rM   r"   r    r   r   u  s    DZ r"   r   c                        e Zd ZdZed        Zy)LogoUrlMixinz2 Mixin for Plex objects that can have a logo url. c                     t        d | j                  D        d      }|r'| j                  j                  |j                  d      S dS )z* Return the logo url for the Plex object. c              3   @   K   | ]  }|j                   d k(  s|  yw)	clearLogoN)re   )r'   is     r    r*   z'LogoUrlMixin.logoUrl.<locals>.<genexpr>  s     FA+0EaFs   NTr   )r+   imagesr<   rD   )r   images     r    logoUrlzLogoUrlMixin.logoUrl  s?     FFMAFt||		=PDPr"   N)rI   rJ   rK   rL   r   r  rM   r"   r    r   r     s    <Q Qr"   r   c                       e Zd ZdZd Zd Zy)LogoLockMixinz5 Mixin for Plex objects that can have a locked logo. c                     t        d      )z" Lock the logo for a Plex object. z&Logo cannot be locked through the API.NotImplementedErrorr   s    r    lockLogozLogoLockMixin.lockLogo  s    !"JKKr"   c                     t        d      )z$ Unlock the logo for a Plex object. z(Logo cannot be unlocked through the API.r
  r   s    r    
unlockLogozLogoLockMixin.unlockLogo  s    !"LMMr"   N)rI   rJ   rK   rL   r  r  rM   r"   r    r  r    s    ?LNr"   r  c                   $    e Zd ZdZd ZddZd Zy)	LogoMixinz- Mixin for Plex objects that can have logos. c                 `    | j                  d| j                   dt        j                        S )zA Returns list of available :class:`~plexapi.media.Logo` objects. r   /clearLogosr   )r   r   r   Logor   s    r    logoszLogoMixin.logos  s+    !3DNN3C;OUZU_U_``r"   Nc                 l   |rXd| j                    dt        |       }| j                  j                  || j                  j                  j
                         | S |rWd| j                    d}t        |      }| j                  j                  || j                  j                  j
                  |       | S )z Upload a logo from a url or filepath.

            Parameters:
                url (str): The full URL to the image to upload.
                filepath (str): The full file path the the image to upload or file-like object.
        r   z/clearLogos?url=r3   r  r   r   r   s        r    
uploadLogozLogoMixin.uploadLogo  s     &t~~&66FzRUFWXCLLs4<<+@+@+E+EF
 	 &t~~&6kBCh'DLLs4<<+@+@+E+EDQr"   c                     t        d      )z Set the logo for a Plex object.

            Raises:
                :exc:`~plexapi.exceptions.NotImplementedError`: Logo cannot be set through the API.
        zTLogo cannot be set through the API. Re-upload the logo using "uploadLogo" to set it.r
  )r   logos     r    setLogozLogoMixin.setLogo  s     "?
 	
r"   r   )rI   rJ   rK   rL   r  r  r  rM   r"   r    r  r    s    7a 	
r"   r  c                   0    e Zd ZdZed        Zed        Zy)PosterUrlMixinz4 Mixin for Plex objects that can have a poster url. c                 j    | j                  ddd      }|r| j                  j                  |d      S dS )z+ Return the thumb url for the Plex object. thumbparentThumbgrandparentThumbTr   Nr   )r   r  s     r    thumbUrlzPosterUrlMixin.thumbUrl  8     w7IJ=Bt||D9LLr"   c                     | j                   S )z Alias to self.thumbUrl. )r   r   s    r    	posterUrlzPosterUrlMixin.posterUrl  r   r"   N)rI   rJ   rK   rL   r   r   r#  rM   r"   r    r  r    s-    >M M
  r"   r  c                       e Zd ZdZd Zd Zy)PosterLockMixinz7 Mixin for Plex objects that can have a locked poster. c                 *     | j                   di ddiS )z$ Lock the poster for a Plex object. thumb.lockedrX   rM   r   r   s    r    
lockPosterzPosterLockMixin.lockPoster      tzz0^Q/00r"   c                 *     | j                   di ddiS )z& Unlock the poster for a Plex object. r'  r   rM   r   r   s    r    unlockPosterzPosterLockMixin.unlockPoster  r)  r"   N)rI   rJ   rK   rL   r(  r+  rM   r"   r    r%  r%    s    A11r"   r%  c                   $    e Zd ZdZd ZddZd Zy)PosterMixinz/ Mixin for Plex objects that can have posters. c                 `    | j                  d| j                   dt        j                        S )zC Returns list of available :class:`~plexapi.media.Poster` objects. r   /postersr   )r   r   r   Posterr   s    r    posterszPosterMixin.posters  s+    !3DNN3C8LRWR^R^__r"   Nc                 l   |rXd| j                    dt        |       }| j                  j                  || j                  j                  j
                         | S |rWd| j                    d}t        |      }| j                  j                  || j                  j                  j
                  |       | S )z Upload a poster from a url or filepath.

            Parameters:
                url (str): The full URL to the image to upload.
                filepath (str): The full file path the the image to upload or file-like object.
        r   z/posters?url=r3   r/  r   r   r   s        r    uploadPosterzPosterMixin.uploadPoster  s     &t~~&6mJsOCTUCLLs4<<+@+@+E+EF
 	 &t~~&6h?Ch'DLLs4<<+@+@+E+EDQr"   c                 &    |j                          | S )z Set the poster for a Plex object.

            Parameters:
                poster (:class:`~plexapi.media.Poster`): The poster object to select.
        r   )r   posters     r    	setPosterzPosterMixin.setPoster  s     	r"   r   )rI   rJ   rK   rL   r1  r3  r6  rM   r"   r    r-  r-    s    9` r"   r-  c                        e Zd ZdZed        Zy)ThemeUrlMixinz3 Mixin for Plex objects that can have a theme url. c                 j    | j                  ddd      }|r| j                  j                  |d      S dS )z+ Return the theme url for the Plex object. themeparentThemegrandparentThemeTr   Nr   r   r:  s     r    themeUrlzThemeUrlMixin.themeUrl  r!  r"   N)rI   rJ   rK   rL   r   r>  rM   r"   r    r8  r8    s    =M Mr"   r8  c                       e Zd ZdZd Zd Zy)ThemeLockMixinz6 Mixin for Plex objects that can have a locked theme. c                 *     | j                   di ddiS )z# Lock the theme for a Plex object. theme.lockedrX   rM   r   r   s    r    	lockThemezThemeLockMixin.lockTheme  r)  r"   c                 *     | j                   di ddiS )z% Unlock the theme for a Plex object. rB  r   rM   r   r   s    r    unlockThemezThemeLockMixin.unlockTheme  r)  r"   N)rI   rJ   rK   rL   rC  rE  rM   r"   r    r@  r@    s    @11r"   r@  c                   $    e Zd ZdZd ZddZd Zy)
ThemeMixinz. Mixin for Plex objects that can have themes. c                 `    | j                  d| j                   dt        j                        S )zB Returns list of available :class:`~plexapi.media.Theme` objects. r   /themesr   )r   r   r   Themer   s    r    themeszThemeMixin.themes$  s+    !3DNN3C7KQVQ\Q\]]r"   Nc                 p   |rYd| j                    dt        |       }| j                  j                  || j                  j                  j
                  |       | S |rXd| j                    d}t        |      }| j                  j                  || j                  j                  j
                  ||       | S )a   Upload a theme from url or filepath.

            Warning: Themes cannot be deleted using PlexAPI!

            Parameters:
                url (str): The full URL to the theme to upload.
                filepath (str): The full file path to the theme to upload or file-like object.
                timeout (int, optional): Timeout, in seconds, to use when uploading themes to the server.
                    (default config.TIMEOUT).
        r   z/themes?url=)r4   timeoutrI  )r4   rA   rM  r   )r   rD   r   rM  r   rA   s         r    uploadThemezThemeMixin.uploadTheme(  s     &t~~&6l:c?BSTCLLs4<<+@+@+E+EwW
 	 &t~~&6g>Ch'DLLs4<<+@+@+E+EDZabr"   c                     t        d      )z Set the theme for a Plex object.

            Raises:
                :exc:`~plexapi.exceptions.NotImplementedError`: Themes cannot be set through the API.
        zXThemes cannot be set through the API. Re-upload the theme using "uploadTheme" to set it.r
  r=  s     r    setThemezThemeMixin.setTheme<  s     "A
 	
r"   )NNN)rI   rJ   rK   rL   rK  rN  rP  rM   r"   r    rG  rG  !  s    8^(	
r"   rG  c                       e Zd ZdZddZy)EditFieldMixinz' Mixin for editing Plex object fields. c                 p    | d|xs d| d|rdndi}|j                  |        | j                  di |S )a   Edit the field of a Plex object. All field editing methods can be chained together.
            Also see :func:`~plexapi.base.PlexPartialObject.batchEdits` for batch editing fields.

            Parameters:
                field (str): The name of the field to edit.
                value (str): The value to edit the field to.
                locked (bool): True (default) to lock the field, False to unlock the field.

            Example:

                .. code-block:: python

                    # Chaining multiple field edits with reloading
                    Movie.editTitle('A New Title').editSummary('A new summary').editTagline('A new tagline').reload()

        z.valuer   .lockedrX   r   rM   )updater   )r   fieldrC   lockedr@   editss         r    	editFieldzEditFieldMixin.editFieldK  sM    $ gVekrgWFq
 	Vtzz"E""r"   NT)rI   rJ   rK   rL   rY  rM   r"   r    rR  rR  H  s
    1#r"   rR  c                       e Zd ZdZddZy)AddedAtMixinz8 Mixin for Plex objects that can have an added at date. c                    t        |t              r7t        t        t	        j
                  |d      j                                     }n2t        |t              r"t        t        |j                                     }| j                  d||      S )a-   Edit the added at date.

            Parameters:
                addedAt (int or str or datetime): The new value as a unix timestamp (int),
                    "YYYY-MM-DD" (str), or datetime object.
                locked (bool): True (default) to lock the field, False to unlock the field.
        %Y-%m-%daddedAtrW  )r   r;   rn   roundr   strptime	timestamprY  )r   r_  rW  s      r    editAddedAtzAddedAtMixin.editAddedAtg  sj     gs#% 1 1': F P P RSTG*% 1 1 345G~~i~@@r"   NrZ  )rI   rJ   rK   rL   rd  rM   r"   r    r\  r\  d  s    BAr"   r\  c                       e Zd ZdZddZy)AudienceRatingMixinz: Mixin for Plex objects that can have an audience rating. c                 *    | j                  d||      S )z Edit the audience rating.

            Parameters:
                audienceRating (float): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        audienceRatingr`  rY  )r   rh  rW  s      r    editAudienceRatingz&AudienceRatingMixin.editAudienceRatingy  s     ~~.v~NNr"   NrZ  )rI   rJ   rK   rL   rj  rM   r"   r    rf  rf  v  s    DOr"   rf  c                       e Zd ZdZddZy)ContentRatingMixinz8 Mixin for Plex objects that can have a content rating. c                 *    | j                  d||      S )z Edit the content rating.

            Parameters:
                contentRating (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        contentRatingr`  ri  )r   rn  rW  s      r    editContentRatingz$ContentRatingMixin.editContentRating       ~~o}V~LLr"   NrZ  )rI   rJ   rK   rL   ro  rM   r"   r    rl  rl    s    BMr"   rl  c                       e Zd ZdZddZy)CriticRatingMixinz7 Mixin for Plex objects that can have a critic rating. c                 *    | j                  d||      S )z Edit the critic rating.

            Parameters:
                criticRating (float): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r   r`  ri  )r   criticRatingrW  s      r    editCriticRatingz"CriticRatingMixin.editCriticRating  s     ~~hV~DDr"   NrZ  )rI   rJ   rK   rL   ru  rM   r"   r    rr  rr    s    AEr"   rr  c                       e Zd ZdZddZy)EditionTitleMixinz8 Mixin for Plex objects that can have an edition title. c                 *    | j                  d||      S )z Edit the edition title. Plex Pass is required to edit this field.

            Parameters:
                editionTitle (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        editionTitler`  ri  )r   ry  rW  s      r    editEditionTitlez"EditionTitleMixin.editEditionTitle  s     ~~nl6~JJr"   NrZ  )rI   rJ   rK   rL   rz  rM   r"   r    rw  rw    s    BKr"   rw  c                       e Zd ZdZddZy)OriginallyAvailableMixinzD Mixin for Plex objects that can have an originally available date. c                 l    t        |t              r|j                  d      }| j                  d||      S )a   Edit the originally available date.

            Parameters:
                originallyAvailable (str or datetime): The new value "YYYY-MM-DD (str) or datetime object.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r^  originallyAvailableAtr`  r   r   strftimerY  )r   originallyAvailablerW  s      r    editOriginallyAvailablez0OriginallyAvailableMixin.editOriginallyAvailable  s8     )84"5">">z"J~~57JSY~ZZr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r|  r|    s    N	[r"   r|  c                       e Zd ZdZddZy)OriginalTitleMixinz9 Mixin for Plex objects that can have an original title. c                 *    | j                  d||      S )z Edit the original title.

            Parameters:
                originalTitle (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        originalTitler`  ri  )r   r  rW  s      r    editOriginalTitlez$OriginalTitleMixin.editOriginalTitle  rp  r"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    s    CMr"   r  c                       e Zd ZdZddZy)SortTitleMixinz4 Mixin for Plex objects that can have a sort title. c                 *    | j                  d||      S )z Edit the sort title.

            Parameters:
                sortTitle (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        	titleSortr`  ri  )r   	sortTitlerW  s      r    editSortTitlezSortTitleMixin.editSortTitle  s     ~~k9V~DDr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    s    >Er"   r  c                       e Zd ZdZddZy)StudioMixinz0 Mixin for Plex objects that can have a studio. c                 *    | j                  d||      S )z Edit the studio.

            Parameters:
                studio (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        studior`  ri  )r   r  rW  s      r    
editStudiozStudioMixin.editStudio  s     ~~hv~>>r"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    s
    :?r"   r  c                       e Zd ZdZddZy)SummaryMixinz1 Mixin for Plex objects that can have a summary. c                 *    | j                  d||      S )z Edit the summary.

            Parameters:
                summary (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        summaryr`  ri  )r   r  rW  s      r    editSummaryzSummaryMixin.editSummary       ~~i~@@r"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r        ;Ar"   r  c                       e Zd ZdZddZy)TaglineMixinz1 Mixin for Plex objects that can have a tagline. c                 *    | j                  d||      S )z Edit the tagline.

            Parameters:
                tagline (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        tagliner`  ri  )r   r  rW  s      r    editTaglinezTaglineMixin.editTagline  r  r"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    r  r"   r  c                       e Zd ZdZddZy)
TitleMixinz/ Mixin for Plex objects that can have a title. c                 n    i }| j                   dk(  r| j                  |d<    | j                  d|fd|i|S )z Edit the title.

            Parameters:
                title (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        albumzartist.id.valuer   rW  )r-   parentRatingKeyrY  )r   r   rW  r@   s       r    	editTitlezTitleMixin.editTitle  sC     99(,(<(<F$%t~~guFVFvFFr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    s    9Gr"   r  c                       e Zd ZdZddZy)TrackArtistMixinz6 Mixin for Plex objects that can have a track artist. c                 *    | j                  d||      S )z Edit the track artist.

            Parameters:
                trackArtist (str): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  r`  ri  )r   trackArtistrW  s      r    editTrackArtistz TrackArtistMixin.editTrackArtist  s     ~~o{6~JJr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    s    @Kr"   r  c                       e Zd ZdZddZy)TrackNumberMixinz6 Mixin for Plex objects that can have a track number. c                 *    | j                  d||      S )z Edit the track number.

            Parameters:
                trackNumber (int): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        indexr`  ri  )r   trackNumberrW  s      r    editTrackNumberz TrackNumberMixin.editTrackNumber  s     ~~g{6~BBr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r    s    @Cr"   r  c                       e Zd ZdZddZy)TrackDiscNumberMixinz; Mixin for Plex objects that can have a track disc number. c                 *    | j                  d||      S )z Edit the track disc number.

            Parameters:
                discNumber (int): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        parentIndexr`  ri  )r   
discNumberrW  s      r    editDiscNumberz#TrackDiscNumberMixin.editDiscNumber(  s     ~~mZ~GGr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r  %  s    EHr"   r  c                       e Zd ZdZddZy)PhotoCapturedTimeMixinz7 Mixin for Plex objects that can have a captured time. c                 l    t        |t              r|j                  d      }| j                  d||      S )a
   Edit the photo captured time.

            Parameters:
                capturedTime (str or datetime): The new value "YYYY-MM-DD hh:mm:ss" (str) or datetime object.
                locked (bool): True (default) to lock the field, False to unlock the field.
        z%Y-%m-%d %H:%M:%Sr~  r`  r  )r   capturedTimerW  s      r    editCapturedTimez'PhotoCapturedTimeMixin.editCapturedTime5  s5     lH-'001DEL~~5|F~SSr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r  2  s    A	Tr"   r  c                       e Zd ZdZddZy)UserRatingMixinz5 Mixin for Plex objects that can have a user rating. c                 *    | j                  d||      S )z Edit the user rating.

            Parameters:
                userRating (float): The new value.
                locked (bool): True (default) to lock the field, False to unlock the field.
        
userRatingr`  ri  )r   r  rW  s      r    editUserRatingzUserRatingMixin.editUserRatingD  s     ~~lJv~FFr"   NrZ  )rI   rJ   rK   rL   r  rM   r"   r    r  r  A  s    ?Gr"   r  c                   h    e Zd ZdZ ed      d	d       Zd	dZed        Zed        Z	ed	d       Z
y)
EditTagsMixinz% Mixin for editing Plex object tags. zuse "editTags" insteadc                 *    | j                  ||||      S r%   editTags)r   tagr6   rW  removes        r    
_edit_tagszEditTagsMixin._edit_tagsQ  s    }}S%88r"   c                    t        |t              s|g}|s1t        | | j                  |      g       }t        |t              r||z   }| j	                  | j                  |      |||      }|j                  |        | j                  di |S )a   Edit the tags of a Plex object. All tag editing methods can be chained together.
            Also see :func:`~plexapi.base.PlexPartialObject.batchEdits` for batch editing tags.

            Parameters:
                tag (str): Name of the tag to edit.
                items (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags to add or remove.
                locked (bool): True (default) to lock the tags, False to unlock the tags.
                remove (bool): True to remove the tags in items.

            Example:

                .. code-block:: python

                    # Chaining multiple tag edits with reloading
                    Show.addCollection('New Collection').removeGenre('Action').addLabel('Favorite').reload()

        rM   )r   r8   r   
_tagPlural
_tagHelper_tagSingularrU  r   )r   r  r6   rW  r  r@   tagsrX  s           r    r  zEditTagsMixin.editTagsU  s    $ %&GE4!5r:D$%u 1 1# 6vvNVtzz"E""r"   c                 8    | dk(  ry| dk(  ry| d   dk(  r| dd S | S )z$ Return the singular name of a tag. 	countriescountrysimilarr   sNrM   r  s    r    r  zEditTagsMixin._tagSingulars  s5     +IW^s8O
r"   c                 8    | dk(  ry| dk(  ry| d   dk7  r| dz   S | S )z" Return the plural name of a tag. r  r  r  r   r  rM   r  s    r    r  zEditTagsMixin._tagPlural~  s4     )IW^9
r"   c                     t        |t              s|g}|  d|rdndi}|r"|  d}dj                  d |D              ||<   |S t        |      D ]  \  }}t	        |        d| d}|||<    |S )	z: Return a dict of the query parameters for editing a tag. rT  rX   r   z[].tag.tag-rl   c              3   D   K   | ]  }t        t        |              y wr%   )r
   r;   )r'   ts     r    r*   z+EditTagsMixin._tagHelper.<locals>.<genexpr>  s     $BqU3q6]$Bs    [z	].tag.tag)r   r8   r   	enumerater;   )r  r6   rW  r  rA   tagnamer  items           r    r  zEditTagsMixin._tagHelper  s     %&GE e7O&Qa
 [)GHH$BE$BBDM 	 %U+ %4 XJas)4 $W% r"   N)TF)rI   rJ   rK   rL   r   r  r  staticmethodr  r  r  rM   r"   r    r  r  N  s^    /()9 *9#<      r"   r  c                        e Zd ZdZddZddZy)CollectionMixinz3 Mixin for Plex objects that can have collections. c                 *    | j                  d||      S )z Add a collection tag(s).

            Parameters:
                collections (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        
collectionr`  r  r   collectionsrW  s      r    addCollectionzCollectionMixin.addCollection  s     }}\;v}FFr"   c                 ,    | j                  d||d      S )z Remove a collection tag(s).

            Parameters:
                collections (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  TrW  r  r  r  s      r    removeCollectionz CollectionMixin.removeCollection  s     }}\;vd}SSr"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r    s    =GTr"   r  c                        e Zd ZdZddZddZy)CountryMixinz1 Mixin for Plex objects that can have countries. c                 *    | j                  d||      S )z Add a country tag(s).

            Parameters:
                countries (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  r`  r  r   r  rW  s      r    
addCountryzCountryMixin.addCountry  s     }}Y	&}AAr"   c                 ,    | j                  d||d      S )z Remove a country tag(s).

            Parameters:
                countries (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r  s      r    removeCountryzCountryMixin.removeCountry  s     }}Y	&}NNr"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r    s    ;BOr"   r  c                        e Zd ZdZddZddZy)DirectorMixinz1 Mixin for Plex objects that can have directors. c                 *    | j                  d||      S )z Add a director tag(s).

            Parameters:
                directors (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        directorr`  r  r   	directorsrW  s      r    addDirectorzDirectorMixin.addDirector       }}Z6}BBr"   c                 ,    | j                  d||d      S )z Remove a director tag(s).

            Parameters:
                directors (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r  s      r    removeDirectorzDirectorMixin.removeDirector       }}Z6$}OOr"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r        ;CPr"   r  c                        e Zd ZdZddZddZy)
GenreMixinz. Mixin for Plex objects that can have genres. c                 *    | j                  d||      S )z Add a genre tag(s).

            Parameters:
                genres (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        genrer`  r  r   genresrW  s      r    addGenrezGenreMixin.addGenre       }}WfV}<<r"   c                 ,    | j                  d||d      S )z Remove a genre tag(s).

            Parameters:
                genres (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r  s      r    removeGenrezGenreMixin.removeGenre       }}WfVD}IIr"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r        8=Jr"   r  c                        e Zd ZdZddZddZy)
LabelMixinz. Mixin for Plex objects that can have labels. c                 *    | j                  d||      S )z Add a label tag(s).

            Parameters:
                labels (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        labelr`  r  r   labelsrW  s      r    addLabelzLabelMixin.addLabel  r   r"   c                 ,    | j                  d||d      S )z Remove a label tag(s).

            Parameters:
                labels (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r	  s      r    removeLabelzLabelMixin.removeLabel  r  r"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r    r  r"   r  c                        e Zd ZdZddZddZy)	MoodMixinz- Mixin for Plex objects that can have moods. c                 *    | j                  d||      S )z Add a mood tag(s).

            Parameters:
                moods (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        moodr`  r  r   moodsrW  s      r    addMoodzMoodMixin.addMood  s     }}VU6}::r"   c                 ,    | j                  d||d      S )z Remove a mood tag(s).

            Parameters:
                moods (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r  s      r    
removeMoodzMoodMixin.removeMood  s     }}VU6$}GGr"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r    s    7;Hr"   r  c                        e Zd ZdZddZddZy)ProducerMixinz1 Mixin for Plex objects that can have producers. c                 *    | j                  d||      S )z Add a producer tag(s).

            Parameters:
                producers (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        producerr`  r  r   	producersrW  s      r    addProducerzProducerMixin.addProducer%  r  r"   c                 ,    | j                  d||d      S )z Remove a producer tag(s).

            Parameters:
                producers (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r  s      r    removeProducerzProducerMixin.removeProducer.  r  r"   NrZ  )rI   rJ   rK   rL   r  r  rM   r"   r    r  r  "  r  r"   r  c                        e Zd ZdZddZddZy)SimilarArtistMixinz7 Mixin for Plex objects that can have similar artists. c                 *    | j                  d||      S )z Add a similar artist tag(s).

            Parameters:
                artists (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  r`  r  r   artistsrW  s      r    addSimilarArtistz#SimilarArtistMixin.addSimilarArtist;  s     }}Y}??r"   c                 ,    | j                  d||d      S )z Remove a similar artist tag(s).

            Parameters:
                artists (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r#  s      r    removeSimilarArtistz&SimilarArtistMixin.removeSimilarArtistD  s     }}Yt}LLr"   NrZ  )rI   rJ   rK   rL   r%  r'  rM   r"   r    r!  r!  8  s    A@Mr"   r!  c                        e Zd ZdZddZddZy)
StyleMixinz. Mixin for Plex objects that can have styles. c                 *    | j                  d||      S )z Add a style tag(s).

            Parameters:
                styles (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        styler`  r  r   stylesrW  s      r    addStylezStyleMixin.addStyleQ  r   r"   c                 ,    | j                  d||d      S )z Remove a style tag(s).

            Parameters:
                styles (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r+  Tr  r  r,  s      r    removeStylezStyleMixin.removeStyleZ  r  r"   NrZ  )rI   rJ   rK   rL   r.  r0  rM   r"   r    r)  r)  N  r  r"   r)  c                        e Zd ZdZddZddZy)TagMixinz, Mixin for Plex objects that can have tags. c                 *    | j                  d||      S )z Add a tag(s).

            Parameters:
                tags (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  r`  r  r   r  rW  s      r    addTagzTagMixin.addTagg  s     }}UD}88r"   c                 ,    | j                  d||d      S )z Remove a tag(s).

            Parameters:
                tags (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r  Tr  r  r4  s      r    	removeTagzTagMixin.removeTagp  s     }}UD}EEr"   NrZ  )rI   rJ   rK   rL   r5  r7  rM   r"   r    r2  r2  d  s    69Fr"   r2  c                        e Zd ZdZddZddZy)WriterMixinz/ Mixin for Plex objects that can have writers. c                 *    | j                  d||      S )z Add a writer tag(s).

            Parameters:
                writers (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        writerr`  r  r   writersrW  s      r    	addWriterzWriterMixin.addWriter}  s     }}Xwv}>>r"   c                 ,    | j                  d||d      S )z Remove a writer tag(s).

            Parameters:
                writers (List<str> or List<:class:`~plexapi.media.MediaTag`>): List of tags.
                locked (bool): True (default) to lock the field, False to unlock the field.
        r;  Tr  r  r<  s      r    removeWriterzWriterMixin.removeWriter  s     }}Xwvd}KKr"   NrZ  )rI   rJ   rK   rL   r>  r@  rM   r"   r    r9  r9  z  s    9?Lr"   r9  c                   0    e Zd ZdZddZddZddZddZy)WatchlistMixinzA Mixin for Plex objects that can be added to a user's watchlist. Nc                     	 |xs | j                   j                         }|j                  |       S # t        $ r | j                   }Y (w xY w)a   Returns True if the item is on the user's watchlist.
            Also see :func:`~plexapi.myplex.MyPlexAccount.onWatchlist`.

            Parameters:
                account (:class:`~plexapi.myplex.MyPlexAccount`, optional): Account to check item on the watchlist.
                   Note: This is required if you are not connected to a Plex server instance using the admin account.
        )r<   myPlexAccountAttributeErroronWatchlistr   accounts     r    rF  zWatchlistMixin.onWatchlist  sK    	#=!;!;!=G ""4((  	#llG	#s   1 A	A	c                     	 |xs | j                   j                         }|j                  |        | S # t        $ r | j                   }Y *w xY w)a   Add this item to the specified user's watchlist.
            Also see :func:`~plexapi.myplex.MyPlexAccount.addToWatchlist`.

            Parameters:
                account (:class:`~plexapi.myplex.MyPlexAccount`, optional): Account to add item to the watchlist.
                   Note: This is required if you are not connected to a Plex server instance using the admin account.
        )r<   rD  rE  addToWatchlistrG  s     r    rJ  zWatchlistMixin.addToWatchlist  sM    	#=!;!;!=G 	t$  	#llG	#   3 A
Ac                     	 |xs | j                   j                         }|j                  |        | S # t        $ r | j                   }Y *w xY w)a   Remove this item from the specified user's watchlist.
            Also see :func:`~plexapi.myplex.MyPlexAccount.removeFromWatchlist`.

            Parameters:
                account (:class:`~plexapi.myplex.MyPlexAccount`, optional): Account to remove item from the watchlist.
                   Note: This is required if you are not connected to a Plex server instance using the admin account.
        )r<   rD  rE  removeFromWatchlistrG  s     r    rM  z"WatchlistMixin.removeFromWatchlist  sM    	#=!;!;!=G 	##D)  	#llG	#rK  c                    	 |xs | j                   j                         }| j                  j	                  dd      d   }|j                  |j                   d| d      }| j                  |      S # t        $ r | j                   }Y hw xY w)a   Return a list of :class:`~plexapi.media.Availability`
            objects for the available streaming services for this item.

            Parameters:
                account (:class:`~plexapi.myplex.MyPlexAccount`, optional): Account used to retrieve availability.
                   Note: This is required if you are not connected to a Plex server instance using the admin account.
        /rX   r   r   z/availabilities)r<   rD  rE  r   rsplitr=   METADATA	findItems)r   rH  r   rA   s       r    streamingServicesz WatchlistMixin.streamingServices  s    	#=!;!;!=G II$$S!,R0	}} 0 011CI;o^_~~d##	  	#llG	#s   A1 1B	B	r%   )rI   rJ   rK   rL   rF  rJ  rM  rS  rM   r"   r    rB  rB    s    K)$r"   rB  c                       e Zd Zy)MovieEditMixinsNrI   rJ   rK   rM   r"   r    rU  rU         	r"   rU  c                       e Zd Zy)ShowEditMixinsNrV  rM   r"   r    rY  rY    rW  r"   rY  c                       e Zd Zy)SeasonEditMixinsNrV  rM   r"   r    r[  r[         	r"   r[  c                       e Zd Zy)EpisodeEditMixinsNrV  rM   r"   r    r^  r^    r\  r"   r^  c                       e Zd Zy)ArtistEditMixinsNrV  rM   r"   r    r`  r`    r\  r"   r`  c                       e Zd Zy)AlbumEditMixinsNrV  rM   r"   r    rb  rb    r\  r"   rb  c                       e Zd Zy)TrackEditMixinsNrV  rM   r"   r    rd  rd    r\  r"   rd  c                       e Zd Zy)PhotoalbumEditMixinsNrV  rM   r"   r    rf  rf         	r"   rf  c                       e Zd Zy)PhotoEditMixinsNrV  rM   r"   r    ri  ri    s    
 	r"   ri  c                       e Zd Zy)CollectionEditMixinsNrV  rM   r"   r    rk  rk     r\  r"   rk  c                       e Zd Zy)PlaylistEditMixinsNrV  rM   r"   r    rm  rm  )  rg  r"   rm  N)Wr  r   r   typingr   r   r   r   urllib.parser	   r
   r   r   r   r   plexapir   r   r   plexapi.exceptionsr   r   plexapi.utilsr   r   r   rO   r   r   r   r   r   r   r   r   r   r   r  r  r  r%  r-  r8  r@  rG  rR  r\  rf  rl  rr  rw  r|  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r!  r)  r2  r9  rB  rU  rY  r[  r^  r`  rb  rd  rf  ri  rk  rm  rM   r"   r    <module>rs     s     + + S S * * 3 02 2jZ* Z*z .Z Zz/ /- -! !H *I I	/ 	/{L BQ Q	N 	N 
m  
F 	1 	1./ BM M	1 	1$
 $
N# #8A> A$
O. 
O
M 
M
E 
E
K 
K[~ [
M 
M
E^ 
E
?. 
?
A> 
A
A> 
AG G"
K~ 
K
C~ 
C
H> 
HT^ T
Gn 
GM M`Tm T,O= O,PM P,J J,J J,H H,PM P,M M,J J,F} F,L- L,=$ =$@	/>%'9;LN_0.|Z\=*j-Yd		/>%'9;L0.+,
OZ		/>%'8*oZ			/>%'9;LnlJ]J			/>%'8L*o\:z9FXZd			/>%'8nk<UdZY
			/>%'8 "24H/ZY			/.,
O		/(.,
Tc		/>%'9;LL*o			/L*	r"   