
    g1                   
   d dl mZ d dlZd dlmZmZ d dlZd dlmZ d dl	m	Z	 d dl
mZ d dlmZmZmZ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 d dlmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$ d dl%m&Z& d dl'm(Z( erd dl)m*Z*  G d de      Z+ G d de      Z, G d de,e      Z- G d de,eee      Z. G d de,e e!e"      Z/ G d de,e#e$      Z0ejb                   G d de             Z2ejb                   G d de             Z3ejb                   G d d e             Z4 G d! d"e      Z5ejb                   G d# d$e5             Z6ejb                   G d% d&e5             Z7ejb                   G d' d(e5             Z8ejb                   G d) d*e5             Z9ejb                   G d+ d,e5             Z:ejb                   G d- d.e5             Z;ejb                   G d/ d0e5             Z<ejb                   G d1 d2e5             Z=ejb                   G d3 d4e5             Z>ejb                   G d5 d6e5             Z?ejb                   G d7 d8e5             Z@ejb                   G d9 d:e5             ZAejb                   G d; d<e5             ZBejb                   G d= d>e5             ZCejb                   G d? d@e5             ZDejb                   G dA dBe5             ZEejb                   G dC dDe5             ZFejb                   G dE dFe5             ZGejb                   G dG dHe5             ZHejb                   G dI dJe5             ZIejb                   G dK dLe5             ZJejb                   G dM dNe5             ZKejb                   G dO dPe5             ZLejb                   G dQ dRe5             ZMejb                   G dS dTe5             ZNejb                   G dU dVe5             ZOejb                   G dW dXe5             ZPejb                   G dY dZe5             ZQejb                   G d[ d\e5             ZRejb                   G d] d^e5             ZSejb                   G d_ d`e5             ZTejb                   G da dbe5             ZUejb                   G dc dde5             ZVejb                   G de dfe5             ZW G dg dhe      ZX G di dje      ZY G dk dle      ZZ G dm dne      Z[ G do dpe      Z\ G dq dre      Z] G ds dte      Z^ G du dve      Z_ G dw dxe      Z` G dy dze      Zaejb                   G d{ d|e             Zbejb                   G d} d~e             Zcejb                   G d de             Zdy)    )annotationsN)AnyTYPE_CHECKING)defaultdict)datetime)cached_property)parse_qs
quote_plus	urlencodeurlparse)logmediautils)	OPERATORS
PlexObject)
BadRequestNotFound)	MovieEditMixinsShowEditMixinsSeasonEditMixinsEpisodeEditMixinsArtistEditMixinsAlbumEditMixinsTrackEditMixinsPhotoalbumEditMixinsPhotoEditMixins)Setting)
deprecated)Trackc                      e Zd ZdZdZd Zd Zd Zd Zd Z	dd	Z
d
 Zd Zd ZddZd Zd Zd Zd Zd Zd Zd ZddZddZd Zy)LibraryaE   Represents a PlexServer library. This contains all sections of media defined
        in your Plex server including video, shows and audio.

        Attributes:
            key (str): '/library'
            identifier (str): Unknown ('com.plexapp.plugins.library').
            mediaTagVersion (str): Unknown (/system/bundle/media/flags/)
            server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to.
            title1 (str): 'Plex Library' (not sure how useful this is).
            title2 (str): Second title (this is blank on my setup).
    z/libraryc                .   || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        i | _        i | _        y )N
identifiermediaTagVersiontitle1title2)	_dataattribgetr#   r$   r%   r&   _sectionsByID_sectionsByTitleselfdatas     $/opt/Tautulli/lib/plexapi/library.py	_loadDatazLibrary._loadData)   sk    
++//,7#{{/@Akkooh/kkooh/ "    c                   d}i }t        t              }t        t        t        t
        d}| j                  j                  |      D ]  } |j                  |j                  j                  d      t              | j                  ||      }|||j                  <   ||j                  j                         j                            j                  |        || _        t#        |      | _        y)z, Loads and caches all the library sections. z/library/sections)movieshowartistphototype)initpathN)r   listMovieSectionShowSectionMusicSectionPhotoSection_serverqueryr)   r(   LibrarySectionkeytitlelowerstripappendr*   dictr+   )r-   rA   sectionsByIDsectionsByTitlelibclselemsections          r/   _loadSectionszLibrary._loadSections2   s    !%d+!"!	
 LL&&s+ 	KDIfjj!8.I$,,X\gjkG(/L%GMM//1779:AA'J	K
 * $_ 5r1   c                h    | j                          t        | j                  j                               S )a   Returns a list of all media sections in this library. Library sections may be any of
            :class:`~plexapi.library.MovieSection`, :class:`~plexapi.library.ShowSection`,
            :class:`~plexapi.library.MusicSection`, :class:`~plexapi.library.PhotoSection`.
        )rL   r9   r*   valuesr-   s    r/   sectionszLibrary.sectionsF   s*    
 	D&&--/00r1   c                :   |j                         j                         }| j                  r|| j                  vr| j                          	 | j                  |   }t        |      dkD  rt        j                  d       |d   S # t        $ r t        d|       dw xY w)a   Returns the :class:`~plexapi.library.LibrarySection` that matches the specified title.
            Note: Multiple library sections with the same title is ambiguous.
            Use :func:`~plexapi.library.Library.sectionByID` instead for an exact match.

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

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: The library section title is not found on the server.
        zInvalid library section: N   zkMultiple library sections with the same title found, use "sectionByID" instead. Returning the last section.)	rC   rD   r+   rL   KeyErrorr   lenwarningswarn)r-   rB   normalized_titlerP   s       r/   rK   zLibrary.sectionN   s     !;;=..0$$(8@U@U(U 	J,,-=>H x=1MM. |  	J6ug>?TI	Js   
B Bc                    | j                   r|| j                   vr| j                          	 | j                   |   S # t        $ r t        d|       dw xY w)a8   Returns the :class:`~plexapi.library.LibrarySection` that matches the specified sectionID.

            Parameters:
                sectionID (int): ID of the section to return.

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: The library section ID is not found on the server.
        zInvalid library sectionID: N)r*   rL   rT   r   )r-   	sectionIDs     r/   sectionByIDzLibrary.sectionByIDh   sc     !!Yd6H6H%H 	P%%i00 	P8DE4O	Ps	   ; ANc                   |r5t        |t              s|g}dj                  t        t        |            |d<   |r't        |t              s|g}dj                  |      |d<   dt        j                  |       }| j                  |      S )a   Returns a list of :class:`~plexapi.library.Hub` across all library sections.

            Parameters:
                sectionID (int or str or list, optional):
                    IDs of the sections to limit results or "playlists".
                identifier (str or list, optional):
                    Names of identifiers to limit results.
                    Available on `Hub` instances as the `hubIdentifier` attribute.
                    Examples: 'home.continue' or 'home.ondeck'
        ,contentDirectoryIDr#   z/hubs)
isinstancer9   joinmapstrr   joinArgs
fetchItems)r-   rZ   r#   kwargsrA   s        r/   hubszLibrary.hubsx   s     i.&K	+.88CY4G+HF'(j$/(\
#&88J#7F< ennV,-.s##r1   c                    g }| j                         D ]*  } |j                  di |D ]  }|j                  |        , |S )zz Returns a list of all media from all library sections.
            This may be a very large dataset to retrieve.
         )rP   allrE   )r-   re   itemsrK   items        r/   ri   zLibrary.all   sN     }} 	#G#-f- #T"#	# r1   c                $    | j                  d      S )z, Returns a list of all media items on deck. z/library/onDeckrd   rO   s    r/   onDeckzLibrary.onDeck   s    011r1   c                $    | j                  d      S )z3 Returns a list of all media items recently added. z/library/recentlyAddedrm   rO   s    r/   recentlyAddedzLibrary.recentlyAdded   s    788r1   c                    i }|r||d<   |rt        j                  |      |d<   |j                         D ]
  \  }}|||<    dt        j                  |       }| j	                  |      S )a   Searching within a library section is much more powerful. It seems certain
            attributes on the media objects can be targeted to filter this search down
            a bit, but I haven't found the documentation for it.

            Example: "studio=Comedy%20Central" or "year=1999" "title=Kung Fu" all work. Other items
            such as actor=<id> seem to work, but require you already know the id of the actor.
            TLDR: This is untested but seems to work. Use library section search when you can.
        rB   r7   z/library/all)r   
searchTyperj   rc   rd   )r-   rB   libtypere   argsattrvaluerA   s           r/   searchzLibrary.search   ss     !DM ++G4DL!<<> 	KD%DJ	U^^D123s##r1   c                |    | j                   j                  d| j                   j                  j                         | S )a   Poster images and other metadata for items in your library are kept in "bundle"
            packages. When you remove items from your library, these bundles aren't immediately
            removed. Removing these old bundles can reduce the size of your install. By default, your
            server will automatically clean up old bundles once a week as part of Scheduled Tasks.
        z/library/clean/bundles?async=1methodr>   r?   _sessionputrO   s    r/   cleanBundleszLibrary.cleanBundles   s1     	;DLLDYDYD]D]^r1   c                P    | j                         D ]  }|j                           | S )zR If a library has items in the Library Trash, use this option to empty the Trash. )rP   
emptyTrashr-   rK   s     r/   r   zLibrary.emptyTrash   s(    }} 	!G 	!r1   c                |    | j                   j                  d| j                   j                  j                         | S )z The Optimize option cleans up the server database from unused or fragmented data.
            For example, if you have deleted or added an entire library or many items in a
            library, you may like to optimize the database.
        z/library/optimize?async=1ry   r{   rO   s    r/   optimizezLibrary.optimize   s1    
 	6t||?T?T?X?XYr1   c                <    | j                   j                  d       | S )z! Scan this library for new items./library/sections/all/refreshr>   r?   rO   s    r/   updatezLibrary.update   s    :;r1   c                    d}| j                   j                  || j                   j                  j                         | S )z Cancel a library update. r   ry   )r>   r?   r|   deleter-   rA   s     r/   cancelUpdatezLibrary.cancelUpdate   s3    -3t||'<'<'C'CDr1   c                <    | j                   j                  d       | S ) Forces a download of fresh media information from the internet.
            This can take a long time. Any locked fields are not modified.
        z%/library/sections/all/refresh?force=1r   rO   s    r/   refreshzLibrary.refresh   s     	BCr1   c                P    | j                         D ]  }|j                           | S )z Delete the preview thumbnails for the all sections. This cannot be
            undone. Recreating media preview files can take hours or even days.
        )rP   deleteMediaPreviewsr   s     r/   r   zLibrary.deleteMediaPreviews   s*     }} 	*G'')	*r1   c                   t        |t              r|g}g }	|D ]?  }
| j                  j                  |
      st	        d|
 d      |	j                  d|
f       A dt        |       d| d| dt        |       d| d	t        |	d
       }|r8|j                         D ci c]  \  }}d| d| }}}|d	t        |       z  }| j                  j                  || j                  j                  j                        S c c}}w )a,   Simplified add for the most common options.

            Parameters:
                name (str): Name of the library
                agent (str): Example com.plexapp.agents.imdb
                type (str): movie, show, # check me
                location (str or list): /path/to/files, ["/path/to/files", "/path/to/morefiles"]
                language (str): Four letter language code (e.g. en-US)
                kwargs (dict): Advanced options should be passed as a dict. where the id is the key.

            **Photo Preferences**

                * **agent** (str): com.plexapp.agents.none
                * **enableAutoPhotoTags** (bool): Tag photos. Default value false.
                * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true.
                * **includeInGlobal** (bool): Include in dashboard. Default value true.
                * **scanner** (str): Plex Photo Scanner

            **Movie Preferences**

                * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.imdb, tv.plex.agents.movie,
                  com.plexapp.agents.themoviedb
                * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true.
                * **enableCinemaTrailers** (bool): Enable Cinema Trailers. Default value true.
                * **includeInGlobal** (bool): Include in dashboard. Default value true.
                * **scanner** (str): Plex Movie, Plex Movie Scanner, Plex Video Files Scanner, Plex Video Files

            **IMDB Movie Options** (com.plexapp.agents.imdb)

                * **title** (bool): Localized titles. Default value false.
                * **extras** (bool): Find trailers and extras automatically (Plex Pass required). Default value true.
                * **only_trailers** (bool): Skip extras which aren't trailers. Default value false.
                * **redband** (bool): Use red band (restricted audiences) trailers when available. Default value false.
                * **native_subs** (bool): Include extras with subtitles in Library language. Default value false.
                * **cast_list** (int): Cast List Source: Default value 1 Possible options: 0:IMDb,1:The Movie Database.
                * **ratings** (int): Ratings Source, Default value 0 Possible options:
                  0:Rotten Tomatoes, 1:IMDb, 2:The Movie Database.
                * **summary** (int): Plot Summary Source: Default value 1 Possible options: 0:IMDb,1:The Movie Database.
                * **country** (int): Default value 46 Possible options 0:Argentina, 1:Australia, 2:Austria,
                  3:Belgium, 4:Belize, 5:Bolivia, 6:Brazil, 7:Canada, 8:Chile, 9:Colombia, 10:Costa Rica,
                  11:Czech Republic, 12:Denmark, 13:Dominican Republic, 14:Ecuador, 15:El Salvador,
                  16:France, 17:Germany, 18:Guatemala, 19:Honduras, 20:Hong Kong SAR, 21:Ireland,
                  22:Italy, 23:Jamaica, 24:Korea, 25:Liechtenstein, 26:Luxembourg, 27:Mexico, 28:Netherlands,
                  29:New Zealand, 30:Nicaragua, 31:Panama, 32:Paraguay, 33:Peru, 34:Portugal,
                  35:Peoples Republic of China, 36:Puerto Rico, 37:Russia, 38:Singapore, 39:South Africa,
                  40:Spain, 41:Sweden, 42:Switzerland, 43:Taiwan, 44:Trinidad, 45:United Kingdom,
                  46:United States, 47:Uruguay, 48:Venezuela.
                * **collections** (bool): Use collection info from The Movie Database. Default value false.
                * **localart** (bool): Prefer artwork based on library language. Default value true.
                * **adult** (bool): Include adult content. Default value false.
                * **usage** (bool): Send anonymous usage data to Plex. Default value true.

            **TheMovieDB Movie Options** (com.plexapp.agents.themoviedb)

                * **collections** (bool): Use collection info from The Movie Database. Default value false.
                * **localart** (bool): Prefer artwork based on library language. Default value true.
                * **adult** (bool): Include adult content. Default value false.
                * **country** (int): Country (used for release date and content rating). Default value 47 Possible
                  options 0:, 1:Argentina, 2:Australia, 3:Austria, 4:Belgium, 5:Belize, 6:Bolivia, 7:Brazil, 8:Canada,
                  9:Chile, 10:Colombia, 11:Costa Rica, 12:Czech Republic, 13:Denmark, 14:Dominican Republic, 15:Ecuador,
                  16:El Salvador, 17:France, 18:Germany, 19:Guatemala, 20:Honduras, 21:Hong Kong SAR, 22:Ireland,
                  23:Italy, 24:Jamaica, 25:Korea, 26:Liechtenstein, 27:Luxembourg, 28:Mexico, 29:Netherlands,
                  30:New Zealand, 31:Nicaragua, 32:Panama, 33:Paraguay, 34:Peru, 35:Portugal,
                  36:Peoples Republic of China, 37:Puerto Rico, 38:Russia, 39:Singapore, 40:South Africa, 41:Spain,
                  42:Sweden, 43:Switzerland, 44:Taiwan, 45:Trinidad, 46:United Kingdom, 47:United States, 48:Uruguay,
                  49:Venezuela.

            **Show Preferences**

                * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.thetvdb, com.plexapp.agents.themoviedb,
                  tv.plex.agents.series
                * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true.
                * **episodeSort** (int): Episode order. Default -1 Possible options: 0:Oldest first, 1:Newest first.
                * **flattenSeasons** (int): Seasons. Default value 0 Possible options: 0:Show,1:Hide.
                * **includeInGlobal** (bool): Include in dashboard. Default value true.
                * **scanner** (str): Plex TV Series, Plex Series Scanner

            **TheTVDB Show Options** (com.plexapp.agents.thetvdb)

                * **extras** (bool): Find trailers and extras automatically (Plex Pass required). Default value true.
                * **native_subs** (bool): Include extras with subtitles in Library language. Default value false.

            **TheMovieDB Show Options** (com.plexapp.agents.themoviedb)

                * **collections** (bool): Use collection info from The Movie Database. Default value false.
                * **localart** (bool): Prefer artwork based on library language. Default value true.
                * **adult** (bool): Include adult content. Default value false.
                * **country** (int): Country (used for release date and content rating). Default value 47 options
                  0:, 1:Argentina, 2:Australia, 3:Austria, 4:Belgium, 5:Belize, 6:Bolivia, 7:Brazil, 8:Canada, 9:Chile,
                  10:Colombia, 11:Costa Rica, 12:Czech Republic, 13:Denmark, 14:Dominican Republic, 15:Ecuador,
                  16:El Salvador, 17:France, 18:Germany, 19:Guatemala, 20:Honduras, 21:Hong Kong SAR, 22:Ireland,
                  23:Italy, 24:Jamaica, 25:Korea, 26:Liechtenstein, 27:Luxembourg, 28:Mexico, 29:Netherlands,
                  30:New Zealand, 31:Nicaragua, 32:Panama, 33:Paraguay, 34:Peru, 35:Portugal,
                  36:Peoples Republic of China, 37:Puerto Rico, 38:Russia, 39:Singapore, 40:South Africa,
                  41:Spain, 42:Sweden, 43:Switzerland, 44:Taiwan, 45:Trinidad, 46:United Kingdom, 47:United States,
                  48:Uruguay, 49:Venezuela.

            **Other Video Preferences**

                * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.imdb, com.plexapp.agents.themoviedb
                * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true.
                * **enableCinemaTrailers** (bool): Enable Cinema Trailers. Default value true.
                * **includeInGlobal** (bool): Include in dashboard. Default value true.
                * **scanner** (str): Plex Movie Scanner, Plex Video Files Scanner

            **IMDB Other Video Options** (com.plexapp.agents.imdb)

                * **title** (bool): Localized titles. Default value false.
                * **extras** (bool): Find trailers and extras automatically (Plex Pass required). Default value true.
                * **only_trailers** (bool): Skip extras which aren't trailers. Default value false.
                * **redband** (bool): Use red band (restricted audiences) trailers when available. Default value false.
                * **native_subs** (bool): Include extras with subtitles in Library language. Default value false.
                * **cast_list** (int): Cast List Source: Default value 1 Possible options: 0:IMDb,1:The Movie Database.
                * **ratings** (int): Ratings Source Default value 0 Possible options:
                  0:Rotten Tomatoes,1:IMDb,2:The Movie Database.
                * **summary** (int): Plot Summary Source: Default value 1 Possible options: 0:IMDb,1:The Movie Database.
                * **country** (int): Country: Default value 46 Possible options: 0:Argentina, 1:Australia, 2:Austria,
                  3:Belgium, 4:Belize, 5:Bolivia, 6:Brazil, 7:Canada, 8:Chile, 9:Colombia, 10:Costa Rica,
                  11:Czech Republic, 12:Denmark, 13:Dominican Republic, 14:Ecuador, 15:El Salvador, 16:France,
                  17:Germany, 18:Guatemala, 19:Honduras, 20:Hong Kong SAR, 21:Ireland, 22:Italy, 23:Jamaica,
                  24:Korea, 25:Liechtenstein, 26:Luxembourg, 27:Mexico, 28:Netherlands, 29:New Zealand, 30:Nicaragua,
                  31:Panama, 32:Paraguay, 33:Peru, 34:Portugal, 35:Peoples Republic of China, 36:Puerto Rico,
                  37:Russia, 38:Singapore, 39:South Africa, 40:Spain, 41:Sweden, 42:Switzerland, 43:Taiwan, 44:Trinidad,
                  45:United Kingdom, 46:United States, 47:Uruguay, 48:Venezuela.
                * **collections** (bool): Use collection info from The Movie Database. Default value false.
                * **localart** (bool): Prefer artwork based on library language. Default value true.
                * **adult** (bool): Include adult content. Default value false.
                * **usage** (bool): Send anonymous usage data to Plex. Default value true.

            **TheMovieDB Other Video Options** (com.plexapp.agents.themoviedb)

                * **collections** (bool): Use collection info from The Movie Database. Default value false.
                * **localart** (bool): Prefer artwork based on library language. Default value true.
                * **adult** (bool): Include adult content. Default value false.
                * **country** (int): Country (used for release date and content rating). Default
                  value 47 Possible options 0:, 1:Argentina, 2:Australia, 3:Austria, 4:Belgium, 5:Belize,
                  6:Bolivia, 7:Brazil, 8:Canada, 9:Chile, 10:Colombia, 11:Costa Rica, 12:Czech Republic,
                  13:Denmark, 14:Dominican Republic, 15:Ecuador, 16:El Salvador, 17:France, 18:Germany,
                  19:Guatemala, 20:Honduras, 21:Hong Kong SAR, 22:Ireland, 23:Italy, 24:Jamaica,
                  25:Korea, 26:Liechtenstein, 27:Luxembourg, 28:Mexico, 29:Netherlands, 30:New Zealand,
                  31:Nicaragua, 32:Panama, 33:Paraguay, 34:Peru, 35:Portugal,
                  36:Peoples Republic of China, 37:Puerto Rico, 38:Russia, 39:Singapore,
                  40:South Africa, 41:Spain, 42:Sweden, 43:Switzerland, 44:Taiwan, 45:Trinidad,
                  46:United Kingdom, 47:United States, 48:Uruguay, 49:Venezuela.
        Path:  does not exist.locationz/library/sections?name=z&type=z&agent=z	&scanner=z
&language=&Tdoseqzprefs[]ry   )r_   rb   r>   isBrowsabler   rE   r
   r   rj   r?   r|   post)r-   namer7   agentscannerr   languagert   re   	locationspathpartkvprefs_paramss                  r/   addzLibrary.add   s   d h$ zH	 	1D<<++D1 6$/?!@AAj$/0	1
 **T*:);6$wugJw/0
8*AiPYaeFfEgi9?HAfQCqM1,HLHa	,/011D||!!$t||/D/D/I/I!JJ Is    D c                x    g }| j                         D ]$  }|j                  |j                  ||             & |S )z Get Play History for all library Sections for the owner.
            Parameters:
                maxresults (int): Only return the specified number of results (optional).
                mindate (datetime): Min datetime to return results from.
        )
maxresultsmindate)rP   extendhistory)r-   r   r   histrK   s        r/   r   zLibrary.history  s>     }} 	QGKK:wOP	Qr1   c                    t        j                  |      }| j                  j                  d|       }| j	                  |      S )z Returns a list of :class:`~plexapi.library.LibraryMediaTag` objects for the specified tag.

            Parameters:
                tag (str): Tag name (see :data:`~plexapi.utils.TAGTYPES`).
        z/library/tags?type=)r   tagTyper>   r?   	findItems)r-   tagr   r.   s       r/   tagszLibrary.tags  s=     --$||!!$7y"AB~~d##r1   NN) r   r   r   r   zen-US)__name__
__module____qualname____doc__rA   r0   rL   rP   rK   r[   rf   ri   rn   rp   rw   r~   r   r   r   r   r   r   r   r   r   rh   r1   r/   r!   r!      sv    
 C#6(14P $,29$&
_KB	$r1   r!   c                  t    e Zd ZdZd Zed        Zed        Zed        Z	 fdZ
d ZdPdZd	 Zd
 ZdQdZd Zd Zd Zd ZdQdZd Zd Zd Zd Zd Zd Zd Zd ZdPdZdQdZdQdZd Z d Z!d Z"dRdZ#d  Z$d! Z%d" Z&dQd#Z'd$ Z(d% Z)d& Z*d' Z+d( Z,dQd)Z-d* Z.d+ Z/dQd,Z0dQd-Z1dQd.Z2d/ Z3dQd0Z4dQd1Z5d2 Z6dQd3Z7d4 Z8d5 Z9dQd6Z:dQd7Z;d8 Z<dSd9Z=dTd:Z>	 	 dUd;Z?d< Z@dVd=ZAdTd>ZB	 	 dWd?ZCd@ ZDdA ZE	 	 dWdBZFdC ZGdQdDZH eIdE      dQdF       ZJ eIdG      dQdH       ZKdXdIZLdJ ZMdK ZNdQdLZOdM ZPdN ZQdO ZR xZSS )Yr@   a~   Base class for a single library section.

        Attributes:
            agent (str): The metadata agent used for the library section (com.plexapp.agents.imdb, etc).
            allowSync (bool): True if you allow syncing content from the library section.
            art (str): Background artwork used to respresent the library section.
            composite (str): Composite image used to represent the library section.
            createdAt (datetime): Datetime the library section was created.
            filters (bool): True if filters are available for the library section.
            key (int): Key (or ID) of this library section.
            language (str): Language represented in this section (en, xn, etc).
            locations (List<str>): List of folder paths added to the library section.
            refreshing (bool): True if this section is currently being refreshed.
            scanner (str): Internal scanner used to find media (Plex Movie Scanner, Plex Premium Music Scanner, etc.)
            thumb (str): Thumbnail image used to represent the library section.
            title (str): Name of the library section.
            type (str): Type of content section represents (movie, show, artist, photo).
            updatedAt (datetime): Datetime the library section was last updated.
            uuid (str): Unique id for the section (32258d7c-3e6c-4ac5-98ad-bad7a3b78c63)
    c                V   || _         |j                  j                  d      | _        t	        j
                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _	        t	        j                  |j                  j                  d            | _        t	        j
                  t        |j                  j                  d            | _        t	        j
                  t        |j                  j                  d            | _        |j                  j                  d      | _        | j!                  |d	d
      | _        t	        j
                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        t	        j                  |j                  j                  d            | _        |j                  j                  d      | _        d | _        d | _        d | _        d | _        d | _        y )Nr   	allowSyncart	composite	createdAtfiltersrA   r   r   Location)etag
refreshingr   thumbrB   r7   	updatedAtuuid)r'   r(   r)   r   r   castboolr   r   r   
toDatetimer   r   intrA   r   	listAttrsr   r   r   r   rB   r7   r   r   _filterTypes_fieldTypes_totalViewSize_totalDuration_totalStorager,   s     r/   r0   zLibrarySection._loadData  s   
[[__W-
D$++//+*FG;;??5)5))$++//+*FGzz$	(BC::c4;;??5#9:
3f:F**T4;;??<+HI{{y1[[__W-
[[__W-
KKOOF+	))$++//+*FGKKOOF+	 ""!r1   c                &    | j                  d      S )zP Returns the total number of items in the library for the default library type. F)includeCollections)totalViewSizerO   s    r/   	totalSizezLibrarySection.totalSize  s     !!U!;;r1   c                R    | j                   | j                          | j                   S )zG Returns the total duration (in milliseconds) of items in the library. )r   _getTotalDurationStoragerO   s    r/   totalDurationzLibrarySection.totalDuration  s(     &))+"""r1   c                R    | j                   | j                          | j                   S )z? Returns the total storage (in bytes) of items in the library. )r   r   rO   s    r/   totalStoragezLibrarySection.totalStorage  s(     %))+!!!r1   c                l   t         |   |      }|j                  d      r|S t        |      rd|j                  v rwt        | j                  t              st        d      t        | j                  d   d   |      s6t        d| j                  d   d   j                  j                   d| d      |S )	N_Mixinz/Must enable batchMultiEdit() to use this methodrj   r   zBatch multi-editing 'z' object has no attribute '')super__getattribute__
startswithcallabler   r_   _editsrF   AttributeErrorhasattr	__class__r   )r-   ru   rv   r   s      r/   r   zLibrarySection.__getattribute__  s     (.??3E?w%*<*<<dkk40$%VWWT[[1!4d;$+DKK,@,C,M,M,V,V+WWrswrxxyz  r1   c                   | j                   j                  d      }d| j                   d}t        t	        |j                  |            d      }|rqt        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        yy)z[ Queries the Plex server for the total library duration and storage and caches the values. z!/media/providers?includeStorage=1zc./MediaProvider[@identifier="com.plexapp.plugins.library"]/Feature[@type="content"]/Directory[@id="z"]NdurationTotalstorageTotal)r>   r?   rA   nextiterfindallr   r   r   r(   r)   r   r   )r-   r.   xpath	directorys       r/   r   z'LibrarySection._getTotalDurationStorage  s    ||!!"EF#xxj, 	
 dll512D9	"'**S)2B2B2F2F2W"XD!&C1A1A1E1En1U!VD r1   c                b   t        t        |            ddd}|#|dk(  rd|d<   nt        j                  |      |d<   d| j                   dt        j
                  |       }| j                  j                  |      }t        j                  t         |j                  j                  d	            S )
a   Returns the total number of items in the library for a specified libtype.
            The number of items for the default library type will be returned if no libtype is specified.
            (e.g. Specify ``libtype='episode'`` for the total number of episodes
            or ``libtype='albums'`` for the total number of albums.)

            Parameters:
                libtype (str, optional): The type of items to return the total number for (movie, show, season, episode,
                    artist, album, track, photoalbum). Default is the main library type.
                includeCollections (bool, optional): True or False to include collections in the total number.
                    Default is True.
        r   )r   zX-Plex-Container-StartzX-Plex-Container-Sizer6   rR   clusterZoomLevelr7   /library/sections//allr   )r   r   r   rr   rA   rc   r>   r?   r   r(   r)   )r-   rs   r   rt   r   r.   s         r/   r   zLibrarySection.totalViewSize  s     #&d+=&>"?&'%&

 '!+,'($//8V#DHH:T%..2F1GH||!!$'zz#t{{{;<<r1   c                   	 | j                   j                  d| j                   | j                   j                  j                        S # t
        $ r+ d| j                   }|dz  }t        j                  |        w xY w)z Delete a library section. r   ry   zFailed to delete library z<You may need to allow this permission in your Plex settings.)r>   r?   rA   r|   r   r   r   error)r-   msgs     r/   r   zLibrarySection.delete  su    	<<%%(:488*&EdllNcNcNjNj%kk 	-dhhZ8CQQCIIcN		s   AA
 
4A>c                    | j                   j                  j                          | j                   j                  j                  | j                        }| j
                  j                  |j
                         | S )z* Reload the data for the library section. )r>   libraryrL   r[   rA   __dict__r   )r-   
newLibrarys     r/   reloadzLibrarySection.reload  sS    **,\\))55dhh?
Z001r1   c           	        |s| j                   }g }|j                  d      rot        |d   t              r	|d   g|d<   |j	                  d      D ]?  }| j
                  j                  |      st        d| d      |j                  d|f       A t        |j                               |z   }d| j                   d| dt        |d       }| j
                  j                  || j
                  j                  j                  	       | S )
z Edit a library. See :class:`~plexapi.library.Library` for example usage.

            Parameters:
                agent (str, optional): The library agent.
                kwargs (dict): Dict of settings to edit.
        r   r   r   r   z?agent=r   Tr   ry   )r   r)   r_   rb   popr>   r   r   rE   r9   rj   rA   r   r?   r|   r}   )r-   r   re   r   r   paramsr   s          r/   editzLibrarySection.edit$  s     JJE	::j!&,c2&,Z&8%9z"

:. 5||//5$vdV3C%DEE  *d!345
 flln%	1#DHH:WUG1YvUY=Z<[\4(=(=(A(ABr1   c                    | j                   }t        |t              r|g}|D ]=  }| j                  j	                  |      st        d| d      |j                  |       ? | j                  |      S )aY   Add a location to a library.

            Parameters:
                location (str or list): A single folder path, list of paths.

            Example:

                .. code-block:: python

                    LibrarySection.addLocations('/path/1')
                    LibrarySection.addLocations(['/path/1', 'path/2', '/path/3'])

        r   r   r   )r   r_   rb   r>   r   r   rE   r   r-   r   r   r   s       r/   addLocationszLibrarySection.addLocations=  su     NN	h$ zH 	#D<<++D1 6$/?!@AAT"	# yy)y,,r1   c                    | j                   }t        |t              r|g}|D ]&  }||v r|j                  |       t	        d| d       t        |      dk(  rt	        d      | j                  |      S )ad   Remove a location from a library.

            Parameters:
                location (str or list): A single folder path, list of paths.

            Example:

                .. code-block:: python

                    LibrarySection.removeLocations('/path/1')
                    LibrarySection.removeLocations(['/path/1', 'path/2', '/path/3'])

        r   z does not exist in the library.r   z6You are unable to remove all locations from a library.r   )r   r_   rb   remover   rU   r   r   s       r/   removeLocationszLibrarySection.removeLocationsT  s     NN	h$ zH 	UDy   & 6(3R!STT		U
 y>QUVVyy)y,,r1   c                    	  | j                   |fddi|d   S # t        $ r d| d}|r|d| z  }t        |      dw xY w)a   Returns the media item with the specified title and kwargs.

            Parameters:
                title (str): Title of the item to return.
                kwargs (dict): Additional search parameters.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: The title is not found in the library.
        limitrR   r   z Unable to find item with title 'r   z and kwargs N)rw   
IndexErrorr   )r-   rB   re   r   s       r/   r)   zLibrarySection.getn  sd    	*4;;u8A88;; 	*4UG1=CfX..3-T)		*s	    &A c                V   	 |j                  d      r| j                  |      d   }|S | j                  d      d   }|j                  | j                  |j	                  dd            }| j                  |d   j
                        d   S # t        $ r t        d	| d
      dw xY w)a   Returns the media item with the specified external Plex, IMDB, TMDB, or TVDB ID.
            Note: Only available for the Plex Movie and Plex TV Series agents.

            Parameters:
                guid (str): The external guid of the item to return.
                    Examples: Plex ``plex://show/5d9c086c46115600200aa2fe``
                    IMDB ``imdb://tt0944947``, TMDB ``tmdb://1399``, TVDB ``tvdb://121361``.

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: The guid is not found in the library.

            Example:

                .. code-block:: python

                    result1 = library.getGuid('plex://show/5d9c086c46115600200aa2fe')
                    result2 = library.getGuid('imdb://tt0944947')
                    result3 = library.getGuid('tmdb://1399')
                    result4 = library.getGuid('tvdb://121361')

                    # Alternatively, create your own guid lookup dictionary for faster performance
                    guidLookup = {}
                    for item in library.all():
                        guidLookup[item.guid] = item
                        guidLookup.update({guid.id: item for guid in item.guids})

                    result1 = guidLookup['plex://show/5d9c086c46115600200aa2fe']
                    result2 = guidLookup['imdb://tt0944947']
                    result3 = guidLookup['tmdb://1399']
                    result4 = guidLookup['tvdb://121361']

        zplex://)guidr   rR   )r   z://-)r   rB   zGuid 'z' is not found in the libraryN)r   rw   matchesr   replacer  r  r   )r-   r  resultdummymatchs        r/   getGuidzLibrarySection.getGuid  s    D		Sy)$/2q1!4DJJdll5RU>VW{{a{6q99 	SVD6)FGHdR	Ss   'B A#B B(c                J    |xs | j                   } | j                  dd|i|S )z Returns a list of all items from this library section.
            See description of :func:`~plexapi.library.LibrarySection.search()` for details about filtering / sorting.
        rs   rh   TYPErw   r-   rs   re   s      r/   ri   zLibrarySection.all  s+     &TYYt{{575f55r1   c                N    d| j                    d}| j                  |t              S )z` Returns a list of available :class:`~plexapi.library.Folder` for this library section.
        r   z/folder)rA   rd   Folderr   s     r/   folderszLibrarySection.folders  s'     #488*G4sF++r1   c                N    d| j                    d}| j                  |t              S )zd Returns a list of available :class:`~plexapi.library.ManagedHub` for this library section.
        /hubs/sections//manage)rA   rd   
ManagedHubr   s     r/   managedHubszLibrarySection.managedHubs  s'      z1sJ//r1   c                    d| j                    d}| j                  j                  || j                  j                  j                         y)zH Reset the managed hub customizations for this library section.
        r  r  ry   NrA   r>   r?   r|   r   r   s     r/   resetManagedHubszLibrarySection.resetManagedHubs  s=      z13t||'<'<'C'CDr1   c                D    d| j                    d}| j                  |      S )z] Returns a list of available :class:`~plexapi.library.Hub` for this library section.
        r  z?includeStations=1rA   rd   r   s     r/   rf   zLibrarySection.hubs  s&      z);<s##r1   c                L    | j                   j                  | j                        S )z] Returns a list of available :class:`~plexapi.media.Agent` for this library section.
        )r>   agentsr7   rO   s    r/   r   zLibrarySection.agents  s     ||""499--r1   c                    d| j                    d}| j                  j                  |      }| j                  |t              S )z) Returns a list of all library settings. r   z/prefscls)rA   r>   r?   r   r   r-   rA   r.   s      r/   settingszLibrarySection.settings  s;    "488*F3||!!#&~~d~00r1   c           
        i }i }d}| j                         D ]=  }|j                  dk7  r|j                  ||j                  <   ,ddd||j                  <   ? |j	                         D ]3  \  }}	 ||   }||v r|||j                  |      <   %t        | d|         | j                  di |S # t
        $ r( t        | dt        |j                                      w xY w)z% Edit a library's advanced settings. 	prefs[{}]r   FT)r   rR   z not found in rh   )r%  r7   
enumValuesidrj   rT   r   r9   keysformatr   )	r-   re   r.   idEnumsrA   setting	settingIDrv   enumss	            r/   editAdvancedzLibrarySection.editAdvanced  s   }} 	:G||v%&-&8&8

#*/D&9

#		: !' 	@IuO	* ~.3SZZ	*+%ug>??	@ tyy 4    O%tGLLN7K6LMNNOs   .B//1C c                *   i }d}| j                         D ]k  }|j                  dk(  r2t        |j                        ||j	                  |j
                        <   D|j                  ||j	                  |j
                        <   m  | j                  di |S )z5 Edit all of library's advanced settings to default. r'  r   rh   )r%  r7   r   defaultr+  r)  r   )r-   r.   rA   r-  s       r/   defaultAdvancedzLibrarySection.defaultAdvanced  s~    }} 	?G||v%/27??/CSZZ

+,/6SZZ

+,		? tyy 4  r1   c                0   |xs | j                   }dt        j                  |      | dt        |      i}d| j                   dt        j
                  |       }| j                  j                  || j                  j                  j                         | S )z6 Lock or unlock a field for all items in the library. r7   z.lockedr   r   ry   )
r  r   rr   r   rA   rc   r>   r?   r|   r}   )r-   fieldrs   lockedrt   rA   s         r/   _lockUnlockAllFieldz"LibrarySection._lockUnlockAllField  s    &TYYE$$W-gWs6{
 #488*D1E0FG3t||'<'<'@'@Ar1   c                *    | j                  ||d      S )a_   Lock a field for all items in the library.

            Parameters:
                field (str): The field to lock (e.g. thumb, rating, collection).
                libtype (str, optional): The library type to lock (movie, show, season, episode,
                    artist, album, track, photoalbum, photo). Default is the main library type.
        Trs   r6  r7  r-   r5  rs   s      r/   lockAllFieldzLibrarySection.lockAllField  s     ''wt'LLr1   c                *    | j                  ||d      S )ac   Unlock a field for all items in the library.

            Parameters:
                field (str): The field to unlock (e.g. thumb, rating, collection).
                libtype (str, optional): The library type to lock (movie, show, season, episode,
                    artist, album, track, photoalbum, photo). Default is the main library type.
        Fr9  r:  r;  s      r/   unlockAllFieldzLibrarySection.unlockAllField  s     ''wu'MMr1   c                p    d| j                    d}| j                  j                  |      }t        | |      S )z4 Returns a timeline query for this library section. r   z	/timeline)rA   r>   r?   LibraryTimeliner$  s      r/   timelinezLibrarySection.timeline  s5    "488*I6||!!#&tT**r1   c                D    d| j                    d}| j                  |      S )zB Returns a list of media items on deck from this library section. r   z/onDeckr  r   s     r/   rn   zLibrarySection.onDeck!  #    "488*G4s##r1   c                D    d| j                    d}| j                  |      S )zF Return a list of media items in the library's Continue Watching hub. r  z/continueWatching/itemsr  r   s     r/   continueWatchingzLibrarySection.continueWatching&  s$    z)@As##r1   c                J    |xs | j                   }| j                  d||      S )a{   Returns a list of media items recently added from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
                libtype (str, optional): The library type to filter (movie, show, season, episode,
                    artist, album, track, photoalbum, photo). Default is the main library type.
        addedAt:desc)sortr   rs   r  )r-   r   rs   s      r/   rp   zLibrarySection.recentlyAdded+  s'     &TYY{{:w{WWr1   c                P    d| j                    d}| j                  |t              S )Nr   z/firstCharacterr"  )rA   rd   FirstCharacterr   s     r/   firstCharacterzLibrarySection.firstCharacter6  s'    "488*O<s77r1   c                    d| j                    d}| j                  j                  || j                  j                  j                         | S )z Run an analysis on all of the items in this library section. See
            See :func:`~plexapi.base.PlexPartialObject.analyze` for more details.
        r   z/analyzery   rA   r>   r?   r|   r}   r   s     r/   analyzezLibrarySection.analyze:  sB     #488*H53t||'<'<'@'@Ar1   c                    d| j                    d}| j                  j                  || j                  j                  j                         | S )zJ If a section has items in the Trash, use this option to empty the Trash. r   z/emptyTrashry   rM  r   s     r/   r   zLibrarySection.emptyTrashB  s@    "488*K83t||'<'<'@'@Ar1   c                    d| j                    d}||dt        |       z  }| j                  j                  |       | S )z Scan this section for new media.

            Parameters:
                path (str, optional): Full path to folder to scan.
        r   /refreshz?path=)rA   r
   r>   r?   )r-   r   rA   s      r/   r   zLibrarySection.updateH  sJ     #488*H5VJt,-..C3r1   c                    d| j                    d}| j                  j                  || j                  j                  j                         | S )z( Cancel update of this Library Section. r   rQ  ry   r  r   s     r/   r   zLibrarySection.cancelUpdateT  s@    "488*H53t||'<'<'C'CDr1   c                \    d| j                    d}| j                  j                  |       | S )r   r   z/refresh?force=1)rA   r>   r?   r   s     r/   r   zLibrarySection.refreshZ  s.     #488*,<=3r1   c                    d| j                    d}| j                  j                  || j                  j                  j                         | S )z Delete the preview thumbnails for items in this library. This cannot
            be undone. Recreating media preview files can take hours or even days.
        r   z/indexesry   r  r   s     r/   r   z"LibrarySection.deleteMediaPreviewsb  sB     #488*H53t||'<'<'C'CDr1   c                >   d}|j                  | j                  d      }| j                  j                  |      }| j	                  |t
        d      | _        | j	                  |t        d      | _        | j                  dk7  ri|j                  | j                  d      }| j                  j                  |      }| j                  j                  | j	                  |t
        d             d}| j                  j                  | j                  |t                     y	)
z Retrieves and caches the list of :class:`~plexapi.library.FilteringType` and
            list of :class:`~plexapi.library.FilteringFieldType` for this library section.
        zq/library/sections/{key}/{filter}?includeMeta=1&includeAdvanced=1&X-Plex-Container-Start=0&X-Plex-Container-Size=0ri   )rA   filterMeta)rtagr6   collectionszA<FieldType type="guid"><Operator key="=" title="is"/></FieldType>N)r+  rA   r>   r?   r   FilteringTyper   FilteringFieldTyper   r  r   rE   _manuallyLoadXML)r-   _keyrA   r.   guidFieldTypes        r/   _loadFilterszLibrarySection._loadFiltersj  s    D kkdhhuk5||!!#& NN4VNL>>$0B>P99++$((=+AC<<%%c*D$$T^^D-f^%UV \ 5 5mEW XYr1   c                R    | j                   | j                          | j                   S )z_ Returns a list of available :class:`~plexapi.library.FilteringType` for this library section. )r   r_  rO   s    r/   filterTypeszLibrarySection.filterTypes  s&    $   r1   c                   xs | j                   	 t        fd| j                         D              S # t        $ r@ | j                         D cg c]  }|j                   nc c}w }}t        d d|       dw xY w)a   Returns a :class:`~plexapi.library.FilteringType` for a specified libtype.

            Parameters:
                libtype (str, optional): The library type to filter (movie, show, season, episode,
                    artist, album, track, photoalbum, photo, collection).

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: Unknown libtype for this library.
        c              3  B   K   | ]  }|j                   k(  s|  y wNr7   ).0frs   s     r/   	<genexpr>z/LibrarySection.getFilterType.<locals>.<genexpr>  s     Ka79JK   zUnknown libtype "z(" for this library. Available libtypes: N)r  r   ra  StopIterationr7   r   )r-   rs   rg  availableLibtypess    `  r/   getFilterTypezLibrarySection.getFilterType  s     &TYY	QK4#3#3#5KKK 	Q151A1A1C DA D D D.wi 822C1DF GLPQ	Qs   !5 A>A$#A>c                R    | j                   | j                          | j                   S )zd Returns a list of available :class:`~plexapi.library.FilteringFieldType` for this library section. )r   r_  rO   s    r/   
fieldTypeszLibrarySection.fieldTypes  s&    #r1   c                    	 t        fd| j                         D              S # t        $ r@ | j                         D cg c]  }|j                   nc c}w }}t	        d d|       dw xY w)a   Returns a :class:`~plexapi.library.FilteringFieldType` for a specified fieldType.

            Parameters:
                fieldType (str): The data type for the field (tag, integer, string, boolean, date,
                    subtitleLanguage, audioLanguage, resolution).

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: Unknown fieldType for this library.
        c              3  B   K   | ]  }|j                   k(  s|  y wrd  re  )rf  rg  	fieldTypes     r/   rh  z.LibrarySection.getFieldType.<locals>.<genexpr>  s     La)8KLri  zUnknown field type "z+" for this library. Available field types: N)r   rn  rj  r7   r   )r-   rq  rg  availableFieldTypess    `  r/   getFieldTypezLibrarySection.getFieldType  s~    	VL4??#4LLL 	V37??3D"Ea166"E"E"E1) =55H4IK LQUV	Vs   !% A. AA.c                8    | j                  |      j                  S )a   Returns a list of available :class:`~plexapi.library.FilteringFilter` for a specified libtype.
            This is the list of options in the filter dropdown menu
            (`screenshot <../_static/images/LibrarySection.listFilters.png>`__).

            Parameters:
                libtype (str, optional): The library type to filter (movie, show, season, episode,
                    artist, album, track, photoalbum, photo, collection).

            Example:

                .. code-block:: python

                    availableFilters = [f.filter for f in library.listFilters()]
                    print("Available filter fields:", availableFilters)

        )rl  r   r-   rs   s     r/   listFilterszLibrarySection.listFilters  s    " !!'*222r1   c                8    | j                  |      j                  S )a   Returns a list of available :class:`~plexapi.library.FilteringSort` for a specified libtype.
            This is the list of options in the sorting dropdown menu
            (`screenshot <../_static/images/LibrarySection.listSorts.png>`__).

            Parameters:
                libtype (str, optional): The library type to filter (movie, show, season, episode,
                    artist, album, track, photoalbum, photo, collection).

            Example:

                .. code-block:: python

                    availableSorts = [f.key for f in library.listSorts()]
                    print("Available sort fields:", availableSorts)

        )rl  sortsru  s     r/   	listSortszLibrarySection.listSorts  s    " !!'*000r1   c                8    | j                  |      j                  S )a   Returns a list of available :class:`~plexapi.library.FilteringFields` for a specified libtype.
            This is the list of options in the custom filter dropdown menu
            (`screenshot <../_static/images/LibrarySection.search.png>`__).

            Parameters:
                libtype (str, optional): The library type to filter (movie, show, season, episode,
                    artist, album, track, photoalbum, photo, collection).

            Example:

                .. code-block:: python

                    availableFields = [f.key.split('.')[-1] for f in library.listFields()]
                    print("Available fields:", availableFields)

        )rl  fieldsru  s     r/   
listFieldszLibrarySection.listFields  s    " !!'*111r1   c                8    | j                  |      j                  S )ap   Returns a list of available :class:`~plexapi.library.FilteringOperator` for a specified fieldType.
            This is the list of options in the custom filter operator dropdown menu
            (`screenshot <../_static/images/LibrarySection.search.png>`__).

            Parameters:
                fieldType (str): The data type for the field (tag, integer, string, boolean, date,
                    subtitleLanguage, audioLanguage, resolution).

            Example:

                .. code-block:: python

                    field = 'genre'  # Available filter field from listFields()
                    filterField = next(f for f in library.listFields() if f.key.endswith(field))
                    availableOperators = [o.key for o in library.listOperators(filterField.type)]
                    print(f"Available operators for {field}:", availableOperators)

        )rs  	operators)r-   rq  s     r/   listOperatorszLibrarySection.listOperators  s    &   +555r1   c           	        t        t              rqt        j                  d      }|st	        d       |j                         \  }|xs |xs | j                  }	 t        fd| j                  |      D              | j                  j                  j                        }| j                  |t               S # t        $ rD | j                  |      D cg c]  }|j                   nc c}w }}t        d d| d|       dw xY w)a   Returns a list of available :class:`~plexapi.library.FilterChoice` for a specified
            :class:`~plexapi.library.FilteringFilter` or filter field.
            This is the list of available values for a custom filter
            (`screenshot <../_static/images/LibrarySection.search.png>`__).

            Parameters:
                field (str): :class:`~plexapi.library.FilteringFilter` object,
                    or the name of the field (genre, year, contentRating, etc.).
                libtype (str, optional): The library type to filter (movie, show, season, episode,
                    artist, album, track, photoalbum, photo, collection).

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: Invalid filter field.
                :exc:`~plexapi.exceptions.NotFound`: Unknown filter field.

            Example:

                .. code-block:: python

                    field = 'genre'  # Available filter field from listFilters()
                    availableChoices = [f.title for f in library.listFilterChoices(field)]
                    print(f"Available choices for {field}:", availableChoices)

        z(?:([a-zA-Z]*)\.)?([a-zA-Z]+)Invalid filter field: c              3  B   K   | ]  }|j                   k(  s|  y wrd  )rV  rf  rg  r5  s     r/   rh  z3LibrarySection.listFilterChoices.<locals>.<genexpr>  s     W1QXXQVEVQWri  Unknown filter field "" for libtype "z". Available filters: N)r_   rb   rer  r   groupsr  r   rv  rj  rV  r   r>   r?   rA   r   FilterChoice)r-   r5  rs   r  _libtyperg  availableFiltersr.   s    `      r/   listFilterChoicesz LibrarySection.listFilterChoices  s   2 eS!HH=uEE #9%!ABB#llnOHe6'6TYYGSW(8(8(AWW ||!!%)),~~dL11 ! S6:6F6Fw6O#PAHH#P#P #P!7wogY W55E4F H INRSSs    #B> >DC.-Dc           	        t        j                  d      }|st        d       |j                         \  }}|xs |xs | j                  }	 t        fd| j                  |      D              }|j                  | j                  ||      }| j                  |||      }|d	k(  r|i}t!        |d
      S |dd z   dj#                  |      i}t!        |      S # t        $ r t        | j                               D ]5  }|j                  |k7  st        fd|j                  D        d      }|s5 nD | j                  |      D 	cg c]  }	|	j                   nc c}	w }
}	t        d d| d|
       dY w xY w)z Validates a filter field and values are available as a custom filter for the library.
            Returns the validated field and values as a URL encoded parameter string.
        z'(?:([a-zA-Z]*)\.)?([a-zA-Z]+)([!<>=&]*)r  c              3  f   K   | ](  }|j                   j                  d       d   k(  s%| * yw.rS   NrA   splitr  s     r/   rh  z6LibrarySection._validateFilterField.<locals>.<genexpr>0  s-     dQaeekkRUFVWYFZ^cFcqd   &11c              3  f   K   | ](  }|j                   j                  d       d   k(  s%| * ywr  r  r  s     r/   rh  z6LibrarySection._validateFilterField.<locals>.<genexpr>4  s-     'faTWHXY[H\`eHe'fr  Nr  r  z". Available filter fields: &=Tr   rS   r]   )r  r  r   r  r  r   r|  rj  reversedra  r7   r{  rA   r   _validateFieldOperator_validateFieldValuer   r`   )r-   r5  rN   rs   r  r  operatorfilterField
filterTyperg  availableFieldsr
  rt   s    `           r/   _validateFilterFieldz#LibrarySection._validateFilterField%  s    CUK5eW=>>$)LLN!%2g2	Xd$//'*BddK ..{HE))+vwGt6?DT..HSbM)388F+;<DT?")  		X&t'7'7'9: X
??g-"&'f:3D3D'fhl"mK"	X 37//'2J"KQ155"K"K"K!7wogY W;;J:K M NSWX 		Xs*   #C 4F !F 6F E F ?F c           	        | j                  |j                        }d}dv rd}d|j                  dk(  r	dv rdz  dd	 dk(  rd	d ndz   	 t        fd
|j                  D               |rdS S # t        $ rX | j                  |j                        D cg c]  }|j                   nc c}w }}t        d d|j                   d|       d	w xY w)zu Validates filter operator is in the available operators.
            Returns the validated operator string.
        F>   r   r  Tr   string>   !==r  rS   Nc              3  B   K   | ]  }|j                   k(  s|  y wrd  rA   )rf  or  s     r/   rh  z8LibrarySection._validateFieldOperator.<locals>.<genexpr>V  s     Eq155H3DEri  zUnknown operator "" for filter field "z". Available operators: r  )rs  r7   r   r~  rj  r  rA   r   )r-   r  r  rq  and_operatorr  availableOperatorss     `    r/   r  z%LibrarySection._validateFieldOperatorG  s    %%k&6&67	{"LH>>X%(k*AOH%-bc]c%9HSbMx3N	SEI//EE $t11  	S151C1CKDTDT1U!VA!%%!V!V!V/z9MkooM^ _33E2FH INRS	Ss   A6 6&CB0/(Cc           	        t        |t        t        f      s|g}| j                  |j                        }g }	 |D ]  }|j                  dk(  rt        t        |            }n|j                  dk(  r| j                  |      }no|j                  dk(  r$dt        |      v rt        |      n
t        |      }n<|j                  dk(  rt        |      }n!|j                  dv r| j                  |||      }|j                  t        |              	 |S # t        t        f$ r* t        d d|j                   d	|j                         d
w xY w)z Validates filter values are the correct datatype and in the available filter choices.
            Returns the validated list of values.
        booleandateintegerr  r  >   r   
resolutionaudioLanguagesubtitleLanguagezInvalid value "r  z", value should be type N)r_   r9   tuplers  r7   r   r   _validateFieldValueDaterb   float_validateFieldValueTagrE   
ValueErrorr   r   rA   )r-   r  rN   rs   rq  resultsrv   s          r/   r  z"LibrarySection._validateFieldValue^  sD    &4-0XF%%k&6&67		Q +>>Y.U,E^^v- 88?E^^y0,/3u:,=E%L3u:E^^x/JE^^'aa 77{GTEs5z*+  	 N+ 	Qug5I+//IZ [55>^^4DF GLPQ	Qs   CD 9E	c                   t        |t              rt        |j                               S t	        j
                  d|      rd|j                  d      z   S t        t        j                  |d      j                               S )z Validates a filter date value. A filter date value can be a datetime object,
            a relative date (e.g. -30d), or a date in YYYY-MM-DD format.
        z^-?\d+(mon|[smhdwy])$r  z%Y-%m-%d)	r_   r   r   	timestampr  r  lstripr   r   )r-   rv   s     r/   r  z&LibrarySection._validateFieldValueDate{  sd     eX&u())XX.6c***u''z:DDFGGr1   c                \   t        |t              r|j                  S t        |t        j                  t
        f      r$t        |j                  xs |j                        }nt        |      }| j                  |j                  |      }|j                         t        fd|D        |      S )a   Validates a filter tag value. A filter tag value can be a :class:`~plexapi.library.FilterChoice` object,
            a :class:`~plexapi.media.MediaTag` object, the exact name :attr:`MediaTag.tag` (*str*),
            or the exact id :attr:`MediaTag.id` (*int*).
        c              3     K   | ]G  }|j                   j                         |j                  j                         hv s:|j                    I y wrd  )rA   rC   rB   )rf  rg  
matchValues     r/   rh  z8LibrarySection._validateFieldValueTag.<locals>.<genexpr>  s;     dqZAEEKKMSTSZSZS`S`SbCc5cQUUds
   ;AA)r_   r  rA   r   MediaTagLibraryMediaTagrb   r)  r   r  rC   r   )r-   rv   r  rs   filterChoicesr  s        @r/   r  z%LibrarySection._validateFieldValueTag  s    
 e\*99eenno>?-EII.EJE..{H[[]
dMdfkllr1   c                    t        |t              r|j                  d      }t        |t        t        f      s|g}g }|D ]#  }|j                  | j                  ||             % dj                  |      S )a   Validates a list of filter sort fields is available for the library. Sort fields can be a
            list of :class:`~plexapi.library.FilteringSort` objects, or a comma separated string.
            Returns the validated comma separated sort fields string.
        r]   )r_   rb   r  r9   r  rE   _validateSortFieldr`   )r-   rH  rs   validatedSorts_sorts        r/   _validateSortFieldsz"LibrarySection._validateSortFields  sr    
 dC ::c?D$u.6D 	KE!!$"9"9%"IJ	K xx''r1   c           	       
 t        |t              r,|xs | j                   d|j                   d|j                   S t        j                  d|j                               }|st        d|       |j                         \  }
}|xs |xs | j                  }	 t        
fd| j                  |      D              }|dz   |j                  z   
g d
}	||	vrt        d| d|	       |r
 d| S 
S # t        $ rD | j                  |      D cg c]  }|j                   nc c}w }}t        d
 d| d|       d	w xY w)z Validates a filter sort field is available for the library. A sort field can be a
            :class:`~plexapi.library.FilteringSort` object, or a string.
            Returns the validated sort field string.
        r  :z*(?:([a-zA-Z]*)\.)?([a-zA-Z]+):?([a-zA-Z]*)zInvalid filter sort: c              3  B   K   | ]  }|j                   k(  s|  y wrd  r  )rf  rg  	sortFields     r/   rh  z4LibrarySection._validateSortField.<locals>.<genexpr>  s     WAAEEYDVaWri  zUnknown sort field "r  z". Available sort fields: N)r   ascdesc	nullsLastzUnknown sort direction "z". Available sort directions: )r_   FilteringSortr  rA   defaultDirectionr  r  rD   r   r  r   ry  rj  r   )r-   rH  rs   r  r  sortDir
filterSortrg  availableSortsavailableDirectionsr  s             @r/   r  z!LibrarySection._validateSortField  sj   
 dM**+1TXXJa8M8M7NOOF

U4TF;<<',||~$)W2g2	QW)@WWJ cMJNN2	>--5gY>\]p\qrss+2)AgY'A	A  	Q-1^^G-DEaeeEENE1)OG9 U55C4DF GLPQ	Qs   #C4 4ED$#Ec                <   t        |t              st        d      g }|j                         D ]  \  }}|j	                         dv rt        |j                               dkD  rt        d      t        |t              st        d      |j                  d       |D ]E  }|j                  | j                  ||             |j                  |j	                          d       G |d= |j                  d	       |j                  | j                  |||              |S )
z Validates an advanced search filter dictionary.
            Returns the list of validated URL encoded parameter strings for the advanced search.
        zFilters must be a dictionary.>   orandrR   z@Multiple keys in the same dictionary with and/or is not allowed.z5Value for and/or keys must be a list of dictionaries.zpush=1z=1rS   zpop=1)r_   rF   r   rj   rC   rU   r9   rE   r   _validateAdvancedSearchr  )r-   r   rs   validatedFiltersr5  rN   rv   s          r/   r  z&LibrarySection._validateAdvancedSearch  s    '4(<==$]]_ 	[ME6{{}-w}}'!+$%ghh!&$/$%\]] ''1# BE$++D,H,HPW,XY$++u{{}oR,@AB %R( ''0 !''(A(A%QX(YZ#	[&  r1   c                :   i }g }	t        t        |j                  dd                  |d<   t        |j	                               D ]E  \  }
}|
j                  d      d   t        vs!|	j                  | j                  |
||             ||
= G |>t        |t        t        f      r#|	j                  | j                  d||             n||d<   |!|	j                  | j                  ||             || j                  ||      |d<   |t        j                  |      |d<   |||d<   t        j                   |      j#                  d	      }|	rd
j%                  |	      nd}d
j%                  ||g      j'                  d
      }d| j(                   d| }|r||fS |S )z Returns the validated and formatted search query API key
            (``/library/sections/<sectionKey>/all?<params>``).
        includeGuidsT__rS   rB   rH  r7   r  ?r   r   r   z/all?)r   r   r   r9   rj   r  r   rE   r  r_   r  r   r  r  r   rr   rc   r  r`   rD   rA   )r-   rB   rH  rs   r  r   returnKwargsre   rt   filter_argsr5  rN   joined_argsjoined_filter_argsr   rA   s                   r/   _buildSearchKeyzLibrarySection._buildSearchKey  s    "4

>4(H#IJ^!&,,.1 	"ME6{{4 $I5""4#<#<UFG#TU5M	" %$/""4#<#<WeW#UV %Wt;;GWMN33D'BDL ++G4DL!DMnnT*11#66ASXXk2r;(:;<BB3G"488*E&:;
r1   c                T    | j                   j                  |||| j                        S )z Returns the hub search results for this library. See :func:`plexapi.server.PlexServer.search`
            for details and parameters.
        )	sectionId)r>   rw   rA   )r-   r?   	mediatyper  s       r/   	hubSearchzLibrarySection.hubSearch  s&     ||""5)Udhh"OOr1   c	           
     h     | j                   d|||||dd|	\  }
}	 | j                  |
f|||d|	S )a5   Search the library. The http requests will be batched in container_size. If you are only looking for the
            first <num> results, it would be wise to set the maxresults option to that amount so the search doesn't iterate
            over all results on the server.

            Parameters:
                title (str, optional): General string query to search for. Partial string matches are allowed.
                sort (:class:`~plexapi.library.FilteringSort` or str or list, optional): A field to sort the results.
                    See the details below for more info.
                maxresults (int, optional): Only return the specified number of results.
                libtype (str, optional): Return results of a specific type (movie, show, season, episode,
                    artist, album, track, photoalbum, photo, collection) (e.g. ``libtype='episode'`` will only
                    return :class:`~plexapi.video.Episode` objects)
                container_start (int, optional): Default 0.
                container_size (int, optional): Default X_PLEX_CONTAINER_SIZE in your config file.
                limit (int, optional): Limit the number of results from the filter.
                filters (dict, optional): A dictionary of advanced filters. See the details below for more info.
                **kwargs (dict): Additional custom filters to apply to the search results.
                    See the details below for more info.

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: When the sort or filter is invalid.
                :exc:`~plexapi.exceptions.NotFound`: When applying an unknown sort or filter.

            **Sorting Results**

            The search results can be sorted by including the ``sort`` parameter.

            * See :func:`~plexapi.library.LibrarySection.listSorts` to get a list of available sort fields.

            The ``sort`` parameter can be a :class:`~plexapi.library.FilteringSort` object or a sort string in the
            format ``field:dir``. The sort direction ``dir`` can be ``asc``, ``desc``, or ``nullsLast``. Omitting the
            sort direction or using a :class:`~plexapi.library.FilteringSort` object will sort the results in the default
            direction of the field. Multi-sorting on multiple fields can be achieved by using a comma separated list of
            sort strings, or a list of :class:`~plexapi.library.FilteringSort` object or strings.

            Examples:

                .. code-block:: python

                    library.search(sort="titleSort:desc")  # Sort title in descending order
                    library.search(sort="titleSort")  # Sort title in the default order
                    # Multi-sort by year in descending order, then by audience rating in descending order
                    library.search(sort="year:desc,audienceRating:desc")
                    library.search(sort=["year:desc", "audienceRating:desc"])

            **Using Plex Filters**

            Any of the available custom filters can be applied to the search results
            (`screenshot <../_static/images/LibrarySection.search.png>`__).

            * See :func:`~plexapi.library.LibrarySection.listFields` to get a list of all available fields.
            * See :func:`~plexapi.library.LibrarySection.listOperators` to get a list of all available operators.
            * See :func:`~plexapi.library.LibrarySection.listFilterChoices` to get a list of all available filter values.

            The following filter fields are just some examples of the possible filters. The list is not exhaustive,
            and not all filters apply to all library types.

            * **actor** (:class:`~plexapi.media.MediaTag`): Search for the name of an actor.
            * **addedAt** (*datetime*): Search for items added before or after a date. See operators below.
            * **audioLanguage** (*str*): Search for a specific audio language (3 character code, e.g. jpn).
            * **collection** (:class:`~plexapi.media.MediaTag`): Search for the name of a collection.
            * **contentRating** (:class:`~plexapi.media.MediaTag`): Search for a specific content rating.
            * **country** (:class:`~plexapi.media.MediaTag`): Search for the name of a country.
            * **decade** (*int*): Search for a specific decade (e.g. 2000).
            * **director** (:class:`~plexapi.media.MediaTag`): Search for the name of a director.
            * **duplicate** (*bool*) Search for duplicate items.
            * **genre** (:class:`~plexapi.media.MediaTag`): Search for a specific genre.
            * **hdr** (*bool*): Search for HDR items.
            * **inProgress** (*bool*): Search for in progress items.
            * **label** (:class:`~plexapi.media.MediaTag`): Search for a specific label.
            * **lastViewedAt** (*datetime*): Search for items watched before or after a date. See operators below.
            * **mood** (:class:`~plexapi.media.MediaTag`): Search for a specific mood.
            * **producer** (:class:`~plexapi.media.MediaTag`): Search for the name of a producer.
            * **resolution** (*str*): Search for a specific resolution (e.g. 1080).
            * **studio** (*str*): Search for the name of a studio.
            * **style** (:class:`~plexapi.media.MediaTag`): Search for a specific style.
            * **subtitleLanguage** (*str*): Search for a specific subtitle language (3 character code, e.g. eng)
            * **unmatched** (*bool*): Search for unmatched items.
            * **unwatched** (*bool*): Search for unwatched items.
            * **userRating** (*int*): Search for items with a specific user rating.
            * **writer** (:class:`~plexapi.media.MediaTag`): Search for the name of a writer.
            * **year** (*int*): Search for a specific year.

            Tag type filter values can be a :class:`~plexapi.library.FilterChoice` object,
            :class:`~plexapi.media.MediaTag` object, the exact name :attr:`MediaTag.tag` (*str*),
            or the exact id :attr:`MediaTag.id` (*int*).

            Date type filter values can be a ``datetime`` object, a relative date using a one of the
            available date suffixes (e.g. ``30d``) (*str*), or a date in ``YYYY-MM-DD`` (*str*) format.

            Relative date suffixes:

            * ``s``: ``seconds``
            * ``m``: ``minutes``
            * ``h``: ``hours``
            * ``d``: ``days``
            * ``w``: ``weeks``
            * ``mon``: ``months``
            * ``y``: ``years``

            Multiple values can be ``OR`` together by providing a list of values.

            Examples:

                .. code-block:: python

                    library.search(unwatched=True, year=2020, resolution="4k")
                    library.search(actor="Arnold Schwarzenegger", decade=1990)
                    library.search(contentRating="TV-G", genre="animation")
                    library.search(genre=["animation", "comedy"])  # Genre is animation OR comedy
                    library.search(studio=["Disney", "Pixar"])  # Studio contains Disney OR Pixar

            **Using a** ``libtype`` **Prefix**

            Some filters may be prefixed by the ``libtype`` separated by a ``.`` (e.g. ``show.collection``,
            ``episode.title``, ``artist.style``, ``album.genre``, ``track.userRating``, etc.). This should not be
            confused with the ``libtype`` parameter. If no ``libtype`` prefix is provided, then the default library
            type is assumed. For example, in a TV show library ``viewCount`` is assumed to be ``show.viewCount``.
            If you want to filter using episode view count then you must specify ``episode.viewCount`` explicitly.
            In addition, if the filter does not exist for the default library type it will fallback to the most
            specific ``libtype`` available. For example, ``show.unwatched`` does not exists so it will fallback to
            ``episode.unwatched``. The ``libtype`` prefix cannot be included directly in the function parameters so
            the filters must be provided as a filters dictionary.

            Examples:

                .. code-block:: python

                    library.search(filters={"show.collection": "Documentary", "episode.inProgress": True})
                    library.search(filters={"artist.genre": "pop", "album.decade": 2000})

                    # The following three options are identical and will return Episode objects
                    showLibrary.search(title="Winter is Coming", libtype='episode')
                    showLibrary.search(libtype='episode', filters={"episode.title": "Winter is Coming"})
                    showLibrary.searchEpisodes(title="Winter is Coming")

                    # The following will search for the episode title but return Show objects
                    showLibrary.search(filters={"episode.title": "Winter is Coming"})

                    # The following will fallback to episode.unwatched
                    showLibrary.search(unwatched=True)

            **Using Plex Operators**

            Operators can be appended to the filter field to narrow down results with more granularity.
            The following is a list of possible operators depending on the data type of the filter being applied.
            A special ``&`` operator can also be used to ``AND`` together a list of values.

            Type: :class:`~plexapi.media.MediaTag` or *subtitleLanguage* or *audioLanguage*

            * no operator: ``is``
            * ``!``: ``is not``

            Type: *int*

            * no operator: ``is``
            * ``!``: ``is not``
            * ``>>``: ``is greater than``
            * ``<<``: ``is less than``

            Type: *str*

            * no operator: ``contains``
            * ``!``: ``does not contain``
            * ``=``: ``is``
            * ``!=``: ``is not``
            * ``<``: ``begins with``
            * ``>``: ``ends with``

            Type: *bool*

            * no operator: ``is true``
            * ``!``: ``is false``

            Type: *datetime*

            * ``<<``: ``is before``
            * ``>>``: ``is after``

            Type: *resolution* or *guid*

            * no operator: ``is``

            Operators cannot be included directly in the function parameters so the filters
            must be provided as a filters dictionary.

            Examples:

                .. code-block:: python

                    # Genre is horror AND thriller
                    library.search(filters={"genre&": ["horror", "thriller"]})

                    # Director is not Steven Spielberg
                    library.search(filters={"director!": "Steven Spielberg"})

                    # Title starts with Marvel and added before 2021-01-01
                    library.search(filters={"title<": "Marvel", "addedAt<<": "2021-01-01"})

                    # Added in the last 30 days using relative dates
                    library.search(filters={"addedAt>>": "30d"})

                    # Collection is James Bond and user rating is greater than 8
                    library.search(filters={"collection": "James Bond", "userRating>>": 8})

            **Using Advanced Filters**

            Any of the Plex filters described above can be combined into a single ``filters`` dictionary that mimics
            the advanced filters used in Plex Web with a tree of ``and``/``or`` branches. Each level of the tree must
            start with ``and`` (Match all of the following) or ``or`` (Match any of the following) as the dictionary
            key, and a list of dictionaries with the desired filters as the dictionary value.

            The following example matches `this <../_static/images/LibrarySection.search_filters.png>`__ advanced filter
            in Plex Web.

            Examples:

                .. code-block:: python

                    advancedFilters = {
                        'and': [                            # Match all of the following in this list
                            {
                                'or': [                     # Match any of the following in this list
                                    {'title': 'elephant'},
                                    {'title': 'bunny'}
                                ]
                            },
                            {'year>>': 1990},
                            {'unwatched': True}
                        ]
                    }
                    library.search(filters=advancedFilters)

            **Using PlexAPI Operators**

            For even more advanced filtering which cannot be achieved in Plex, the PlexAPI operators can be applied
            to any XML attribute. See :func:`plexapi.base.PlexObject.fetchItems` for a list of operators and how they
            are used. Note that using the Plex filters above will be faster since the filters are applied by the Plex
            server before the results are returned to PlexAPI. Using the PlexAPI operators requires the Plex server
            to return *all* results to allow PlexAPI to do the filtering. The Plex filters and the PlexAPI operators
            can be used in conjunction with each other.

            Examples:

                .. code-block:: python

                    library.search(summary__icontains="Christmas")
                    library.search(duration__gt=7200000)
                    library.search(audienceRating__lte=6.0, audienceRatingImage__startswith="rottentomatoes://")
                    library.search(media__videoCodec__exact="h265")
                    library.search(genre="holiday", viewCount__gte=3)

        T)rB   rH  rs   r  r   r  )container_startcontainer_sizer   rh   )r  rd   )r-   rB   rH  r   rs   r  r  r  r   re   rA   s              r/   rw   zLibrarySection.search
  sh    ~ +d** pdG5'`dphnpVtr!0\frjpr 	rr1   c                B    | j                  | j                  t              S )zF Returns a list of :class:`~plexapi.library.Location` objects
        )r   r'   r   rO   s    r/   
_locationszLibrarySection._locations  s     ~~djj(33r1   c                   ddl m}	 | j                  st        d      | j                  j                         }
 |	| j                  d      }|r|n| j                  |_        | j                  |_        | j                  |_	        | j                  |_        | j                  j                  |_         | j                  d	|||d|}d| j                   dt        |       |_        ||_        ||_        |
j'                  |||      S )
a   Add current library section as sync item for specified device.
            See description of :func:`~plexapi.library.LibrarySection.search` for details about filtering / sorting
            and :func:`~plexapi.myplex.MyPlexAccount.sync` for possible exceptions.

            Parameters:
                policy (:class:`~plexapi.sync.Policy`): policy of syncing the media (how many items to sync and process
                                                       watched media or not), generated automatically when method
                                                       called on specific LibrarySection object.
                mediaSettings (:class:`~plexapi.sync.MediaSettings`): Transcoding settings used for the media, generated
                                                                     automatically when method called on specific
                                                                     LibrarySection object.
                client (:class:`~plexapi.myplex.MyPlexDevice`): sync destination, see
                                                               :func:`~plexapi.myplex.MyPlexAccount.sync`.
                clientId (str): sync destination, see :func:`~plexapi.myplex.MyPlexAccount.sync`.
                title (str): descriptive title for the new :class:`~plexapi.sync.SyncItem`, if empty the value would be
                             generated from metadata of current media.
                sort (str): formatted as `column:dir`; column can be any of {`addedAt`, `originallyAvailableAt`,
                            `lastViewedAt`, `titleSort`, `rating`, `mediaHeight`, `duration`}. dir can be `asc` or
                            `desc`.
                libtype (str): Filter results to a specific libtype (`movie`, `show`, `episode`, `artist`, `album`,
                               `track`).

            Returns:
                :class:`~plexapi.sync.SyncItem`: an instance of created syncItem.

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: When the library is not allowed to sync.
                :exc:`~plexapi.exceptions.BadRequest`: When the sort or filter is invalid.
                :exc:`~plexapi.exceptions.NotFound`: When applying an unknown sort or filter.

            Example:

                .. code-block:: python

                    from plexapi import myplex
                    from plexapi.sync import Policy, MediaSettings, VIDEO_QUALITY_3_MBPS_720p

                    c = myplex.MyPlexAccount()
                    target = c.device('Plex Client')
                    sync_items_wd = c.syncItems(target.clientIdentifier)
                    srv = c.resource('Server Name').connect()
                    section = srv.library.section('Movies')
                    policy = Policy('count', unwatched=True, value=1)
                    media_settings = MediaSettings.create(VIDEO_QUALITY_3_MBPS_720p)
                    section.sync(target, policy, media_settings, title='Next best movie', sort='rating:desc')

        r   )SyncItemz,The requested library is not allowed to syncN)rB   rH  rs   z
library://z/directory/)clientclientId	sync_itemrh   )plexapi.syncr  r   r   r>   myPlexAccountrB   	rootTitleCONTENT_TYPEcontentTypeMETADATA_TYPEmetadataTypemachineIdentifierr  r   r
   r   policymediaSettingssync)r-   r  r  r  r  rB   rH  rs   re   r  myplexr  rA   s                r/   r  zLibrarySection.sync  s    b 	*~~KLL++-T\\40	#(%djj	"jj	 $ 1 1	!%!3!3	&*ll&D&D	#"d""UT7UfU)$))K
3?PQ	!	"/	{{&8y{QQr1   c                T    | j                   j                  ||| j                  d      S )z Get Play History for this library Section for the owner.
            Parameters:
                maxresults (int): Only return the specified number of results (optional).
                mindate (datetime): Min datetime to return results from.
        rR   )r   r   librarySectionID	accountID)r>   r   rA   )r-   r   r   s      r/   r   zLibrarySection.historyY  s*     ||##z7]a]e]eqr#ssr1   c                L     | j                   j                  |f| ||||||d|S )z Alias for :func:`~plexapi.server.PlexServer.createCollection` using this
            :class:`~plexapi.library.LibrarySection`.
        )rK   rj   smartr  rs   rH  r   )r>   createCollection)	r-   rB   rj   r  r  rs   rH  r   re   s	            r/   r  zLibrarySection.createCollectiona  sA    
 -t||,,CuE$C;AC 	Cr1   c                j    	 | j                  ||      d   S # t        $ r t        d| d      dw xY w)z Returns the collection with the specified title.

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

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: Unable to find collection.
        rB   title__iexactr   z&Unable to find collection with title "".N)rY  r  r   r-   rB   s     r/   
collectionzLibrarySection.collectionj  sL    	Y##%u#EaHH 	YCE7"MNTXX	Y    2c                *     | j                   dddi|S )z Returns a list of collections from this library section.
            See description of :func:`~plexapi.library.LibrarySection.search` for details about filtering / sorting.
        rs   r  rh   rw   r-   re   s     r/   rY  zLibrarySection.collectionsx  s     t{{:<:6::r1   c                L     | j                   j                  |f| ||||||d|S )z Alias for :func:`~plexapi.server.PlexServer.createPlaylist` using this
            :class:`~plexapi.library.LibrarySection`.
        )rK   rj   r  r  rH  r   m3ufilepath)r>   createPlaylist)	r-   rB   rj   r  r  rH  r   r  re   s	            r/   r	  zLibrarySection.createPlaylist~  sA    
 +t||**KuEwKKCIK 	Kr1   c                j    	 | j                  ||      d   S # t        $ r t        d| d      dw xY w)z Returns the playlist with the specified title.

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

            Raises:
                :exc:`~plexapi.exceptions.NotFound`: Unable to find playlist.
        r  r   z$Unable to find playlist with title "r   N)	playlistsr  r   r  s     r/   playlistzLibrarySection.playlist  sI    	W>>U>CAFF 	WA%KLRVV	Wr  c                j     | j                   j                  d| j                  | j                  |d|S )z8 Returns a list of playlists from this library section. )playlistTyper  rH  rh   )r>   r  r  rA   )r-   rH  re   s      r/   r  zLibrarySection.playlists  s=    %t||%% U**dhhTUMSU 	Ur1   zuse "listFields" insteadc                &    | j                  |      S )N)rs   )r|  )r-   	mediaTypes     r/   filterFieldszLibrarySection.filterFields  s    y11r1   zuse "listFilterChoices" insteadc                (    | j                  ||      S )N)r5  rs   )r  )r-   categoryrs   re   s       r/   listChoiceszLibrarySection.listChoices  s    %%Hg%FFr1   c                    d| j                   i}|||d<   |
||d<   d|d<    | j                  j                  dd|i|S )aZ   Returns the Plex Web URL for the library.

            Parameters:
                base (str): The base URL before the fragment (``#!``).
                    Default is https://app.plex.tv/desktop.
                tab (str): The library tab (recommended, library, collections, playlists, timeline).
                key (str): A hub key.
        sourcepivotrA   r9   pageTypebaserh   )rA   r>   _buildWebURL)r-   r  tabrA   r   s        r/   	getWebURLzLibrarySection.getWebURL  sW     DHH%?!F7O?F5M!'F:(t||((=d=f==r1   c                2   ||g k(  rt        d      t        |t              s|g}|d   j                  }|D ]]  }|j                  | j
                  k7  rt        |j                   d      |j                  |k7  sDt        d| d|j                          |S )zK Validates the specified items are from this library and of the same type. zNo items specified.r   z is not from this library.z$Cannot mix items of different type: z and )r   r_   r9   r7   r  rA   rB   )r-   rj   itemTyperk   s       r/   _validateItemszLibrarySection._validateItems  s    =ERK233%&GE8== 	dD$$0 DJJ</I!JKKh& #GzQVW[W`W`Va!bcc		d r1   c                   dj                  d | j                  |      D              t        j                  |d   j                        d}d| j
                   dt        j                  |       }| j                  |t              S )zL Returns a :class:`~plexapi.library.Common` object for the specified items. r]   c              3  F   K   | ]  }t        |j                          y wrd  rb   	ratingKeyrf  rk   s     r/   rh  z(LibrarySection.common.<locals>.<genexpr>  s     V43t~~.V   !r   )r)  r7   r   z/commonr"  )	r`   r  r   rr   r7   rA   rc   	fetchItemCommon)r-   rj   r   r   s       r/   commonzLibrarySection.common  ss     ((V4;N;Nu;UVV$$U1X]]3
 $DHH:WU^^F5K4LM~~d~//r1   c                   t        | j                  t              r|| j                  j                  |       | S dj	                  d | j                  |      D              |d<   d|vr%t        j                  |d   j                        |d<   d| j                   dt        j                  |       }| j                  j                  || j                  j                  j                         | S )	z! Actually edit multiple objects. r]   c              3  F   K   | ]  }t        |j                          y wrd  r"  r$  s     r/   rh  z'LibrarySection._edit.<locals>.<genexpr>  s     [DNN 3[r%  r)  r7   r   r   r   ry   )r_   r   rF   r   r`   r  r   rr   r7   rA   rc   r>   r?   r|   r}   )r-   rj   re   r   s       r/   _editzLibrarySection._edit  s    dkk4(U]KKv&Kxx[@S@STY@Z[[t"--eAhmm<F6N#DHH:T%..2H1IJ4(=(=(A(ABr1   c                (     | j                   |fi |S )a
   Edit multiple objects at once.
            Note: This is a low level method and you need to know all the field/tag keys.
            See :class:`~plexapi.LibrarySection.batchMultiEdits` instead.

            Parameters:
                items (List): List of :class:`~plexapi.audio.Audio`, :class:`~plexapi.video.Video`,
                    :class:`~plexapi.photo.Photo`, or :class:`~plexapi.collection.Collection`
                    objects to be edited.
                kwargs (dict): Dict of settings to edit.
        )r+  )r-   rj   re   s      r/   	multiEditzLibrarySection.multiEdit  s     tzz%*6**r1   c                6    d| j                  |      i| _        | S )a   Enable batch multi-editing mode to save API calls.
            Must call :func:`~plexapi.library.LibrarySection.saveMultiEdits` at the end to save all the edits.
            See :class:`~plexapi.mixins.EditFieldMixin` and :class:`~plexapi.mixins.EditTagsMixin`
            for individual field and tag editing methods.

            Parameters:
                items (List): List of :class:`~plexapi.audio.Audio`, :class:`~plexapi.video.Video`,
                    :class:`~plexapi.photo.Photo`, or :class:`~plexapi.collection.Collection`
                    objects to be edited.

            Example:

                .. code-block:: python

                    movies = MovieSection.all()
                    items = [movies[0], movies[3], movies[5]]

                    # Batch multi-editing multiple fields and tags in a single API call
                    MovieSection.batchMultiEdits(items)
                    MovieSection.editTitle('A New Title').editSummary('A new summary').editTagline('A new tagline') \
                        .addCollection('New Collection').removeGenre('Action').addLabel('Favorite')
                    MovieSection.saveMultiEdits()

        rj   )r  r   )r-   rj   s     r/   batchMultiEditszLibrarySection.batchMultiEdits  s     2  3 3E :;r1   c                    t        | j                  t              st        d      | j                  }d| _         | j                  dd|j                  d      i| | S )z~ Save all the batch multi-edits.
            See :func:`~plexapi.library.LibrarySection.batchMultiEdits` for details.
        zJBatch multi-editing mode not enabled. Must call `batchMultiEdits()` first.Nrj   rh   )r_   r   rF   r   r+  r   )r-   editss     r/   saveMultiEditszLibrarySection.saveMultiEdits  sR     $++t,ijj

57+5u5r1   )NTrd  )2   N)NNNNNFr   )NNNNNNNN)NNNNN)NFNNNNNNN)Tr   r   r   r   r0   r   r   propertyr   r   r   r   r   r   r   r   r   r  r)   r  ri   r  r  r  rf   r   r%  r0  r3  r7  r<  r>  rA  rn   rE  rp   rK  rN  r   r   r   r   r   r_  ra  rl  rn  rs  rv  ry  r|  r  r  r  r  r  r  r  r  r  r  r  r  rw   r  r  r   r  r  rY  r	  r  r  r   r  r  r  r  r(  r+  r-  r/  r2  __classcell__r   s   @r/   r@   r@     s   *"2 < < # # " "W=42-.-4*&+SZ6,0E$.
1!0
!	MN+$
$
	X8
Z*!Q$ V"3&1&2&6*'2R #D2.:	Hm("B: <!FP FJNRBrH4
DRLt FJ:>CY; DH<@KWU
 *+2 ,2 12G 3G>""0+8
r1   r@   c                  B     e Zd ZdZdZdZdZdZd ZddZ	d	 fd	Z
 xZS )
r:   z Represents a :class:`~plexapi.library.LibrarySection` section containing movies.

        Attributes:
            TAG (str): 'Directory'
            TYPE (str): 'movie'
    	Directoryr3   videoc                *     | j                   dddi|S )zS Search for a movie. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   r3   rh   r  r  s     r/   searchMovieszMovieSection.searchMovies      t{{575f55r1   c                (    | j                  |d      S )z Returns a list of recently added movies from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        r3   r   rs   rp   r-   r   s     r/   recentlyAddedMoviesz MovieSection.recentlyAddedMovies!       !!Z!IIr1   c                    ddl m}m} |j                  |      |d<   |j	                  ||      |d<   t        t        |   di |S )a   Add current Movie library section as sync item for specified device.
            See description of :func:`~plexapi.library.LibrarySection.search` for details about filtering / sorting and
            :func:`~plexapi.library.LibrarySection.sync` for details on syncing libraries and possible exceptions.

            Parameters:
                videoQuality (int): idx of quality of the video, one of VIDEO_QUALITY_* values defined in
                                    :mod:`~plexapi.sync` module.
                limit (int): maximum count of movies to sync, unlimited if `None`.
                unwatched (bool): if `True` watched videos wouldn't be synced.

            Returns:
                :class:`~plexapi.sync.SyncItem`: an instance of created syncItem.

            Example:

                .. code-block:: python

                    from plexapi import myplex
                    from plexapi.sync import VIDEO_QUALITY_3_MBPS_720p

                    c = myplex.MyPlexAccount()
                    target = c.device('Plex Client')
                    sync_items_wd = c.syncItems(target.clientIdentifier)
                    srv = c.resource('Server Name').connect()
                    section = srv.library.section('Movies')
                    section.sync(VIDEO_QUALITY_3_MBPS_720p, client=target, limit=1, unwatched=True,
                                 title='Next best movie', sort='rating:desc')

        r   PolicyMediaSettingsr  r  rh   )r  rF  rG  createVideocreater   r:   r  r-   videoQualityr  	unwatchedre   rF  rG  r   s          r/   r  zMovieSection.sync)  sG    < 	7"/";";L"I!==	:x\4-777r1   r3  NF)r   r   r   r   TAGr  r  r  r<  rB  r  r6  r7  s   @r/   r:   r:     s3     CDML6J!8 !8r1   r:   c                  ^     e Zd ZdZdZdZdZdZd Zd Z	d Z
dd	Zdd
ZddZd fd	Z xZS )r;   z Represents a :class:`~plexapi.library.LibrarySection` section containing tv shows.

        Attributes:
            TAG (str): 'Directory'
            TYPE (str): 'show'
    r9  r4   episoder:  c                *     | j                   dddi|S )zR Search for a show. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   r4   rh   r  r  s     r/   searchShowszShowSection.searchShowsY  s    t{{464V44r1   c                *     | j                   dddi|S )zT Search for a season. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   seasonrh   r  r  s     r/   searchSeasonszShowSection.searchSeasons]      t{{686v66r1   c                *     | j                   dddi|S )zV Search for an episode. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   rQ  rh   r  r  s     r/   searchEpisodeszShowSection.searchEpisodesa  s    t{{79777r1   c                (    | j                  |d      S )z Returns a list of recently added shows from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        r4   r?  r@  rA  s     r/   recentlyAddedShowszShowSection.recentlyAddedShowse  s     !!Z!HHr1   c                (    | j                  |d      S )z Returns a list of recently added seasons from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        rU  r?  r@  rA  s     r/   recentlyAddedSeasonsz ShowSection.recentlyAddedSeasonsm       !!Z!JJr1   c                (    | j                  |d      S )z Returns a list of recently added episodes from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        rQ  r?  r@  rA  s     r/   recentlyAddedEpisodesz!ShowSection.recentlyAddedEpisodesu  s     !!Z!KKr1   c                    ddl m}m} |j                  |      |d<   |j	                  ||      |d<   t        t        |   di |S )a   Add current Show library section as sync item for specified device.
            See description of :func:`~plexapi.library.LibrarySection.search` for details about filtering / sorting and
            :func:`~plexapi.library.LibrarySection.sync` for details on syncing libraries and possible exceptions.

            Parameters:
                videoQuality (int): idx of quality of the video, one of VIDEO_QUALITY_* values defined in
                                    :mod:`~plexapi.sync` module.
                limit (int): maximum count of episodes to sync, unlimited if `None`.
                unwatched (bool): if `True` watched videos wouldn't be synced.

            Returns:
                :class:`~plexapi.sync.SyncItem`: an instance of created syncItem.

            Example:

                .. code-block:: python

                    from plexapi import myplex
                    from plexapi.sync import VIDEO_QUALITY_3_MBPS_720p

                    c = myplex.MyPlexAccount()
                    target = c.device('Plex Client')
                    sync_items_wd = c.syncItems(target.clientIdentifier)
                    srv = c.resource('Server Name').connect()
                    section = srv.library.section('TV-Shows')
                    section.sync(VIDEO_QUALITY_3_MBPS_720p, client=target, limit=1, unwatched=True,
                                 title='Next unwatched episode')

        r   rE  r  r  rh   )r  rF  rG  rH  rI  r   r;   r  rJ  s          r/   r  zShowSection.sync}  sG    < 	7"/";";L"I!==	:x[$,6v66r1   rM  rN  )r   r   r   r   rO  r  r  r  rS  rV  rY  r[  r]  r`  r  r6  r7  s   @r/   r;   r;   M  sI     CDML578IKL!7 !7r1   r;   c                       e Zd ZdZdZdZdZdZd Zd Z	d Z
d	 Zd
 ZddZddZddZd fd	Z	 	 	 	 	 	 	 	 ddZ xZS )r<   z Represents a :class:`~plexapi.library.LibrarySection` section containing music artists.

        Attributes:
            TAG (str): 'Directory'
            TYPE (str): 'artist'
    r9  r5   trackaudioc                D    d| j                    d}| j                  |      S )zJ Returns a list of :class:`~plexapi.audio.Album` objects in this section. r   z/albumsr  r   s     r/   albumszMusicSection.albums  rC  r1   c                D    t        d | j                         D        d      S )zQ Returns a list of :class:`~plexapi.playlist.Playlist` stations in this section. c              3  T   K   | ]   }|j                   d k(  s|j                   " yw)zhub.music.stationsN)contextrj   )rf  hubs     r/   rh  z(MusicSection.stations.<locals>.<genexpr>  s      ]3H\9\SYY]s   ((N)r   rf   rO   s    r/   stationszMusicSection.stations  s    ]$))+]_cddr1   c                *     | j                   dddi|S )zU Search for an artist. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   r5   rh   r  r  s     r/   searchArtistszMusicSection.searchArtists  rW  r1   c                *     | j                   dddi|S )zT Search for an album. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   albumrh   r  r  s     r/   searchAlbumszMusicSection.searchAlbums  r=  r1   c                *     | j                   dddi|S )zS Search for a track. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   rc  rh   r  r  s     r/   searchTrackszMusicSection.searchTracks  r=  r1   c                (    | j                  |d      S )z Returns a list of recently added artists from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        r5   r?  r@  rA  s     r/   recentlyAddedArtistsz!MusicSection.recentlyAddedArtists  r^  r1   c                (    | j                  |d      S )z Returns a list of recently added albums from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        ro  r?  r@  rA  s     r/   recentlyAddedAlbumsz MusicSection.recentlyAddedAlbums  rC  r1   c                (    | j                  |d      S )z Returns a list of recently added tracks from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        rc  r?  r@  rA  s     r/   recentlyAddedTracksz MusicSection.recentlyAddedTracks  rC  r1   c                    ddl m}m} |j                  |      |d<   |j	                  |      |d<   t        t        |   di |S )a8   Add current Music library section as sync item for specified device.
            See description of :func:`~plexapi.library.LibrarySection.search` for details about filtering / sorting and
            :func:`~plexapi.library.LibrarySection.sync` for details on syncing libraries and possible exceptions.

            Parameters:
                bitrate (int): maximum bitrate for synchronized music, better use one of MUSIC_BITRATE_* values from the
                               module :mod:`~plexapi.sync`.
                limit (int): maximum count of tracks to sync, unlimited if `None`.

            Returns:
                :class:`~plexapi.sync.SyncItem`: an instance of created syncItem.

            Example:

                .. code-block:: python

                    from plexapi import myplex
                    from plexapi.sync import AUDIO_BITRATE_320_KBPS

                    c = myplex.MyPlexAccount()
                    target = c.device('Plex Client')
                    sync_items_wd = c.syncItems(target.clientIdentifier)
                    srv = c.resource('Server Name').connect()
                    section = srv.library.section('Music')
                    section.sync(AUDIO_BITRATE_320_KBPS, client=target, limit=100, sort='addedAt:desc',
                                 title='New music')

        r   rE  r  r  rh   )r  rF  rG  createMusicrI  r   r<   r  )r-   bitrater  re   rF  rG  r   s         r/   r  zMusicSection.sync  sE    : 	7"/";";G"D!==/x\4-777r1   c                    t        |t              r|n|j                  }t        |t              r|n|j                  }d| j                   d| d| } | j                  |fi |S )a   Returns a list of tracks from this library section that are part of a sonic adventure.
            ID's should be of a track, other ID's will return an empty list or items itself or an error.

            Parameters:
                start (Track | int): The :class:`~plexapi.audio.Track` or ID of the first track in the sonic adventure.
                end (Track | int): The :class:`~plexapi.audio.Track` or ID of the last track in the sonic adventure.
                kwargs: Additional parameters to pass to :func:`~plexapi.base.PlexObject.fetchItems`.

            Returns:
                List[:class:`~plexapi.audio.Track`]: a list of tracks from this library section
                that are part of a sonic adventure.
        r   z/computePath?startID=z&endID=)r_   r   r#  rA   rd   )r-   startendre   startIDendIDrA   s          r/   sonicAdventurezMusicSection.sonicAdventure  sa    & &eS1%u!#s+"488*,A''RWQXYts-f--r1   rM  rd  )r}  Track | intr~  r  re   r   returnzlist[Track])r   r   r   r   rO  r  r  r  rf  rk  rm  rp  rr  rt  rv  rx  r  r  r6  r7  s   @r/   r<   r<     s{     CDML$
e766KJJ 8D.. . 	.
 
.r1   r<   c                  V     e Zd ZdZdZdZdZdZd
dZd Z	d Z
d ZddZd
 fd		Z xZS )r=   z Represents a :class:`~plexapi.library.LibrarySection` section containing photos.

        Attributes:
            TAG (str): 'Directory'
            TYPE (str): 'photo'
    r9  r6   c                6    |xs d} | j                   dd|i|S )z Returns a list of all items from this library section.
            See description of :func:`plexapi.library.LibrarySection.search()` for details about filtering / sorting.
        
photoalbumrs   rh   r  r  s      r/   ri   zPhotoSection.all"  s'     )\t{{575f55r1   c                    t        d      )Nz2Collections are not available for a Photo library.)NotImplementedErrorr  s     r/   rY  zPhotoSection.collections)  s    !"VWWr1   c                *     | j                   dddi|S )zY Search for a photo album. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   r  rh   r  r  s     r/   rp  zPhotoSection.searchAlbums,  s    t{{:<:6::r1   c                *     | j                   dddi|S )zS Search for a photo. See :func:`~plexapi.library.LibrarySection.search` for usage. rs   r6   rh   r  r  s     r/   searchPhotoszPhotoSection.searchPhotos0  r=  r1   c                (    | j                  d|      S )z Returns a list of recently added photo albums from this library section.

            Parameters:
                maxresults (int): Max number of items to return (default 50).
        rG  )rH  r   r  rA  s     r/   rv  z PhotoSection.recentlyAddedAlbums4  s     {{:{FFr1   c                    ddl m}m} |j                  |      |d<   |j	                  |      |d<   t        t        |   di |S )a6   Add current Music library section as sync item for specified device.
            See description of :func:`~plexapi.library.LibrarySection.search` for details about filtering / sorting and
            :func:`~plexapi.library.LibrarySection.sync` for details on syncing libraries and possible exceptions.

            Parameters:
                resolution (str): maximum allowed resolution for synchronized photos, see PHOTO_QUALITY_* values in the
                                  module :mod:`~plexapi.sync`.
                limit (int): maximum count of tracks to sync, unlimited if `None`.

            Returns:
                :class:`~plexapi.sync.SyncItem`: an instance of created syncItem.

            Example:

                .. code-block:: python

                    from plexapi import myplex
                    from plexapi.sync import PHOTO_QUALITY_HIGH

                    c = myplex.MyPlexAccount()
                    target = c.device('Plex Client')
                    sync_items_wd = c.syncItems(target.clientIdentifier)
                    srv = c.resource('Server Name').connect()
                    section = srv.library.section('Photos')
                    section.sync(PHOTO_QUALITY_HIGH, client=target, limit=100, sort='addedAt:desc',
                                 title='Fresh photos')

        r   rE  r  r  rh   )r  rF  rG  createPhotorI  r   r=   r  )r-   r  r  re   rF  rG  r   s         r/   r  zPhotoSection.sync=  sE    : 	7"/";";J"G!==/x\4-777r1   rd  rM  )r   r   r   r   rO  r  r  r  ri   rY  rp  r  rv  r  r6  r7  s   @r/   r=   r=     sC     CDML6X;6G 8  8r1   r=   c                      e Zd ZdZd Zd Zy)r@  a  Represents a LibrarySection timeline.

        Attributes:
            TAG (str): 'LibraryTimeline'
            size (int): Unknown
            allowSync (bool): Unknown
            art (str): Relative path to art image.
            content (str): "secondary"
            identifier (str): "com.plexapp.plugins.library"
            latestEntryTime (int): Epoch timestamp
            mediaTagPrefix (str): "/system/bundle/media/flags/"
            mediaTagVersion (int): Unknown
            thumb (str): Relative path to library thumb image.
            title1 (str): Name of library section.
            updateQueueSize (int): Number of items queued to update.
            viewGroup (str): "secondary"
            viewMode (int): Unknown
    c                r   || _         t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _	        |j                  j                  d      | _
        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d	      | _        |j                  j                  d
      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        y)/ Load attribute values from Plex XML response. sizer   r   contentr#   latestEntryTimemediaTagPrefixr$   r   r%   updateQueueSize	viewGroupviewModeN)r'   r   r   r   r(   r)   r  r   r   r   r  r#   r  r  r$   r   r%   r  r  r  r,   s     r/   r0   zLibraryTimeline._loadDatav  sW   
JJsDKKOOF$;<	D$++//+*FG;;??5){{y1++//,7$zz#t{{?P/QR"kkoo.>?$zz#t{{?P/QR[[__W-
kkooh/$zz#t{{?P/QR5

3
(CDr1   Nr   r   r   r   rO  r0   rh   r1   r/   r@  r@  `  s    $ CEr1   r@  c                      e Zd ZdZd Zd Zy)r   z Represents a single library Location.

        Attributes:
            TAG (str): 'Location'
            id (int): Location path ID.
            path (str): Path used for library..
    c                    || _         t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        y)r  r)  r   N)r'   r   r   r   r(   r)   r)  r   r,   s     r/   r0   zLocation._loadData  s<    
**S$++//$"78KKOOF+	r1   Nr  rh   r1   r/   r   r     s     C,r1   r   c                  ,    e Zd ZdZd Zd Zd Zd Zd Zy)Huba   Represents a single Hub (or category) in the PlexServer search.

        Attributes:
            TAG (str): 'Hub'
            context (str): The context of the hub.
            hubKey (str): API URL for these specific hub items.
            hubIdentifier (str): The identifier of the hub.
            items (list): List of items in the hub.
            key (str): API URL for the hub.
            more (bool): True if there are more items to load (call reload() to fetch all items).
            size (int): The number of items in the hub.
            style (str): The style of the hub.
            title (str): The title of the hub.
            type (str): The type of items in the hub.
    c                   || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        | j                  |      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d	      | _        d
| _        y
)r  ri  hubKeyhubIdentifierrA   morer  stylerB   r7   N)r'   r(   r)   ri  r  r  r   rj   rA   r   r   r   r  r   r  r  rB   r7   _sectionr,   s     r/   r0   zHub._loadData  s    
{{y1kkooh/![[___=^^D)
;;??5)JJtT[[__V%<=	JJsDKKOOF$;<	[[__W-
[[__W-
KKOOF+	r1   c                    | j                   S rd  )r  rO   s    r/   __len__zHub.__len__  s    yyr1   c                    | j                   rO| j                  rB| j                  | j                        | _        d| _         t	        | j                        | _        yyy)z0 Reloads the hub to fetch all items in the hub. FN)r  rA   rd   rj   rU   r  rO   s    r/   r   z
Hub.reload  s@    992DJDIDJJDI "9r1   c                    | j                   4| j                  j                  j                  | j                        | _         | j                   S )zS Returns the :class:`~plexapi.library.LibrarySection` this hub belongs to.
        )r  r>   r   r[   r  rO   s    r/   rK   zHub.section  s:     ==  LL00<<T=R=RSDM}}r1   N)	r   r   r   r   rO  r0   r  r   rK   rh   r1   r/   r  r    s"     C(r1   r  c                       e Zd ZdZdZd Zd Zy)r  a   Base class of library media tags.

        Attributes:
            TAG (str): 'Directory'
            count (int): The number of items where this tag is found.
            filter (str): The URL filter for the tag.
            id (int): The id of the tag.
            key (str): API URL (/library/section/<librarySectionID>/all?<filter>).
            librarySectionID (int): The library section ID where the tag is found.
            librarySectionKey (str): API URL for the library section (/library/section/<librarySectionID>)
            librarySectionTitle (str): The library title where the tag is found.
            librarySectionType (int): The library type where the tag is found.
            reason (str): The reason for the search result.
            reasonID (int): The reason ID for the search result.
            reasonTitle (str): The reason title for the search result.
            score (float): The score for the search result.
            type (str): The type of search result (tag).
            tag (str): The title of the tag.
            tagKey (str): The Plex Discover ratingKey (guid) for people.
            tagType (int): The type ID of the tag.
            tagValue (int): The value of the tag.
            thumb (str): The URL for the thumbnail of the tag (if available).
    r9  c                   || _         t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _	        t        j                  t        |j                  j                  d            | _
        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d	      | _        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      | _        y)r  countrV  r)  rA   r  librarySectionKeylibrarySectionTitlelibrarySectionTypereasonreasonIDreasonTitlescorer7   r   tagKeyr   tagValuer   N)r'   r   r   r   r(   r)   r  rV  r)  rA   r  r  r  r  r  r  r  r  r  r7   r   r  r   r  r   r,   s     r/   r0   zLibraryMediaTag._loadData  s   
ZZT[[__W%=>
kkooh/**S$++//$"78;;??5) %

3@R0S T!%1D!E#';;??3H#I "'**S$++//BV2W"Xkkooh/

3
(CD;;??=9ZZt{{w'?@
KKOOF+	;;??5)kkooh/zz#t{{y'AB

3
(CD[[__W-
r1   c                    | j                   st        d| j                         | j                  | j                         S )z+ Return the list of items within this tag. z!Key is not defined for this tag: )rA   r   r   rd   )r-   rt   re   s      r/   rj   zLibraryMediaTag.items  s3    xx@
KLLtxx((r1   Nr   r   r   r   rO  r0   rj   rh   r1   r/   r  r    s    . C.,)r1   r  c                      e Zd ZdZdZy)Aperturezi Represents a single Aperture library media tag.

        Attributes:
            TAGTYPE (int): 202
       Nr   r   r   r   TAGTYPErh   r1   r/   r  r  	      
 Gr1   r  c                      e Zd ZdZdZy)Artzd Represents a single Art library media tag.

        Attributes:
            TAGTYPE (int): 313
    i9  Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Autotagzh Represents a single Autotag library media tag.

        Attributes:
            TAGTYPE (int): 207
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Chapterzf Represents a single Chapter library media tag.

        Attributes:
            TAGTYPE (int): 9
    	   Nr  rh   r1   r/   r  r  #	      
 Gr1   r  c                      e Zd ZdZdZy)
Collectionzi Represents a single Collection library media tag.

        Attributes:
            TAGTYPE (int): 2
       Nr  rh   r1   r/   r  r  -	  r  r1   r  c                      e Zd ZdZdZy)Concertzh Represents a single Concert library media tag.

        Attributes:
            TAGTYPE (int): 306
    i2  Nr  rh   r1   r/   r  r  7	  r  r1   r  c                      e Zd ZdZdZy)Countryzf Represents a single Country library media tag.

        Attributes:
            TAGTYPE (int): 8
       Nr  rh   r1   r/   r  r  A	  r  r1   r  c                      e Zd ZdZdZy)Devicezg Represents a single Device library media tag.

        Attributes:
            TAGTYPE (int): 206
       Nr  rh   r1   r/   r  r  K	  r  r1   r  c                      e Zd ZdZdZy)Directorzg Represents a single Director library media tag.

        Attributes:
            TAGTYPE (int): 4
       Nr  rh   r1   r/   r  r  U	  r  r1   r  c                      e Zd ZdZdZy)Exposurezi Represents a single Exposure library media tag.

        Attributes:
            TAGTYPE (int): 203
       Nr  rh   r1   r/   r  r  _	  r  r1   r  c                      e Zd ZdZdZy)Formatzg Represents a single Format library media tag.

        Attributes:
            TAGTYPE (int): 302
    i.  Nr  rh   r1   r/   r  r  i	  r  r1   r  c                      e Zd ZdZdZy)Genrezd Represents a single Genre library media tag.

        Attributes:
            TAGTYPE (int): 1
    rR   Nr  rh   r1   r/   r  r  s	  r  r1   r  c                      e Zd ZdZdZy)Guidze Represents a single Guid library media tag.

        Attributes:
            TAGTYPE (int): 314
    i:  Nr  rh   r1   r/   r  r  }	  r  r1   r  c                      e Zd ZdZdZy)ISOzd Represents a single ISO library media tag.

        Attributes:
            TAGTYPE (int): 204
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Labelze Represents a single Label library media tag.

        Attributes:
            TAGTYPE (int): 11
       Nr  rh   r1   r/   r  r  	      
 Gr1   r  c                      e Zd ZdZdZy)Lensze Represents a single Lens library media tag.

        Attributes:
            TAGTYPE (int): 205
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Makeze Represents a single Make library media tag.

        Attributes:
            TAGTYPE (int): 200
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Markerzf Represents a single Marker library media tag.

        Attributes:
            TAGTYPE (int): 12
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZdZy)MediaProcessingTargetz Represents a single MediaProcessingTarget library media tag.

        Attributes:
            TAG (str): 'Tag'
            TAGTYPE (int): 42
    Tag*   N)r   r   r   r   rO  r  rh   r1   r/   r  r  	  s     CGr1   r  c                      e Zd ZdZdZy)Modelzf Represents a single Model library media tag.

        Attributes:
            TAGTYPE (int): 201
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Moodze Represents a single Mood library media tag.

        Attributes:
            TAGTYPE (int): 300
    i,  Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Networkzh Represents a single Network library media tag.

        Attributes:
            TAGTYPE (int): 319
    i?  Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Placezf Represents a single Place library media tag.

        Attributes:
            TAGTYPE (int): 400
    i  Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Posterzg Represents a single Poster library media tag.

        Attributes:
            TAGTYPE (int): 312
    i8  Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)Producerzg Represents a single Producer library media tag.

        Attributes:
            TAGTYPE (int): 7
       Nr  rh   r1   r/   r  r  	  r  r1   r  c                      e Zd ZdZdZy)RatingImagezl Represents a single RatingImage library media tag.

        Attributes:
            TAGTYPE (int): 316
    i<  Nr  rh   r1   r/   r  r  
  r  r1   r  c                      e Zd ZdZdZy)Reviewzf Represents a single Review library media tag.

        Attributes:
            TAGTYPE (int): 10
    
   Nr  rh   r1   r/   r  r  
  r  r1   r  c                      e Zd ZdZdZy)Rolezc Represents a single Role library media tag.

        Attributes:
            TAGTYPE (int): 6
       Nr  rh   r1   r/   r  r  
  r  r1   r  c                      e Zd ZdZdZy)Similarzh Represents a single Similar library media tag.

        Attributes:
            TAGTYPE (int): 305
    i1  Nr  rh   r1   r/   r  r  
  r  r1   r  c                      e Zd ZdZdZy)Studiozg Represents a single Studio library media tag.

        Attributes:
            TAGTYPE (int): 318
    i>  Nr  rh   r1   r/   r	  r	  )
  r  r1   r	  c                      e Zd ZdZdZy)Stylezf Represents a single Style library media tag.

        Attributes:
            TAGTYPE (int): 301
    i-  Nr  rh   r1   r/   r  r  3
  r  r1   r  c                      e Zd ZdZdZy)r  zb Represents a single Tag library media tag.

        Attributes:
            TAGTYPE (int): 0
    r   Nr  rh   r1   r/   r  r  =
  r  r1   r  c                      e Zd ZdZdZy)Themezf Represents a single Theme library media tag.

        Attributes:
            TAGTYPE (int): 317
    i=  Nr  rh   r1   r/   r  r  G
  r  r1   r  c                      e Zd ZdZdZy)Writerze Represents a single Writer library media tag.

        Attributes:
            TAGTYPE (int): 5
       Nr  rh   r1   r/   r  r  Q
  r  r1   r  c                  2    e Zd ZdZdZd Zd Zd Zd Zd Z	y)	rZ  a}   Represents a single filtering Type object for a library.

        Attributes:
            TAG (str): 'Type'
            active (bool): True if this filter type is currently active.
            fields (List<:class:`~plexapi.library.FilteringField`>): List of field objects.
            filters (List<:class:`~plexapi.library.FilteringFilter`>): List of filter objects.
            key (str): The API URL path for the libtype filter.
            sorts (List<:class:`~plexapi.library.FilteringSort`>): List of sort objects.
            title (str): The title for the libtype filter.
            type (str): The libtype for the filter.
    Typec                    | j                  | j                  d            }ddj                  | j                  j                  |fD cg c]  }|s|	 c}       dS c c}w Nr7   <r  >_clean	firstAttrr`   r   r   r-   _typeps      r/   __repr__zFilteringType.__repr__j
  R    DNN623388)@)@%(HN1AQNOPPQRRN   A
A
c                   || _         t        j                  t        |j                  j                  dd            | _        | j                  |t              | _	        | j                  |t              | _        |j                  j                  d      | _        | j                  |t              | _        |j                  j                  d      | _        |j                  j                  d      | _        | j#                         j                  | _        | xj                  | j'                         z  c_        | xj                  | j)                         z  c_        | xj                  | j+                         z  c_	        y )Nactive0rA   rB   r7   )r'   r   r   r   r(   r)   r"  r   FilteringFieldr{  FilteringFilterr   rA   r  rx  rB   r7   _parent_librarySectionID_manualFilters_manualSorts_manualFieldsr,   s     r/   r0   zFilteringType._loadDatan
  s    
jjt{{x'EFnnT>:~~dO<;;??5)^^D-8
[[__W-
KKOOF+	!%!3!3 	++--

d''))
t))++r1   c           
     B   g }| j                   dk(  r|j                  dg       n| j                   dk(  r|j                  dg       ne| j                   dk(  r|j                  dg       nC| j                   dk(  r|j                  dg       n!| j                   dk(  r|j                  dg       g }|D ]l  \  }}}d| j                   d| d	t        j                  | j                          }d
| d| d| d| d	}|j                  | j                  |t                     n |S )zm Manually add additional filters which are available
            but not exposed on the Plex server.
        rU  )labelr  LabelsrQ  r5   rc  r  r   /z?type=z<Filter filter="z" filterType="z" key="	" title="z" type="filter" />)r7   r   r'  r   rr   rE   r\  r%  )r-   additionalFiltersmanualFilters	filterTagr  filterTitle	filterKey	filterXMLs           r/   r(  zFilteringType._manualFilters
  sj   

 99 $$-&  YY)#$$-&  YY("$$-&  YY'!$$-&  YY,&$$-&  2C 		T.Iz;,T-C-C,DAi[PVW\WgWghlhqhqWrVstI"9+ .)l +!{ #% '#$    !6!6y/!RS		T r1   c           
        dddd| j                   j                          dfdddg}| j                   d	k(  r|j                  d
g       ne| j                   dk(  r|j                  dg       nC| j                   dk(  r|j                  dg       n!| j                   dk(  r|j                  dg       g }|D ]:  \  }}}d| d| d| d| d	}|j                  | j	                  |t
                     < |S )zk Manually add additional sorts which are available
            but not exposed on the Plex server.
        )r  r  r  )r)  r  
Rating Keyindexr   Number)summaryr  Summary)tagliner  Tagline)r   r  Date UpdatedrU  )	titleSortr  Titlerc  )absoluteIndexr  zAbsolute Indexr6   )viewUpdatedAtr  zView Updated Atr  )addedAtr  
Date Addedz<Sort defaultDirection="z" descKey="z:desc" key="r/  z" />)r7   
capitalizer   rE   r\  r  )r-   additionalSortsmanualSortsr  r  	sortTitlesortXMLs          r/   r)  zFilteringType._manualSorts
  s>    $'e		 4 4 67w?@))0
 99 ""-$  YY'!"":$  YY'!""<$  YY,&""0$  -< 	N)Iw	*7) 4%; '!{ ##D*  t44WmLM	N r1   c                F   dddd| j                   j                          dfdd| j                   j                          dfd	d
dg}| j                   dk(  r|j                  g d       n| j                   dk(  r|j                  g d       n| j                   dk(  r|j                  g d       n| j                   dk(  r|j                  g d       ng| j                   dk(  r|j                  dg       nE| j                   dk(  r|j                  g d       n"| j                   dk(  r|j                  ddg       | j                   dk(  rdn| j                   dz   }g }|D ]A  \  }}}|dvr| | }d| d| d| d }|j                  | j	                  |t
                     C |S )!zl Manually add additional fields which are available
            but not exposed on the Plex server.
        )r  r  r  )r)  r  r7  r8  r  r9  lastRatedAtr  z Last Rated)r   r  r>  )groupr  zSQL Group By Statement)havingr  zSQL Having Clauser3   )audienceRatingr  zAudience Ratingratingr  zCritic Rating
viewOffsetr  zView Offsetr4   )rN  )originallyAvailableAtr  zShow Release DaterP  unviewedLeafCountr  zEpisode Unplayed CountrU  ))rC  r  zDate Season AddedrU  )yearr  zSeason Yearr,  r   r  rQ  )rN  durationr  DurationrP  rR  rX  r5   rX  rc  )rY  rR  rX  )ratingCountr  zRating Countr  )rC  r  rD  r   r  >   rL  rM  z<Field key="r/  z" type="z"/>)r7   rE  r   rE   r\  r$  )r-   additionalFieldsprefixmanualFieldsr5  rq  
fieldTitlefieldXMLs           r/   r*  zFilteringType._manualFields
  s    %+iDII$8$8$:#;7!CDFtyy';';'=&>k$JK195
 99## % 
 YY& ## %  YY("## %  YY)### %  YY("##)%  YY'!## %  YY,&##1)% 
 yyG+S,< 		Q(E9j//!(5'*ug &$ &"3(   5 5h OP		Q r1   N)
r   r   r   r   rO  r  r0   r(  r)  r*  rh   r1   r/   rZ  rZ  [
  s+     CS,$)V*XJr1   rZ  c                      e Zd ZdZdZd Zy)r%  a   Represents a single Filter object for a :class:`~plexapi.library.FilteringType`.

        Attributes:
            TAG (str): 'Filter'
            filter (str): The key for the filter.
            filterType (str): The :class:`~plexapi.library.FilteringFieldType` type (string, boolean, integer, date, etc).
            key (str): The API URL path for the filter.
            title (str): The title of the filter.
            type (str): 'filter'
    Filterc                R   || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        y )NrV  r  rA   rB   r7   )r'   r(   r)   rV  r  rA   rB   r7   r,   s     r/   r0   zFilteringFilter._loadData1  sm    
kkooh/++//,7;;??5)[[__W-
KKOOF+	r1   Nr  rh   r1   r/   r%  r%  $  s    	 C,r1   r%  c                      e Zd ZdZdZd Zy)r  a   Represents a single Sort object for a :class:`~plexapi.library.FilteringType`.

        Attributes:
            TAG (str): 'Sort'
            active (bool): True if the sort is currently active.
            activeDirection (str): The currently active sorting direction.
            default (str): The currently active default sorting direction.
            defaultDirection (str): The default sorting direction.
            descKey (str): The URL key for sorting with desc.
            firstCharacterKey (str): API URL path for first character endpoint.
            key (str): The URL key for the sorting.
            title (str): The title of the sorting.
    Sortc                D   || _         t        j                  t        |j                  j                  dd            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _	        |j                  j                  d      | _
        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d	      | _        y
)r  r"  r#  activeDirectionr2  r  descKeyfirstCharacterKeyrA   rB   N)r'   r   r   r   r(   r)   r"  rh  r2  r  ri  rj  rA   rB   r,   s     r/   r0   zFilteringSort._loadDataJ  s    
jjt{{x'EF#{{/@A{{y1 $0B C{{y1!%1D!E;;??5)[[__W-
r1   Nr  rh   r1   r/   r  r  :  s     C
.r1   r  c                      e Zd ZdZdZd Zy)r$  a   Represents a single Field object for a :class:`~plexapi.library.FilteringType`.

        Attributes:
            TAG (str): 'Field'
            key (str): The URL key for the filter field.
            title (str): The title of the filter field.
            type (str): The :class:`~plexapi.library.FilteringFieldType` type (string, boolean, integer, date, etc).
            subType (str): The subtype of the filter (decade, rating, etc).
    Fieldc                   || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        y)r  rA   rB   r7   subTypeN)r'   r(   r)   rA   rB   r7   rn  r,   s     r/   r0   zFilteringField._loadDatac  sY    
;;??5)[[__W-
KKOOF+	{{y1r1   Nr  rh   r1   r/   r$  r$  W  s     C2r1   r$  c                       e Zd ZdZdZd Zd Zy)r[  a.   Represents a single FieldType for library filtering.

        Attributes:
            TAG (str): 'FieldType'
            type (str): The filtering data type (string, boolean, integer, date, etc).
            operators (List<:class:`~plexapi.library.FilteringOperator`>): List of operator objects.
    	FieldTypec                    | j                  | j                  d            }ddj                  | j                  j                  |fD cg c]  }|s|	 c}       dS c c}w r  r  r  s      r/   r  zFilteringFieldType.__repr__v  r  r   c                    || _         |j                  j                  d      | _        | j	                  |t
              | _        y)r  r7   N)r'   r(   r)   r7   r   FilteringOperatorr~  r,   s     r/   r0   zFilteringFieldType._loadDataz  s0    
KKOOF+	.?@r1   N)r   r   r   r   rO  r  r0   rh   r1   r/   r[  r[  l  s     CSAr1   r[  c                      e Zd ZdZdZd Zy)rs  z Represents an single Operator for a :class:`~plexapi.library.FilteringFieldType`.

        Attributes:
            TAG (str): 'Operator'
            key (str): The URL key for the operator.
            title (str): The title of the operator.
    Operatorc                    |j                   j                  d      | _        |j                   j                  d      | _        yr  rA   rB   Nr(   r)   rA   rB   r,   s     r/   r0   zFilteringOperator._loadData  *    ;;??5)[[__W-
r1   Nr  rh   r1   r/   rs  rs    s     C.r1   rs  c                       e Zd ZdZdZd Zd Zy)r  a   Represents a single FilterChoice object.
        These objects are gathered when using filters while searching for library items and is the
        object returned in the result set of :func:`~plexapi.library.LibrarySection.listFilterChoices`.

        Attributes:
            TAG (str): 'Directory'
            fastKey (str): API URL path to quickly list all items with this filter choice.
                (/library/sections/<section>/all?genre=<key>)
            key (str): The id value of this filter choice.
            thumb (str): Thumbnail URL for the filter choice.
            title (str): The title of the filter choice.
            type (str): The filter type (genre, contentRating, etc).
    r9  c                R   || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        y)r  fastKeyrA   r   rB   r7   N)r'   r(   r)   r|  rA   r   rB   r7   r,   s     r/   r0   zFilterChoice._loadData  sm    
{{y1;;??5)[[__W-
[[__W-
KKOOF+	r1   c                8    | j                  | j                        S )z1 Returns a list of items for this filter choice. )rd   r|  rO   s    r/   rj   zFilterChoice.items  s    t||,,r1   Nr  rh   r1   r/   r  r    s     C,-r1   r  c                  Z    e Zd ZdZdZd Zd ZddZd ZddZ	d	 Z
d
 Zd Zd Zd Zd Zy)r  a   Represents a Managed Hub (recommendation) inside a library.

        Attributes:
            TAG (str): 'Hub'
            deletable (bool): True if the Hub can be deleted (promoted collection).
            homeVisibility (str): Promoted home visibility (none, all, admin, or shared).
            identifier (str): Hub identifier for the managed hub.
            promotedToOwnHome (bool): Promoted to own home.
            promotedToRecommended (bool): Promoted to recommended.
            promotedToSharedHome (bool): Promoted to shared home.
            recommendationsVisibility (str): Promoted recommendation visibility (none or all).
            title (str): Title of managed hub.
    r  c                r   || _         t        j                  t        |j                  j                  dd            | _        |j                  j                  d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
d      | _        |j                  j                  d      | _        d| _        | j                         }t!        |t"              r|j$                  | _        y|j&                  | _        y)r  	deletableThomeVisibilitynoner#   promotedToOwnHomeFpromotedToRecommendedpromotedToSharedHomerecommendationsVisibilityrB   N)r'   r   r   r   r(   r)   r  r  r#   r  r  r  r  rB   	_promotedr&  r_   r@   rA   r  )r-   r.   parents      r/   r0   zManagedHub._loadData  s$   
D$++//+t*LM"kkoo.>G++//,7!&D$++//BUW\2]!^%*ZZdkkooF]_d6e%f"$)JJtT[[__E[]b5c$d!)-9TV\)]&[[__W-
.8.P

V\VmVmr1   c                    d| j                    d}| j                  || j                  | j                        }| j                  j                  |j                         | S )z' Reload the data for this managed hub. r  r  )r#   )r  r&  r   r#   r   r   )r-   rA   rj  s      r/   r   zManagedHub.reload  sN     5 56g>nnS$..T__nMS\\*r1   Nc                   | j                   st        d      d| j                   d| j                   d}|r| d|j                   }| j                  j                  || j                  j                  j                         y)aq   Move a managed hub to a new position in the library's Managed Recommendations.

            Parameters:
                after (obj): :class:`~plexapi.library.ManagedHub` object to move the item after in the collection.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying to move a Hub that is not a Managed Recommendation.
        z7Collection must be a Managed Recommendation to be movedr  /manage/z/movez?after=ry   N)r  r   r  r#   r>   r?   r|   r}   )r-   afterrA   s      r/   movezManagedHub.move  sx     ~~VWW 5 56ht>OuUE!1!1 23C3t||'<'<'@'@Ar1   c                B   | j                   st        d      | j                  s%t        | j                   d| j                  z        d| j                   d| j
                   }| j                  j                  || j                  j                  j                         y)a   Removes a managed hub from the library's Managed Recommendations.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying to remove a Hub that is not a Managed Recommendation
                    or when the Hub cannot be removed.
        z9Collection must be a Managed Recommendation to be removedz managed hub cannot be removedr  r  ry   N)
r  r   r  rB   r  r#   r>   r?   r|   r   r   s     r/   r   zManagedHub.remove  s     ~~XYY~~

|+IJTZZWXX 5 56ht>OP3t||'<'<'C'CDr1   c                   t        | j                        t        | j                        t        | j                        d}|t        |      |d<   |t        |      |d<   |t        |      |d<   | j                  s}| j
                  j                  d      d   |d<   d| j                   d	}| j                  j                  || j                  j                  j                  |
       | j                         S d| j                   d| j
                   }| j                  j                  || j                  j                  j                  |
       | j                         S )a   Update the managed hub's visibility settings.

            Parameters:
                recommended (bool): True to make visible on your Library Recommended page. False to hide. Default None.
                home (bool): True to make visible on your Home page. False to hide. Default None.
                shared (bool): True to make visible on your Friends' Home page. False to hide. Default None.

            Example:

                .. code-block:: python

                    managedHub.updateVisibility(recommended=True, home=True, shared=False).reload()
                    # or using chained methods
                    managedHub.promoteRecommended().promoteHome().demoteShared().reload()

        )r  r  r  r  r  r  r  rS   metadataItemIdr  r  )rz   r   r  )r   r  r  r  r  r#   rsplitr  r>   r?   r|   r   r}   r   )r-   recommendedhomesharedr   rA   s         r/   updateVisibilityzManagedHub.updateVisibility  s>   $ &))C)C%D!$T%;%;!<$'(A(A$B

 ".1+.>F*+*-d)F&'-0[F)*~~'+'='=c'B2'FF#$#D$9$9#:'BCLLs4<<+@+@+E+EfU {{} $D$9$9#:(4??BSTCLLs4<<+@+@+D+DVT{{}r1   c                &    | j                  d      S )z8 Show the managed hub on your Library Recommended Page. Tr  r  rO   s    r/   promoteRecommendedzManagedHub.promoteRecommended  s    $$$66r1   c                &    | j                  d      S )z8 Hide the managed hub on your Library Recommended Page. Fr  r  rO   s    r/   demoteRecommendedzManagedHub.demoteRecommended  s    $$$77r1   c                &    | j                  d      S )z) Show the managed hub on your Home Page. Tr  r  rO   s    r/   promoteHomezManagedHub.promoteHome"  s    $$$$//r1   c                &    | j                  d      S )z( Hide the manged hub on your Home Page. Fr  r  rO   s    r/   
demoteHomezManagedHub.demoteHome&  s    $$%$00r1   c                &    | j                  d      S )z2 Show the managed hub on your Friends' Home Page. Tr  r  rO   s    r/   promoteSharedzManagedHub.promoteShared*  s    $$D$11r1   c                &    | j                  d      S )z2 Hide the managed hub on your Friends' Home Page. Fr  r  rO   s    r/   demoteSharedzManagedHub.demoteShared.  s    $$E$22r1   rd  r4  )r   r   r   r   rO  r0   r   r  r   r  r  r  r  r  r  r  rh   r1   r/   r  r    sI     Cn B E$L780123r1   r  c                  "    e Zd ZdZd Zd Zd Zy)r  z Represents a Folder inside a library.

        Attributes:
            key (str): Url key for folder.
            title (str): Title of folder.
    c                    |j                   j                  d      | _        |j                   j                  d      | _        yrw  rx  r,   s     r/   r0   zFolder._loadData;  ry  r1   c                    | j                   j                  d      r| j                  | j                         S | j                  | j                   t              S )z Returns a list of available :class:`~plexapi.library.Folder` for this folder.
            Continue down subfolders until a mediaType is found.
        /library/metadata)rA   r   rd   r  rO   s    r/   
subfolderszFolder.subfolders@  s?     8823??488,,??488V44r1   c                   g }| j                         D ]r  }|j                  j                  d      r|j                  |       	 |j                         D ]/  }|j                  j                  d      r|j                  |       1 t |S )z Returns a list of all available :class:`~plexapi.library.Folder` for this folder.
            Only returns :class:`~plexapi.library.Folder`.
        r  )r  rA   r   rE   )r-   r  folder	subfolders       r/   allSubfolderszFolder.allSubfoldersI  s     oo' 	F::(()<=v&%+%6%6%8 %	(}}778KL#NN95$% 	 r1   N)r   r   r   r   r0   r  r  rh   r1   r/   r  r  3  s    .
5r1   r  c                      e Zd ZdZd Zy)rJ  a
   Represents a First Character element from a library.

        Attributes:
            key (str): Url key for character.
            size (str): Total amount of library items starting with this character.
            title (str): Character (#, !, A, B, C, ...).
    c                    || _         |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        y)r  rA   r  rB   N)r'   r(   r)   rA   r  rB   r,   s     r/   r0   zFirstCharacter._loadDatac  sE    
;;??5)KKOOF+	[[__W-
r1   N)r   r   r   r   r0   rh   r1   r/   rJ  rJ  Z  s    .r1   rJ  c                  (    e Zd ZdZd Zd ZddZd Zy)Pathak   Represents a single directory Path.

        Attributes:
            TAG (str): 'Path'
            home (bool): True if the path is the home directory
            key (str): API URL (/services/browse/<base64path>)
            network (bool): True if path is a network location
            path (str): Full path to folder
            title (str): Folder name
    c                   t        j                  t        |j                  j	                  d            | _        |j                  j	                  d      | _        t        j                  t        |j                  j	                  d            | _        |j                  j	                  d      | _        |j                  j	                  d      | _	        y )Nr  rA   networkr   rB   )
r   r   r   r(   r)   r  rA   r  r   rB   r,   s     r/   r0   zPath._loadDatay  s|    JJtT[[__V%<=	;;??5)zz$	(BCKKOOF+	[[__W-
r1   c                :    | j                   j                  | |      S )z6 Alias for :func:`~plexapi.server.PlexServer.browse`. )r>   browse)r-   includeFiless     r/   r  zPath.browse  s    ||""466r1   c              #  b   K   | j                   j                  |       D ]  \  }}}|||f  yw)z4 Alias for :func:`~plexapi.server.PlexServer.walk`. N)r>   walk)r-   r   pathsfiless       r/   r  z	Path.walk  s8     "&,,"3"3D"9 	%D%u$$	%s   -/N)T)r   r   r   r   rO  r0   r  r  rh   r1   r/   r  r  k  s    	 C.7%r1   r  c                      e Zd ZdZd Zd Zy)Filez Represents a single File.

        Attributes:
            TAG (str): 'File'
            key (str): API URL (/services/browse/<base64path>)
            path (str): Full path to file
            title (str): File name
    c                    |j                   j                  d      | _        |j                   j                  d      | _        |j                   j                  d      | _        y )NrA   r   rB   )r(   r)   rA   r   rB   r,   s     r/   r0   zFile._loadData  s>    ;;??5)KKOOF+	[[__W-
r1   Nr  rh   r1   r/   r  r    s     C.r1   r  c                  F    e Zd ZdZd Zd Zd Zed        Zed        Z	d Z
y)r'  a	   Represents a Common element from a library. This object lists common fields between multiple objects.

        Attributes:
            TAG (str): 'Common'
            collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
            contentRating (str): Content rating of the items.
            countries (List<:class:`~plexapi.media.Country`>): List of countries objects.
            directors (List<:class:`~plexapi.media.Director`>): List of director objects.
            editionTitle (str): Edition title of the items.
            fields (List<:class:`~plexapi.media.Field`>): List of field objects.
            genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
            grandparentRatingKey (int): Grandparent rating key of the items.
            grandparentTitle (str): Grandparent title of the items.
            guid (str): Plex GUID of the items.
            guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
            index (int): Index of the items.
            key (str): API URL (/library/metadata/<ratingkey>).
            labels (List<:class:`~plexapi.media.Label`>): List of label objects.
            mixedFields (List<str>): List of mixed fields.
            moods (List<:class:`~plexapi.media.Mood`>): List of mood objects.
            originallyAvailableAt (datetime): Datetime of the release date of the items.
            parentRatingKey (int): Parent rating key of the items.
            parentTitle (str): Parent title of the items.
            producers (List<:class:`~plexapi.media.Producer`>): List of producer objects.
            ratingKey (int): Rating key of the items.
            ratings (List<:class:`~plexapi.media.Rating`>): List of rating objects.
            roles (List<:class:`~plexapi.media.Role`>): List of role objects.
            studio (str): Studio name of the items.
            styles (List<:class:`~plexapi.media.Style`>): List of style objects.
            summary (str): Summary of the items.
            tagline (str): Tagline of the items.
            tags (List<:class:`~plexapi.media.Tag`>): List of tag objects.
            title (str): Title of the items.
            titleSort (str): Title to use when sorting of the items.
            type (str): Type of the media (common).
            writers (List<:class:`~plexapi.media.Writer`>): List of writer objects.
            year (int): Year of the items.
    c                
   || _         | j                  |t        j                        | _        |j
                  j                  d      | _        | j                  |t        j                        | _	        | j                  |t        j                        | _        |j
                  j                  d      | _        | j                  |t        j                        | _        | j                  |t        j                        | _        t#        j$                  t&        |j
                  j                  d            | _        |j
                  j                  d      | _        |j
                  j                  d      | _        | j                  |t        j.                        | _        t#        j$                  t&        |j
                  j                  d            | _        |j
                  j                  d      | _        | j                  |t        j6                        | _        |j
                  j                  d      j;                  d	      | _        | j                  |t        j>                        | _         t#        jB                  |j
                  j                  d
            | _"        t#        j$                  t&        |j
                  j                  d            | _#        |j
                  j                  d      | _$        | j                  |t        jJ                        | _&        t#        j$                  t&        |j
                  j                  d            | _'        | j                  |t        jP                        | _)        | j                  |t        jT                        | _+        |j
                  j                  d      | _,        | j                  |t        jZ                        | _.        |j
                  j                  d      | _/        |j
                  j                  d      | _0        | j                  |t        jb                        | _2        |j
                  j                  d      | _3        |j
                  j                  d      | _4        |j
                  j                  d      | _5        | j                  |t        jl                        | _7        t#        j$                  t&        |j
                  j                  d            | _8        y )NcontentRatingeditionTitlegrandparentRatingKeygrandparentTitler  r8  rA   mixedFieldsr]   rT  parentRatingKeyparentTitler#  studior:  r<  rB   r?  r7   rW  )9r'   r   r   r  rY  r(   r)   r  r  	countriesr  	directorsr  rl  r{  r  genresr   r   r   r  r  r  r  guidsr8  rA   r  labelsr  r  r  moodsr   rT  r  r  r  	producersr#  Ratingratingsr  rolesr  r  stylesr:  r<  r  r   rB   r?  r7   r  writersrW  r,   s     r/   r0   zCommon._loadData  s   
>>$0@0@A![[___=emm<enn= KKOON;nnT5;;7nnT5;;7$)JJsDKKOODZ4[$\! $0B CKKOOF+	^^D%**5
ZZT[[__W%=>
;;??5)nnT5;;7;;??=9??D^^D%**5
%*%5%5dkkooF]6^%_"$zz#t{{?P/QR;;??=9enn=C)EF~~dELL9^^D%**5
kkooh/nnT5;;7{{y1{{y1NN43	[[__W-
5KKOOF+	~~dELL9JJsDKKOOF$;<	r1   c           	         d| j                   j                  d| j                  ddj                  d | j                  D              dS )Nr  r  r]   c              3  2   K   | ]  }t        |        y wrd  )rb   )rf  rA   s     r/   rh  z"Common.__repr__.<locals>.<genexpr>  s     9#SX9s   r  )r   r   
commonTyper`   
ratingKeysrO   s    r/   r  zCommon.__repr__  s6    NN##OOHH999
 	
r1   c                    t        t        | j                        j                        }t	        j
                  |d   d         S )z- Returns the media type of the common items. r7   r   )r	   r   	_initpathr?   r   reverseSearchType)r-   parsed_querys     r/   r  zCommon.commonType  s8       8 > >?&&|F';A'>??r1   c                    t        t        | j                        j                        }|d   d   j	                  d      D cg c]  }t        |j                                c}S c c}w )z5 Returns a list of rating keys for the common items. r)  r   r]   )r	   r   r  r?   r  r   rD   )r-   r  rv   s      r/   r  zCommon.ratingKeys  sQ       8 > >?0<T0B10E0K0KC0PQuEKKM"QQQs    A%c                L    | j                   j                  | j                        S )z% Returns a list of the common items. )r>   rd   r  rO   s    r/   rj   zCommon.items  s    ||&&t77r1   N)r   r   r   r   rO  r0   r  r5  r  r  rj   rh   r1   r/   r'  r'    sK    %L C"=H
 @ @
 R R
8r1   r'  )e
__future__r   r  typingr   r   rV   rY  r   r   	functoolsr   urllib.parser	   r
   r   r   plexapir   r   r   plexapi.baser   r   plexapi.exceptionsr   r   plexapi.mixinsr   r   r   r   r   r   r   r   r   plexapi.settingsr   plexapi.utilsr   plexapi.audior   r!   r@   r:   r;   r<   r=   registerPlexObjectr@  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  r  r  r	  r  r  r  r  rZ  r%  r  r$  r[  rs  r  r  r  rJ  r  r  r'  rh   r1   r/   <module>r     sw   " 	 %  #  % B B % % . 3   % $ #~$j ~$BrZ rj+98>? 98xQ7..2BDU Q7hr.>#3_o r.jG8>#7 G8T $Ej $E $EN ,z , ," 0* 0 0f4)j 4)n    /   o   o      o   o   _         _   O   ?   /   O   ?   ?   _   O   O   ?   o   O   _      /   _   ?   o   _   O   /   O   _  FJ FR,j ,,.J .:2Z 2*A A*.
 . -: -<A3 A3H$Z $N.Z ." %: % %< .: . ." b8Z b8 b8r1   