
    g                        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	 d dl
mZmZmZmZ d dlmZ d dlmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$  G d	 d
ee      Z%e	jL                   G d de%eeeeeeeeeeee e$             Z'e	jL                   G d de%eeeeeeeeeee!e$             Z(e	jL                   G d de%eeeeeeee"             Z)e	jL                   G d de%eeeeeeee#             Z*e	jL                   G d de%eee             Z+ G d de+      Z,e	jL                   G d dee'             Z-e	jL                   G d dee*             Z.e	jL                   G d dee+             Z/e	jL                   G d dee'             Z0e	jL                   G d d ee*             Z1e	jL                   G d! d"ee+             Z2y)#    N)cached_property)Path)
quote_plus)mediautils)PlayablePlexPartialObjectPlexHistoryPlexSession)
BadRequest)AdvancedSettingsMixinSplitMergeMixinUnmatchMatchMixinExtrasMixin	HubsMixinPlayedUnplayedMixinRatingMixinArtUrlMixinArtMixin	LogoMixinPosterUrlMixinPosterMixinThemeUrlMixin
ThemeMixinMovieEditMixinsShowEditMixinsSeasonEditMixinsEpisodeEditMixinsWatchlistMixinc                   X    e Zd ZdZd Zd Zd Zd Zd ZddZ	d Z
dd
Z	 	 ddZddZy	)Videoa   Base class for all video objects including :class:`~plexapi.video.Movie`,
        :class:`~plexapi.video.Show`, :class:`~plexapi.video.Season`,
        :class:`~plexapi.video.Episode`, and :class:`~plexapi.video.Clip`.

        Attributes:
            addedAt (datetime): Datetime the item was added to the library.
            art (str): URL to artwork image (/library/metadata/<ratingKey>/art/<artid>).
            artBlurHash (str): BlurHash string for artwork image.
            fields (List<:class:`~plexapi.media.Field`>): List of field objects.
            guid (str): Plex GUID for the movie, show, season, episode, or clip (plex://movie/5d776b59ad5437001f79c6f8).
            images (List<:class:`~plexapi.media.Image`>): List of image objects.
            key (str): API URL (/library/metadata/<ratingkey>).
            lastRatedAt (datetime): Datetime the item was last rated.
            lastViewedAt (datetime): Datetime the item was last played.
            librarySectionID (int): :class:`~plexapi.library.LibrarySection` ID.
            librarySectionKey (str): :class:`~plexapi.library.LibrarySection` key.
            librarySectionTitle (str): :class:`~plexapi.library.LibrarySection` title.
            listType (str): Hardcoded as 'video' (useful for search filters).
            ratingKey (int): Unique key identifying the item.
            summary (str): Summary of the movie, show, season, episode, or clip.
            thumb (str): URL to thumbnail image (/library/metadata/<ratingKey>/thumb/<thumbid>).
            thumbBlurHash (str): BlurHash string for thumbnail image.
            title (str): Name of the movie, show, season, episode, or clip.
            titleSort (str): Title to use when sorting (defaults to title).
            type (str): 'movie', 'show', 'season', 'episode', or 'clip'.
            updatedAt (datetime): Datetime the item was updated.
            userRating (float): Rating of the item (0.0 - 10.0) equaling (0 stars - 5 stars).
            viewCount (int): Count of times the item was played.
    c                 &   || _         t        j                  |j                  j	                  d            | _        |j                  j	                  d      | _        |j                  j	                  d      | _        | j                  |t        j                        | _        |j                  j	                  d      | _        | j                  |t        j                        | _        |j                  j	                  dd      | _        t        j                  |j                  j	                  d            | _        t        j                  |j                  j	                  d            | _        t        j$                  t&        |j                  j	                  d	            | _        |j                  j	                  d
      | _        |j                  j	                  d      | _        d| _        t        j$                  t&        |j                  j	                  d            | _        |j                  j	                  d      | _        |j                  j	                  d      | _        |j                  j	                  d      | _        |j                  j	                  d      | _        |j                  j	                  d| j8                        | _        |j                  j	                  d      | _        t        j                  |j                  j	                  d            | _        t        j$                  t@        |j                  j	                  d            | _!        t        j$                  t&        |j                  j	                  dd            | _"        y)/ Load attribute values from Plex XML response. addedAtartartBlurHashguidkey lastRatedAtlastViewedAtlibrarySectionIDlibrarySectionKeylibrarySectionTitlevideo	ratingKeysummarythumbthumbBlurHashtitle	titleSorttype	updatedAt
userRating	viewCountr   N)#_datar   
toDatetimeattribgetr$   r%   r&   	findItemsr   Fieldfieldsr'   Imageimagesr(   r*   r+   castintr,   r-   r.   listTyper0   r1   r2   r3   r4   r5   r6   r7   floatr8   r9   selfdatas     "/opt/Tautulli/lib/plexapi/video.py	_loadDatazVideo._loadData1   s8   
''	(BC;;??5);;??=9nnT5;;7KKOOF+	nnT5;;7;;??5"- ++DKKOOM,JK!,,T[[__^-LM %

3@R0S T!%1D!E#';;??3H#I C)EF{{y1[[__W-
![[___=[[__W-
djjAKKOOF+	))$++//+*FG**UDKKOOL,IJCa)HI    c                 D    |r| j                   j                  |d      S dS )zR Returns the full url for something. Typically used for getting a specific image. T)includeTokenN)_serverurlrH   parts     rJ   rP   z	Video.urlL   s#    <@t||48JdJrL   c                 ^   | j                   j                         }t        d |j                         D        d      }|j                  dk7  s|dk(  rt        d      | j                   j                  | j                  dz         }|j                  j                  d      }| j                  |      S )a   Returns a list of :class:`~plexapi.library.Hub` objects.
            Augmentation returns hub items relating to online media sources
            such as Tidal Music "Track from {item}" or "Soundtrack of {item}".
            Plex Pass and linked Tidal account are required.
        c              3   R   K   | ]  }|j                   d k(  r|j                   ! yw)ztv.plex.provider.musicN)r(   value).0services     rJ   	<genexpr>z%Video.augmentation.<locals>.<genexpr>X   s(      <w;;":: ]] <s   %'NActiveopt_outz+Requires Plex Pass and Tidal Music enabled.z?asyncAugmentMetadata=1augmentationKey)rO   myPlexAccountnextonlineMediaSourcessubscriptionStatusr   queryr(   r<   r=   
fetchItems)rH   accounttidalOptOutrI   r[   s        rJ   augmentationzVideo.augmentationP   s     ,,,,.<'*D*D*F <

 %%1[I5MJKK||!!$((-F"FG++//*;<//rL   c                     | j                   S )0 Returns str, default title for a new syncItem. r4   rH   s    rJ   _defaultSyncTitlezVideo._defaultSyncTitleb       zzrL   c                 ~   | j                    d}t        j                  j                  |      }t        j                  j	                  |      d   dd }||d}ddi}t        |d      5 }| j                  j                  || j                  j                  j                  |||       ddd       | S # 1 sw Y   | S xY w)	z Upload a subtitle file for the video.

            Parameters:
                filepath (str): Path to subtitle file.
        
/subtitles   N)r4   formatAcceptztext/plain, */*rb)rI   paramsheaders)
r(   ospathbasenamesplitextopenrO   r`   _sessionpost)rH   filepathrP   filename	subFormatrq   rr   subfiles           rJ   uploadSubtitleszVideo.uploadSubtitlesf   s     
*%77##H-GG$$X.q1!"5	
 ./(D! 	nWLLsDLL$9$9$>$>WU[elm	n	ns   )?B22B<c                 x    |||d}| j                    dt        j                  |       }| j                  |      S )a   Search for on-demand subtitles for the video.
            See https://support.plex.tv/articles/subtitle-search/.

            Parameters:
                language (str, optional): Language code (ISO 639-1) of the subtitles to search for.
                    Default 'en'.
                hearingImpaired (int, optional): Search option for SDH subtitles.
                    Default 0.
                    (0 = Prefer non-SDH subtitles, 1 = Prefer SDH subtitles,
                    2 = Only show SDH subtitles, 3 = Only show non-SDH subtitles)
                forced (int, optional): Search option for forced subtitles.
                    Default 0.
                    (0 = Prefer non-forced subtitles, 1 = Prefer forced subtitles,
                    2 = Only show forced subtitles, 3 = Only show non-forced subtitles)

            Returns:
                List<:class:`~plexapi.media.SubtitleStream`>: List of SubtitleStream objects.
        )languagehearingImpairedforcedrl   )r(   r   joinArgsra   )rH   r   r   r   rq   r(   s         rJ   searchSubtitleszVideo.searchSubtitlesx   sC    ( !.

 
*U^^F%;$<=s##rL   c                     | j                    d}d|j                   i}| j                  j                  || j                  j                  j                  |       | S )a   Download on-demand subtitles for the video.
            See https://support.plex.tv/articles/subtitle-search/.

            Note: This method is asynchronous and returns immediately before subtitles are fully downloaded.

            Parameters:
                subtitleStream (:class:`~plexapi.media.SubtitleStream`):
                    Subtitle object returned from :func:`~plexapi.video.Video.searchSubtitles`.
        rl   r(   )rq   )r(   rO   r`   rx   put)rH   subtitleStreamr(   rq   s       rJ   downloadSubtitleszVideo.downloadSubtitles   sR     
*%++,3 5 5 9 9&IrL   Nc                    |$	 t        fd| j                         D              }| j                  j                  |j                  | j                  j                  j                         | S # t        $ r t        d d d      dw xY w)a;   Remove an upload or downloaded subtitle from the video.

            Note: If the subtitle file is located inside video directory it will be deleted.
            Files outside of video directory are not affected.
            Embedded subtitles cannot be removed.

            Parameters:
                subtitleStream (:class:`~plexapi.media.SubtitleStream`, optional): Subtitle object to remove.
                streamID (int, optional): ID of the subtitle stream to remove.
                streamTitle (str, optional): Title of the subtitle stream to remove.
        Nc              3   ^   K   | ]$  }|j                   k(  s|j                  k(  r| & y wN)idr4   )rV   streamstreamIDstreamTitles     rJ   rX   z(Video.removeSubtitles.<locals>.<genexpr>   s0      &%699,v||0K &s   *-zSubtitle stream with ID 'z' or title 'z' not found.)	r]   subtitleStreamsStopIterationr   rO   r`   r(   rx   delete)rH   r   r   r   s     ``rJ   removeSubtitleszVideo.removeSubtitles   s     !x!% &)-)=)=)?& " 	>--t||/D/D/K/KL	 ! x #<XJlS^R__k!lmswwxs   #A/ /Bc                    ddl m} ddlm}	m}
 | j                  d      }|j                   d}| j                  j                  j                  d      D ci c]'  }|j                  j                         |j                  ) }}|d   |d<   |d	   |d
<   |d   |d<   |j                  |j                         d      }|s|r|t        d      |rd}n	|r|sd| }| j                         }dg|j!                         D cg c]  }|j                   c}z   }t#        ||      r|j                  }||vrt        d| d|       t#        | t$        t&        f      rdt)        | j                   d       }n%d|j*                   dt)        | j                         }|	j-                  ||      }d|xs | j/                         |||||j0                  t3        |j4                        t3        t7        |j8                              d	}|r||d<   |rW|
j;                  |      }|j<                  |d<   |j>                  |d<   |j@                  |d<   d|d<   d|d<   d|d<   d|d <   d|d!<   |tC        jD                  |      z   }| j                  jG                  || j                  jH                  jJ                  "       | S c c}w c c}w )#a	   Create an optimized version of the video.

            Parameters:
                title (str, optional): Title of the optimized video.
                target (str, optional): Target quality profile:
                    "Optimized for Mobile" ("mobile"), "Optimized for TV" ("tv"), "Original Quality" ("original"),
                    or custom quality profile name (default  "Custom: {deviceProfile}").
                deviceProfile (str, optional): Custom quality device profile:
                    "Android", "iOS", "Universal Mobile", "Universal TV", "Windows Phone", "Windows", "Xbox One".
                    Required if ``target`` is custom.
                videoQuality (int, optional): Index of the quality profile, one of ``VIDEO_QUALITY_*``
                    values defined in the :mod:`~plexapi.sync` module. Only used if ``target`` is custom.
                locationID (int or :class:`~plexapi.library.Location`, optional): Default -1 for
                    "In folder with original items", otherwise a :class:`~plexapi.library.Location` object or ID.
                    See examples below.
                limit (int, optional): Maximum count of items to optimize, unlimited if ``None``.
                unwatched (bool, optional): ``True`` to only optimized unwatched videos.

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: Unknown quality profile target
                    or missing deviceProfile and videoQuality.
                :exc:`~plexapi.exceptions.BadRequest`: Unknown location ID.

            Example:

                .. code-block:: python

                    # Optimize for mobile using defaults
                    video.optimize(target="mobile")

                    # Optimize for Android at 10 Mbps 1080p
                    from plexapi.sync import VIDEO_QUALITY_10_MBPS_1080p
                    video.optimize(deviceProfile="Android", videoQuality=sync.VIDEO_QUALITY_10_MBPS_1080p)

                    # Optimize for iOS at original quality in library location
                    from plexapi.sync import VIDEO_QUALITY_ORIGINAL
                    locations = plex.library.section("Movies")._locations()
                    video.optimize(deviceProfile="iOS", videoQuality=VIDEO_QUALITY_ORIGINAL, locationID=locations[0])

                    # Optimize for tv the next 5 unwatched episodes
                    show.optimize(target="tv", limit=5, unwatched=True)

        r   )Location)PolicyMediaSettingsz/playlists?type=42z/itemsmediaProcessingTargetzoptimized for mobilemobilezoptimized for tvtvzoriginal qualityoriginalr)   zIUnknown quality profile target or missing deviceProfile and videoQuality.zCustom: zUnknown location ID "z	" not in zlibrary:///directory/	/children
library:///item/*   )	z
Item[type]zItem[title]zItem[target]zItem[targetTagID]zItem[locationID]zItem[Location][uri]zItem[Policy][scope]zItem[Policy][value]zItem[Policy][unwatched]zItem[Device][profile]z!Item[MediaSettings][videoQuality]z$Item[MediaSettings][videoResolution]z$Item[MediaSettings][maxVideoBitrate]zItem[MediaSettings][audioBoost]z!Item[MediaSettings][subtitleSize]z!Item[MediaSettings][musicBitrate]z!Item[MediaSettings][photoQuality]z$Item[MediaSettings][photoResolution])method)&plexapi.libraryr   plexapi.syncr   r   	fetchItemr(   rO   librarytagstaglowerr   r=   r   section
_locations
isinstanceShowSeasonr   uuidcreateri   scopestrrU   rD   	unwatchedcreateVideovideoQualityvideoResolutionmaxVideoBitrater   r   r`   rx   r   )rH   r4   targetdeviceProfiler   
locationIDlimitr   r   r   r   backgroundProcessingr(   tr   targetTagIDr   locationlibraryLocationIDsuripolicyrq   mediaSettingsrP   s                           rJ   optimizezVideo.optimize   s   Z 	-6#~~.BC%))*&1-1\\-A-A-F-FG^-_`qtt#``45X,-T
 23Zhhv||~r2M\5IhiiF6/F,,. TASASAU$VXX[[$VVj(+#J//4ZL	J\I]^__dT6N+)*z5K*L)MNCw||nF:dhh3G2HICui0  <D$:$:$<"!, *#&#)<<#&v||#4'*3v/?/?+@'A

 .;F*+)55lCM:G:T:TF67=J=Z=ZF9:=J=Z=ZF9:8:F45:<F67:<F67:<F67=?F9:ENN6**3t||'<'<'@'@Aq a %Ws   ,J9?J>c                 r   ddl m}m}m}	 | j                  j                         }
 || j                  d      }|r|n| j                         |_        | j                  |_        | j                  |_
        | j                  |_        | j                  j                  |_        | j                  j                  j                  | j                         }d|j"                   dt%        | j&                         |_        |j+                  ||      |_        |	j/                  |      |_        |
j3                  |||      S )ae   Add current video (movie, tv-show, season or episode) as sync item for specified device.
            See :func:`~plexapi.myplex.MyPlexAccount.sync` for possible exceptions.

            Parameters:
                videoQuality (int): idx of quality of the video, one of VIDEO_QUALITY_* values defined in
                                    :mod:`~plexapi.sync` module.
                client (:class:`~plexapi.myplex.MyPlexDevice`): sync destination, see
                                                               :func:`~plexapi.myplex.MyPlexAccount.sync`.
                clientId (str): sync destination, see :func:`~plexapi.myplex.MyPlexAccount.sync`.
                limit (int): maximum count of items to sync, unlimited if `None`.
                unwatched (bool): if `True` watched videos wouldn't be synced.
                title (str): descriptive title for the new :class:`~plexapi.sync.SyncItem`, if empty the value would be
                             generated from metadata of current media.

            Returns:
                :class:`~plexapi.sync.SyncItem`: an instance of created syncItem.
        r   )SyncItemr   r   Nr   r   )clientclientId)r   r   r   r   rO   r\   ri   r4   	rootTitlerE   contentTypeMETADATA_TYPEmetadataTypemachineIdentifierr   sectionByIDr,   r   r   r(   r   r   r   r   r   sync)rH   r   r   r   r   r   r4   r   r   r   myplex	sync_itemr   s                rJ   r   z
Video.sync'  s    & 	A@++-T\\40	#(%d.D.D.F	"jj	 $	!%!3!3	&*ll&D&D	#,,&&2243H3HI)',,vj>R=ST	!==	:	"/";";L"I	{{9Vh{GGrL   )enr   r   NNN)r)   r)   r)   Nr   NF)NNNFN)__name__
__module____qualname____doc__rK   rP   rd   ri   r~   r   r   r   r   r    rL   rJ   r!   r!      sH    <J6K0$$$60 LP6;kZ#HrL   r!   c                       e Zd ZdZdZdZdZd Zed        Z	ed        Z
ed        Zed        Zed	        Zd
 Zd Zd Zd Zed        Zy)Movieul   Represents a single Movie.

        Attributes:
            TAG (str): 'Video'
            TYPE (str): 'movie'
            audienceRating (float): Audience rating (usually from Rotten Tomatoes).
            audienceRatingImage (str): Key to audience rating image (rottentomatoes://image.rating.spilled).
            chapters (List<:class:`~plexapi.media.Chapter`>): List of Chapter objects.
            chapterSource (str): Chapter source (agent; media; mixed).
            collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
            contentRating (str) Content rating (PG-13; NR; TV-G).
            countries (List<:class:`~plexapi.media.Country`>): List of countries objects.
            directors (List<:class:`~plexapi.media.Director`>): List of director objects.
            duration (int): Duration of the movie in milliseconds.
            editionTitle (str): The edition title of the movie (e.g. Director's Cut, Extended Edition, etc.).
            enableCreditsMarkerGeneration (int): Setting that indicates if credits markers detection is enabled.
                (-1 = Library default, 0 = Disabled)
            genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
            guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
            labels (List<:class:`~plexapi.media.Label`>): List of label objects.
            languageOverride (str): Setting that indicates if a language is used to override metadata
                (eg. en-CA, None = Library default).
            markers (List<:class:`~plexapi.media.Marker`>): List of marker objects.
            media (List<:class:`~plexapi.media.Media`>): List of media objects.
            originallyAvailableAt (datetime): Datetime the movie was released.
            originalTitle (str): Original title, often the foreign title (転々; 엽기적인 그녀).
            primaryExtraKey (str) Primary extra key (/library/metadata/66351).
            producers (List<:class:`~plexapi.media.Producer`>): List of producers objects.
            rating (float): Movie critic rating (7.9; 9.8; 8.1).
            ratingImage (str): Key to critic rating image (rottentomatoes://image.rating.rotten).
            ratings (List<:class:`~plexapi.media.Rating`>): List of rating objects.
            roles (List<:class:`~plexapi.media.Role`>): List of role objects.
            slug (str): The clean watch.plex.tv URL identifier for the movie.
            similar (List<:class:`~plexapi.media.Similar`>): List of Similar objects.
            sourceURI (str): Remote server URI (server://<machineIdentifier>/com.plexapp.plugins.library)
                (remote playlist item only).
            studio (str): Studio that created movie (Di Bonaventura Pictures; 21 Laps Entertainment).
            tagline (str): Movie tag line (Back 2 Work; Who says men can't change?).
            theme (str): URL to theme resource (/library/metadata/<ratingkey>/theme/<themeid>).
            ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
            useOriginalTitle (int): Setting that indicates if the original title is used for the movie
                (-1 = Library default, 0 = No, 1 = Yes).
            viewOffset (int): View offset in milliseconds.
            writers (List<:class:`~plexapi.media.Writer`>): List of writers objects.
            year (int): Year movie was released.
    r!   moviec                 p   t         j                  | |       t        j                  | |       t        j                  t
        |j                  j                  d            | _        |j                  j                  d      | _	        | j                  |t        j                        | _        |j                  j                  d      | _        | j                  |t        j                        | _        |j                  j                  d      | _        | j                  |t        j$                        | _        | j                  |t        j(                        | _        t        j                  t,        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  t,        |j                  j                  dd            | _        | j                  |t        j4                        | _        | j                  |t        j8                        | _        | j                  |t        j<                        | _        |j                  j                  d	      | _         | j                  |t        jB                        | _"        | j                  |t        jF                        | _        t        jH                  |j                  j                  d
      d      | _%        |j                  j                  d      | _&        |j                  j                  d      | _'        | j                  |t        jP                        | _)        t        j                  t
        |j                  j                  d            | _*        |j                  j                  d      | _+        | j                  |t        jX                        | _-        | j                  |t        j\                        | _/        |j                  j                  d      | _0        | j                  |t        jb                        | _2        |j                  j                  d      | _3        |j                  j                  d      | _4        |j                  j                  d      | _5        |j                  j                  d      | _6        | jo                  |t        jp                        | _9        t        j                  t,        |j                  j                  dd            | _:        t        j                  t,        |j                  j                  dd            | _;        | j                  |t        jx                        | _=        t        j                  t,        |j                  j                  d            | _>        y)r#   audienceRatingaudienceRatingImagechapterSourcecontentRatingdurationeditionTitleenableCreditsMarkerGeneration-1languageOverrideoriginallyAvailableAt%Y-%m-%doriginalTitleprimaryExtraKeyratingratingImageslugsourcestudiotaglinethemeuseOriginalTitle
viewOffsetr   yearN)?r!   rK   r   r   rC   rF   r<   r=   r   r   r>   r   Chapterchaptersr   
Collectioncollectionsr   Country	countriesDirector	directorsrD   r   r   r   GenregenresGuidguidsLabellabelsr   MarkermarkersMediar;   r   r   r   Producer	producersr   r   RatingratingsRolerolesr   Similarsimilar	sourceURIr   r   r   findItemUltraBlurColorsultraBlurColorsr   r   Writerwritersr   rG   s     rJ   rK   zMovie._loadData  s   d#4&#jj@P0QR#';;??3H#I tU]];![[___=>>$0@0@A![[___=emm<enn=

3
(CD KKOON;-2ZZT[[__Mlnr=s-t*nnT5;;7^^D%**5
nnT5;;7 $0B C~~dELL9^^D%++6
%*%5%5dkkooF]6^`j%k"![[___=#{{/@Aenn=jj(AB;;??=9~~dELL9^^D%**5
KKOOF+	~~dEMM:2kkooh/{{y1[[__W-
#}}T53H3HI %

3@RTX0Y Z**S$++//,*JK~~dELL9JJsDKKOOF$;<	rL   c                     | j                   S z Alias to self.roles. r	  rh   s    rJ   actorszMovie.actors       zzrL   c                 b    | j                         D cg c]  }|s|j                   c}S c c}w )z This does not exist in plex xml response but is added to have a common
            interface to get the locations of the movie.

            Returns:
                List<str> of file paths where the movie is found on disk.
        	iterPartsfilerQ   s     rJ   	locationszMovie.locations  %     '+nn&6?d$		???   ,,c                 :    t        d | j                  D              S )z1 Returns True if the movie has a credits marker. c              3   :   K   | ]  }|j                   d k(    ywcreditsNr6   rV   markers     rJ   rX   z)Movie.hasCreditsMarker.<locals>.<genexpr>       G6;;)+G   anyr  rh   s    rJ   hasCreditsMarkerzMovie.hasCreditsMarker       G$,,GGGrL   c                 :    t        d | j                  D              S )? Returns True if any of the media has voice activity analyzed. c              3   4   K   | ]  }|j                     y wr   hasVoiceActivityrV   r   s     rJ   rX   z)Movie.hasVoiceActivity.<locals>.<genexpr>       Be5))B   r(  r   rh   s    rJ   r/  zMovie.hasVoiceActivity       BtzzBBBrL   c                 :    t        d | j                  D              S )P Returns True if any of the media parts has generated preview (BIF) thumbnails. c              3   V   K   | ]!  }|j                   D ]  }|j                    # y wr   partshasPreviewThumbnailsrV   r   rR   s      rJ   rX   z-Movie.hasPreviewThumbnails.<locals>.<genexpr>  *     ]QVQ\Q\]4,,],]   ')r3  rh   s    rJ   r:  zMovie.hasPreviewThumbnails       ]$**]]]rL   c                 :    | j                    d| j                   dS ) Returns a filename for use in download. z ())r4   r   rh   s    rJ   _prettyfilenamezMovie._prettyfilename  s    **R		{!,,rL   c                 d    | j                    d}| j                  |t        j                  d      S )z; Returns a list of :class:`~plexapi.media.Review` objects. z?includeReviews=1r!   clsrtag)r(   ra   r   ReviewrH   r(   s     rJ   reviewszMovie.reviews  s,    
+,s7CCrL   c                 t    | j                   | j                  d}| j                         j                  |      S )zs Returns a list of :class:`~plexapi.video.Movie` objects
            for other editions of the same movie.
        )r'   zid!)filters)r'   r0   r   search)rH   rL  s     rJ   editionszMovie.editions  s5    
 II>>
 ||~$$W$55rL   c                     d}d| j                   i}| j                  j                  ||| j                  j                  j                         | S z* Remove the movie from continue watching. z#/actions/removeFromContinueWatchingr0   )rq   r   r0   rO   r`   rx   r   rH   r(   rq   s      rJ   removeFromContinueWatchingz Movie.removeFromContinueWatching  C    3t~~.3vdll6K6K6O6OPrL   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S L Returns the Plex Media Server data directory where the metadata is stored. MetadataMoviesr   rm   N.bundler   sha1hashr'   r   r   rH   	guid_hashs     rJ   metadataDirectoryzMovie.metadataDirectory  G     NN499-	4
#h.1=9QR=/QX@YYZZrL   N)r   r   r   r   TAGTYPEr   rK   propertyr  r  r)  r/  r:  rC  rJ  rN  rS  r_  r   rL   rJ   r   r   M  s    -\ CDM'=R   @ @ H H C C ^ ^-D
6 [ [rL   r   c                       e Zd ZdZdZdZdZd Zd Ze	d        Z
e	d        Zd	 ZddZd ZddZd ZddZd Zd ZddZe	d        Zy
)r   a   Represents a single Show (including all seasons and episodes).

        Attributes:
            TAG (str): 'Directory'
            TYPE (str): 'show'
            audienceRating (float): Audience rating (TMDB or TVDB).
            audienceRatingImage (str): Key to audience rating image (tmdb://image.rating).
            audioLanguage (str): Setting that indicates the preferred audio language.
            autoDeletionItemPolicyUnwatchedLibrary (int): Setting that indicates the number of unplayed
                episodes to keep for the show (0 = All episodes, 5 = 5 latest episodes, 3 = 3 latest episodes,
                1 = 1 latest episode, -3 = Episodes added in the past 3 days, -7 = Episodes added in the
                past 7 days, -30 = Episodes added in the past 30 days).
            autoDeletionItemPolicyWatchedLibrary (int): Setting that indicates if episodes are deleted
                after being watched for the show (0 = Never, 1 = After a day, 7 = After a week,
                100 = On next refresh).
            childCount (int): Number of seasons (including Specials) in the show.
            collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
            contentRating (str) Content rating (PG-13; NR; TV-G).
            duration (int): Typical duration of the show episodes in milliseconds.
            enableCreditsMarkerGeneration (int): Setting that indicates if credits markers detection is enabled.
                (-1 = Library default, 0 = Disabled).
            episodeSort (int): Setting that indicates how episodes are sorted for the show
                (-1 = Library default, 0 = Oldest first, 1 = Newest first).
            flattenSeasons (int): Setting that indicates if seasons are set to hidden for the show
                (-1 = Library default, 0 = Hide, 1 = Show).
            genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
            guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
            index (int): Plex index number for the show.
            key (str): API URL (/library/metadata/<ratingkey>).
            labels (List<:class:`~plexapi.media.Label`>): List of label objects.
            languageOverride (str): Setting that indicates if a language is used to override metadata
                (eg. en-CA, None = Library default).
            leafCount (int): Number of items in the show view.
            locations (List<str>): List of folder paths where the show is found on disk.
            network (str): The network that distributed the show.
            originallyAvailableAt (datetime): Datetime the show was released.
            originalTitle (str): The original title of the show.
            rating (float): Show rating (7.9; 9.8; 8.1).
            ratings (List<:class:`~plexapi.media.Rating`>): List of rating objects.
            roles (List<:class:`~plexapi.media.Role`>): List of role objects.
            seasonCount (int): Number of seasons (excluding Specials) in the show.
            showOrdering (str): Setting that indicates the episode ordering for the show
                (None = Library default, tmdbAiring = The Movie Database (Aired),
                aired = TheTVDB (Aired), dvd = TheTVDB (DVD), absolute = TheTVDB (Absolute)).
            similar (List<:class:`~plexapi.media.Similar`>): List of Similar objects.
            slug (str): The clean watch.plex.tv URL identifier for the show.
            studio (str): Studio that created show (Di Bonaventura Pictures; 21 Laps Entertainment).
            subtitleLanguage (str): Setting that indicates the preferred subtitle language.
            subtitleMode (int): Setting that indicates the auto-select subtitle mode.
                (-1 = Account default, 0 = Manually selected, 1 = Shown with foreign audio, 2 = Always enabled).
            tagline (str): Show tag line.
            theme (str): URL to theme resource (/library/metadata/<ratingkey>/theme/<themeid>).
            ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
            useOriginalTitle (int): Setting that indicates if the original title is used for the show
                (-1 = Library default, 0 = No, 1 = Yes).
            viewedLeafCount (int): Number of items marked as played in the show view.
            year (int): Year the show was released.
    	Directoryshowepisodec                    t         j                  | |       t        j                  t        |j
                  j                  d            | _        |j
                  j                  d      | _        |j
                  j                  dd      | _	        t        j                  t        |j
                  j                  dd            | _        t        j                  t        |j
                  j                  dd            | _        t        j                  t        |j
                  j                  d            | _        | j                  |t        j                         | _        |j
                  j                  d	      | _        t        j                  t        |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                  |t        j.                        | _        | j                  |t        j2                        | _        t        j                  t        |j
                  j                  d            | _        | j8                  j;                  dd      | _        | j                  |t        j<                        | _        |j
                  j                  d      | _         t        j                  t        |j
                  j                  d            | _!        | jE                  |dd      | _#        |j
                  j                  d      | _$        t        jJ                  |j
                  j                  d      d      | _&        |j
                  j                  d      | _'        t        j                  t        |j
                  j                  d            | _(        | j                  |t        jR                        | _*        | j                  |t        jV                        | _,        t        j                  t        |j
                  j                  d| j                              | _-        |j
                  j                  d      | _.        | j                  |t        j^                        | _0        |j
                  j                  d      | _1        |j
                  j                  d      | _2        |j
                  j                  dd      | _3        t        j                  t        |j
                  j                  d d            | _4        |j
                  j                  d!      | _5        |j
                  j                  d"      | _6        | jo                  |t        jp                        | _9        t        j                  t        |j
                  j                  d#d            | _:        t        j                  t        |j
                  j                  d$            | _;        t        j                  t        |j
                  j                  d%            | _<        y&)'r#   r   r   audioLanguager)   &autoDeletionItemPolicyUnwatchedLibrary0$autoDeletionItemPolicyWatchedLibrary
childCountr   r   r   r   episodeSortflattenSeasonsindexr   r   	leafCountrt   r   )etagnetworkr   r   r   r   seasonCountshowOrderingr   r   subtitleLanguagesubtitleModer   r   r   viewedLeafCountr   N)=r!   rK   r   rC   rF   r<   r=   r   r   ri  rD   rj  rl  rm  r>   r   r   r   r   r   r   rn  ro  r   r   r   r   rp  r(   replacer   r   r   rq  	listAttrsr  rs  r;   r   r   r   r  r  r  r	  rt  ru  r
  r  r   r   rv  rw  r   r   r  r  r  r   rx  r   rG   s     rJ   rK   zShow._loadData5  s6   d##jj@P0QR#';;??3H#I ![[___bA6;jj!I3O7Q349JJ!GM5O1**S$++//,*GH>>$0@0@A![[___=

3
(CD-2ZZT[[__Mlnr=s-t* ::c4;;??=$+OP#jjdkkoo>NPT.UVnnT5;;7^^D%**5
ZZT[[__W%=>
88##K4nnT5;;7 $0B CC)EFf:F{{y1%*%5%5dkkooF]6^`j%k"![[___=jj(AB~~dELL9^^D%**5
 ::c4;;??=$//+Z[ KKOON;~~dEMM:KKOOF+	kkooh/ $0BB G!JJsDKKOOND,QR{{y1[[__W-
#}}T53H3HI %

3@RTX0Y Z$zz#t{{?P/QRJJsDKKOOF$;<	rL   c              #   >   K   | j                         D ]  }|  y wr   )seasons)rH   seasons     rJ   __iter__zShow.__iter__b  s      lln 	FL	   c                     | j                   S r  r  rh   s    rJ   r  zShow.actorsf  r  rL   c                 F    t        | j                  | j                  k(        S )z+ Returns True if the show is fully played. boolrx  rq  rh   s    rJ   isPlayedzShow.isPlayedk       D((DNN:;;rL   c           	      v    | j                    d}t        t        | j                  |t        d            d      S )z Returns show's On Deck :class:`~plexapi.video.Video` object or `None`.
            If show is unwatched, return will likely be the first episode.
        ?includeOnDeck=1OnDeckrE  Nr(   r]   iterra   EpisoderI  s     rJ   onDeckzShow.onDeckp  6     
*+D'IJDQQrL   Nc                    | j                    d}|(t        |t              s| j                  |t        |      S |t        |t              r-t        |t              r|}n|}| j                  |t        |      S t        d      )ah   Returns the season with the specified title or number.

            Parameters:
                title (str): Title of the season to return.
                season (int): Season number (default: None; required if title not specified).

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: If title or season parameter is missing.
        /children?excludeAllLeaves=1title__iexactrp  z-Missing argument: title or season is required)r(   r   rD   r   r   r   )rH   r4   r}  r(   rp  s        rJ   r}  zShow.seasonw  s}     
67Zs%;>>#vU>CC:eS#9%%>>#vU>;;HIIrL   c                 h    | j                    d} | j                  |t        fd| j                  i|S )zG Returns a list of :class:`~plexapi.video.Season` objects in the show. r  container_size)r(   ra   r   rm  rH   kwargsr(   s      rJ   r|  zShow.seasons  s4    
67tsFU4??UfUUrL   c                     | j                    d}|| j                  |t        |      S ||| j                  |t        ||      S t        d      )a   Find a episode using a title or season and episode.

            Parameters:
                title (str): Title of the episode to return
                season (int): Season number (default: None; required if title not specified).
                episode (int): Episode number (default: None; required if title not specified).

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: If title or season and episode parameters are missing.
        
/allLeavesr  parentIndexrp  z:Missing argument: title or season and episode are required)r(   r   r  r   )rH   r4   r}  rg  r(   s        rJ   rg  zShow.episode  s]     
*%>>#we>DDG$7>>#wF'>RRUVVrL   c                 P    | j                    d} | j                  |t        fi |S )zH Returns a list of :class:`~plexapi.video.Episode` objects in the show. r  r(   ra   r  r  s      rJ   episodeszShow.episodes  s*    
*%tsG6v66rL   c                 (    | j                  |||      S )z/ Alias to :func:`~plexapi.video.Show.episode`. rg  )rH   r4   r}  rg  s       rJ   r=   zShow.get  s    ||E6733rL   c                 &    | j                  d      S zB Returns list of watched :class:`~plexapi.video.Episode` objects. r   )viewCount__gtr  rh   s    rJ   watchedzShow.watched      }}1}--rL   c                 &    | j                  d      S zD Returns list of unwatched :class:`~plexapi.video.Episode` objects. r   )r9   r  rh   s    rJ   r   zShow.unwatched      }}q}))rL   c                     g }| j                         D ]b  }|rEt        j                  j                  |dt	        |j
                        j                  d             n|}| |j                  ||fi |z  }d |S )a   Download all episodes from the show. See :func:`~plexapi.base.Playable.download` for details.

            Parameters:
                savepath (str): Defaults to current working dir.
                keep_original_name (bool): True to keep the original filename otherwise
                    a friendlier filename is generated.
                subfolders (bool): True to separate episodes in to season folders.
                **kwargs: Additional options passed into :func:`~plexapi.base.PlexObject.getStreamURL`.
        zSeason    )r  rs   rt   joinr   seasonNumberzfilldownload)rH   savepathkeep_original_name
subfoldersr  	filepathsrg  	_savepaths           rJ   r  zShow.download  s     	}} 	SGblXW=Q=Q9R9X9XYZ9[8\/]^rzI))))5GR6RRI	S rL   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S rW  rX  zTV Showsr   rm   NrZ  r[  r]  s     rJ   r_  zShow.metadataDirectory  sG     NN499-	4
#j09Q<?Yqr]OSZB[[\\rL   NNr   )NFF)r   r   r   r   ra  rb  r   rK   r~  rc  r  r  r  r}  r|  rg  r  r=   r  r   r  r_  r   rL   rJ   r   r     s    9t CDM+=Z   < <RJ*V
W$7
4.*  ] ]rL   r   c                       e Zd ZdZdZdZdZd Zd Zd Z	e
d        Ze
d	        Zd
 ZddZd ZddZd Zd Zd ZddZd Ze
d        Zy)r   a4   Represents a single Season.

        Attributes:
            TAG (str): 'Directory'
            TYPE (str): 'season'
            audienceRating (float): Audience rating.
            audioLanguage (str): Setting that indicates the preferred audio language.
            collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
            guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
            index (int): Season number.
            key (str): API URL (/library/metadata/<ratingkey>).
            labels (List<:class:`~plexapi.media.Label`>): List of label objects.
            leafCount (int): Number of items in the season view.
            parentGuid (str): Plex GUID for the show (plex://show/5d9c086fe9d5a1001f4d9fe6).
            parentIndex (int): Plex index number for the show.
            parentKey (str): API URL of the show (/library/metadata/<parentRatingKey>).
            parentRatingKey (int): Unique key identifying the show.
            parentSlug (str): The clean watch.plex.tv URL identifier for the show.
            parentStudio (str): Studio that created show.
            parentTheme (str): URL to show theme resource (/library/metadata/<parentRatingkey>/theme/<themeid>).
            parentThumb (str): URL to show thumbnail image (/library/metadata/<parentRatingKey>/thumb/<thumbid>).
            parentTitle (str): Name of the show for the season.
            rating (float): Season rating (7.9; 9.8; 8.1).
            ratings (List<:class:`~plexapi.media.Rating`>): List of rating objects.
            subtitleLanguage (str): Setting that indicates the preferred subtitle language.
            subtitleMode (int): Setting that indicates the auto-select subtitle mode.
                (-1 = Series default, 0 = Manually selected, 1 = Shown with foreign audio, 2 = Always enabled).
            ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
            viewedLeafCount (int): Number of items marked as played in the season view.
            year (int): Year the season was released.
    re  r}  rg  c                    t         j                  | |       t        j                  t        |j
                  j                  d            | _        |j
                  j                  dd      | _        | j                  |t        j                        | _        | j                  |t        j                        | _        t        j                  t        |j
                  j                  d            | _        | j"                  j%                  dd      | _        | j                  |t        j&                        | _        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      | _        |j
                  j                  d      | _        |j
                  j                  d      | _        t        j                  t        |j
                  j                  d            | _        | j                  |t        j@                        | _!        |j
                  j                  dd      | _"        t        j                  t        |j
                  j                  dd            | _#        | jI                  |t        jJ                        | _&        t        j                  t        |j
                  j                  d            | _'        t        j                  t        |j
                  j                  d            | _(        y)r#   r   ri  r)   rp  r   rq  
parentGuidr  	parentKeyparentRatingKey
parentSlugparentStudioparentThemeparentThumbparentTitler   rv  rw  r   rx  r   N))r!   rK   r   rC   rF   r<   r=   r   ri  r>   r   r   r   r   r   rD   rp  r(   ry  r   r   rq  r  r  r  r  r  r  r  r  r  r   r  r  rv  rw  r  r  r  rx  r   rG   s     rJ   rK   zSeason._loadData  s|   d##jj@P0QR![[___bA>>$0@0@A^^D%**5
ZZT[[__W%=>
88##K4nnT5;;7C)EF++//,7 ::c4;;??=+IJ5$zz#t{{?P/QR++//,7 KKOON;;;??=9;;??=9;;??=9jj(AB~~dELL9 $0BB G!JJsDKKOOND,QR#}}T53H3HI$zz#t{{?P/QRJJsDKKOOF$;<	rL   c              #   >   K   | j                         D ]  }|  y wr   r  )rH   rg  s     rJ   r~  zSeason.__iter__  s      }} 	GM	r  c           
      F   dj                  dj                  | j                  j                  | j                  j                  dd      j                  dd      | j                  j                  dd      d d  d| j                   fD cg c]  }|r| c}            S c c}w 	Nz<{}>:/library/metadata/r)   r    -   )rn   r  	__class__r   r(   ry  r  r  rH   ps     rJ   __repr__zSeason.__repr__  s    }}HH''  !5r:BB;PRS##++C5cr:;1T=N=N<OP" A 	   
 	
   Bc                 F    t        | j                  | j                  k(        S )z- Returns True if the season is fully played. r  rh   s    rJ   r  zSeason.isPlayed  r  rL   c                     | j                   S )z Returns the season number. r  rh   s    rJ   r  zSeason.seasonNumber#  r  rL   c           	      v    | j                    d}t        t        | j                  |t        d            d      S )z Returns season's On Deck :class:`~plexapi.video.Video` object or `None`.
            Will only return a match if the show's On Deck episode is in this season.
        r  r  rE  Nr  rI  s     rJ   r  zSeason.onDeck(  r  rL   Nc                    | j                    d}|(t        |t              s| j                  |t        |      S |t        |t              r8t        |t              r|}n|}| j                  |t        | j
                  |      S t        d      )ai   Returns the episode with the given title or number.

            Parameters:
                title (str): Title of the episode to return.
                episode (int): Episode number (default: None; required if title not specified).

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: If title or episode parameter is missing.
        r   r  r  z.Missing argument: title or episode is required)r(   r   rD   r   r  rp  r   )rH   r4   rg  r(   rp  s        rJ   rg  zSeason.episode/  s     
)$Zs%;>>#we>DD Juc$:%%>>#wDJJe>TTIJJrL   c                 P    | j                    d} | j                  |t        fi |S )zJ Returns a list of :class:`~plexapi.video.Episode` objects in the season. r   r  r  s      rJ   r  zSeason.episodesD  s*    
)$tsG6v66rL   c                 &    | j                  ||      S )z1 Alias to :func:`~plexapi.video.Season.episode`. r  )rH   r4   rg  s      rJ   r=   z
Season.getI  s    ||E7++rL   c                 8    | j                  | j                        S )z3 Return the season's :class:`~plexapi.video.Show`. r   r  rh   s    rJ   rf  zSeason.showM      ~~dnn--rL   c                 &    | j                  d      S r  r  rh   s    rJ   r  zSeason.watchedQ  r  rL   c                 &    | j                  d      S r  r  rh   s    rJ   r   zSeason.unwatchedU  r  rL   c                 b    g }| j                         D ]  }| |j                  ||fi |z  } |S )a   Download all episodes from the season. See :func:`~plexapi.base.Playable.download` for details.

            Parameters:
                savepath (str): Defaults to current working dir.
                keep_original_name (bool): True to keep the original filename otherwise
                    a friendlier filename is generated.
                **kwargs: Additional options passed into :func:`~plexapi.base.PlexObject.getStreamURL`.
        )r  r  )rH   r  r  r  r  rg  s         rJ   r  zSeason.downloadY  sF     	}} 	RG)))(4FQ&QQI	RrL   c                 8    | j                    d| j                   S )rf    - )r  r4   rh   s    rJ   ri   zSeason._defaultSyncTitleg  s    ""#3tzzl33rL   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S r  )r   r\  r  r   r   r]  s     rJ   r_  zSeason.metadataDirectoryk  sG     NN4??3	4
#j09Q<?Yqr]OSZB[[\\rL   r  )NF)r   r   r   r   ra  rb  r   rK   r~  r  rc  r  r  r  rg  r  r=   rf  r  r   r  ri   r_  r   rL   rJ   r   r     s    > CDM=8
 < <  RK*7
,..*4 ] ]rL   r   c                   6   e Zd ZdZdZdZdZd Zed        Z	ed        Z
ed        Zed        Zd	 Zd
 Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zd Zd Zd Zd Zed        Zy)r  a4   Represents a single Episode.

        Attributes:
            TAG (str): 'Video'
            TYPE (str): 'episode'
            audienceRating (float): Audience rating (TMDB or TVDB).
            audienceRatingImage (str): Key to audience rating image (tmdb://image.rating).
            chapters (List<:class:`~plexapi.media.Chapter`>): List of Chapter objects.
            chapterSource (str): Chapter source (agent; media; mixed).
            collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
            contentRating (str) Content rating (PG-13; NR; TV-G).
            directors (List<:class:`~plexapi.media.Director`>): List of director objects.
            duration (int): Duration of the episode in milliseconds.
            grandparentArt (str): URL to show artwork (/library/metadata/<grandparentRatingKey>/art/<artid>).
            grandparentGuid (str): Plex GUID for the show (plex://show/5d9c086fe9d5a1001f4d9fe6).
            grandparentKey (str): API URL of the show (/library/metadata/<grandparentRatingKey>).
            grandparentRatingKey (int): Unique key identifying the show.
            grandparentSlug (str): The clean watch.plex.tv URL identifier for the show.
            grandparentTheme (str): URL to show theme resource (/library/metadata/<grandparentRatingkey>/theme/<themeid>).
            grandparentThumb (str): URL to show thumbnail image (/library/metadata/<grandparentRatingKey>/thumb/<thumbid>).
            grandparentTitle (str): Name of the show for the episode.
            guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
            index (int): Episode number.
            labels (List<:class:`~plexapi.media.Label`>): List of label objects.
            markers (List<:class:`~plexapi.media.Marker`>): List of marker objects.
            media (List<:class:`~plexapi.media.Media`>): List of media objects.
            originallyAvailableAt (datetime): Datetime the episode was released.
            parentGuid (str): Plex GUID for the season (plex://season/5d9c09e42df347001e3c2a72).
            parentIndex (int): Season number of episode.
            parentKey (str): API URL of the season (/library/metadata/<parentRatingKey>).
            parentRatingKey (int): Unique key identifying the season.
            parentThumb (str): URL to season thumbnail image (/library/metadata/<parentRatingKey>/thumb/<thumbid>).
            parentTitle (str): Name of the season for the episode.
            parentYear (int): Year the season was released.
            producers (List<:class:`~plexapi.media.Producer`>): List of producers objects.
            rating (float): Episode rating (7.9; 9.8; 8.1).
            ratings (List<:class:`~plexapi.media.Rating`>): List of rating objects.
            roles (List<:class:`~plexapi.media.Role`>): List of role objects.
            skipParent (bool): True if the show's seasons are set to hidden.
            sourceURI (str): Remote server URI (server://<machineIdentifier>/com.plexapp.plugins.library)
                (remote playlist item only).
            ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
            viewOffset (int): View offset in milliseconds.
            writers (List<:class:`~plexapi.media.Writer`>): List of writers objects.
            year (int): Year the episode was released.
    r!   rg  c                    t         j                  | |       t        j                  | |       t        j                  t
        |j                  j                  d            | _        |j                  j                  d      | _	        | j                  |t        j                        | _        |j                  j                  d      | _        | j                  |t        j                        | _        |j                  j                  d      | _        | j                  |t        j$                        | _        t        j                  t(        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t(        |j                  j                  d	            | _        |j                  j                  d
      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        | j                  |t        j<                        | _        t        j                  t(        |j                  j                  d            | _         | j                  |t        jB                        | _"        | j                  |t        jF                        | _$        | j                  |t        jJ                        | _        t        jL                  |j                  j                  d      d      | _'        |j                  j                  d      | _(        t        j                  t(        |j                  j                  d            | _)        |j                  j                  d      | _*        t        j                  t(        |j                  j                  d            | _+        | j                  |t        jX                        | _-        t        j                  t
        |j                  j                  d            | _.        | j                  |t        j^                        | _0        | j                  |t        jb                        | _2        t        j                  tf        |j                  j                  dd            | _4        |j                  j                  d      | _5        | jm                  |t        jn                        | _8        t        j                  t(        |j                  j                  dd            | _9        | j                  |t        jt                        | _;        t        j                  t(        |j                  j                  d            | _<        |j                  j                  d      | _=        t        j                  t(        |j                  j                  d            | _>        |j                  j                  d      | _?        y) r#   r   r   r   r   r   grandparentArtgrandparentGuidgrandparentKeygrandparentRatingKeygrandparentSluggrandparentThemegrandparentThumbgrandparentTitlerp  r   r   r  r  r  
parentYearr   
skipParentrk  r   r   r   r   r  r  r  N)@r!   rK   r   r   rC   rF   r<   r=   r   r   r>   r   r   r   r   r   r   r   r   r   rD   r   r  r  r  r  r  r  r  r  r   r   rp  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   
_parentKey_parentRatingKey_parentThumbrG   s     rJ   rK   zEpisode._loadData  s   d#4&#jj@P0QR#';;??3H#I tU]];![[___=>>$0@0@A![[___=enn=

3
(CD"kkoo.>?#{{/@A"kkoo.>?$)JJsDKKOODZ4[$\!#{{/@A $0B C $0B C $0B C^^D%**5
ZZT[[__W%=>
nnT5;;7~~dELL9^^D%++6
%*%5%5dkkooF]6^`j%k"++//,7 ::c4;;??=+IJ;;??=9**S$++//,*GHenn=jj(AB~~dELL9^^D%**5
**T4;;??<+MN2#}}T53H3HI**S$++//,*JK~~dELL9JJsDKKOOF$;<	
 ++//+6 %

3@Q0R S KKOOM:rL   c                 j    | j                   r| j                   S | j                  rd| j                   S y)z9 Returns the parentKey. Refer to the Episode attributes. r  N)r  r  rh   s    rJ   r  zEpisode.parentKey  s5     ????"'(<(<'=>>rL   c                 2   | j                   | j                   S | j                  rQ| j                  j                  d      r6t        j                  t
        | j                  j                  d      d         S | j                  r| j                  j                  S y)z? Returns the parentRatingKey. Refer to the Episode attributes. Nr  /   )	r  r  
startswithr   rC   rD   split_seasonr0   rh   s    rJ   r  zEpisode.parentRatingKey  sz       ,(((!2!2!=!=>R!S::c4#4#4#:#:3#?#BCC<<<<)))rL   c                 x    | j                   r| j                   S | j                  r| j                  j                  S y)z; Returns the parentThumb. Refer to the Episode attributes. N)r  r  r2   rh   s    rJ   r  zEpisode.parentThumb  s3     $$$<<<<%%%rL   c                     | j                   r6| j                  *| j                  | j                    d| j                         S y)zX Returns the :class:`~plexapi.video.Season` object by querying for the show's children. Nz#/children?excludeAllLeaves=1&index=)r  r  r   rh   s    rJ   r  zEpisode._season  sE     4#3#3#?>>T%8%8$99\]a]m]m\n"opprL   c           
      F   dj                  dj                  | j                  j                  | j                  j                  dd      j                  dd      | j                  j                  dd      d d  d| j                   fD cg c]  }|r| c}            S c c}w r  )rn   r  r  r   r(   ry  r  seasonEpisoder  s     rJ   r  zEpisode.__repr__  s    }}HH''  !5r:BB;PRS((00c:3B?@$BTBTAUV" A 	   
 	
r  c                 R    | j                    d| j                   d| j                   S )rA  r  )r  r  r4   rh   s    rJ   rC  zEpisode._prettyfilename
  s+    ''(D,>,>+?s4::,OOrL   c                     | j                   S r  r  rh   s    rJ   r  zEpisode.actors  r  rL   c                 b    | j                         D cg c]  }|s|j                   c}S c c}w )z This does not exist in plex xml response but is added to have a common
            interface to get the locations of the episode.

            Returns:
                List<str> of file paths where the episode is found on disk.
        r  rQ   s     rJ   r  zEpisode.locations  r  r  c                     | j                   S )z Returns the episode number. r  rh   s    rJ   episodeNumberzEpisode.episodeNumber  r  rL   c                     t        | j                  t              r| j                  S | j                  r| j                  j                  S y)z& Returns the episode's season number. N)r   r  rD   r  rp  rh   s    rJ   r  zEpisode.seasonNumber"  s:     d&&,###\\<<%%%rL   c                     dt        | j                        j                  d       dt        | j                        j                  d       S )zF Returns the s00e00 string containing the season and episode numbers. sr  e)r   r  r  r  rh   s    rJ   r  zEpisode.seasonEpisode+  sF     3t(()//231S9K9K5L5R5RST5U4VWWrL   c                 :    t        d | j                  D              S )z6 Returns True if the episode has a commercial marker. c              3   :   K   | ]  }|j                   d k(    yw)
commercialNr"  r#  s     rJ   rX   z.Episode.hasCommercialMarker.<locals>.<genexpr>3  s     J66;;,.Jr&  r'  rh   s    rJ   hasCommercialMarkerzEpisode.hasCommercialMarker0  s     JT\\JJJrL   c                 :    t        d | j                  D              S )z2 Returns True if the episode has an intro marker. c              3   :   K   | ]  }|j                   d k(    yw)introNr"  r#  s     rJ   rX   z)Episode.hasIntroMarker.<locals>.<genexpr>8  s     Ef6;;')Er&  r'  rh   s    rJ   hasIntroMarkerzEpisode.hasIntroMarker5  s     EEEErL   c                 :    t        d | j                  D              S )z3 Returns True if the episode has a credits marker. c              3   :   K   | ]  }|j                   d k(    ywr   r"  r#  s     rJ   rX   z+Episode.hasCreditsMarker.<locals>.<genexpr>=  r%  r&  r'  rh   s    rJ   r)  zEpisode.hasCreditsMarker:  r*  rL   c                 :    t        d | j                  D              S )r,  c              3   4   K   | ]  }|j                     y wr   r.  r0  s     rJ   rX   z+Episode.hasVoiceActivity.<locals>.<genexpr>B  r1  r2  r3  rh   s    rJ   r/  zEpisode.hasVoiceActivity?  r4  rL   c                 :    t        d | j                  D              S )r6  c              3   V   K   | ]!  }|j                   D ]  }|j                    # y wr   r8  r;  s      rJ   rX   z/Episode.hasPreviewThumbnails.<locals>.<genexpr>G  r<  r=  r3  rh   s    rJ   r:  zEpisode.hasPreviewThumbnailsD  r>  rL   c                 8    | j                  | j                        S )z7" Return the episode's :class:`~plexapi.video.Season`. r  rh   s    rJ   r}  zEpisode.seasonI  r  rL   c                 8    | j                  | j                        S )z5" Return the episode's :class:`~plexapi.video.Show`. )r   r  rh   s    rJ   rf  zEpisode.showM  s    ~~d1122rL   c                 l    | j                    d| j                   d| j                   d| j                   S )rf   r  z - (z) )r  r  r  r4   rh   s    rJ   ri   zEpisode._defaultSyncTitleQ  s=    ''(D,<,<+=T$BTBTAUUWX\XbXbWcddrL   c                     d}d| j                   i}| j                  j                  ||| j                  j                  j                         | S rP  rQ  rR  s      rJ   rS  z"Episode.removeFromContinueWatchingU  rT  rL   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S r  )r   r\  r  r   r   r]  s     rJ   r_  zEpisode.metadataDirectory\  sI     NN4#7#78	4
#j09Q<?Yqr]OSZB[[\\rL   N)r   r   r   r   ra  rb  r   rK   r   r  r  r  r  r  rC  rc  r  r  r  r  r  r  r  r)  r/  r:  r}  rf  ri   rS  r_  r   rL   rJ   r  r  r  s{   -\ CDM.;`   
 
    
P   @ @     X X K K F F H H C C ^ ^.3e ] ]rL   r  c                   H    e Zd ZdZdZdZdZd Zed        Z	d Z
ed        Zy)	Clipa   Represents a single Clip.

        Attributes:
            TAG (str): 'Video'
            TYPE (str): 'clip'
            duration (int): Duration of the clip in milliseconds.
            extraType (int): Unknown.
            index (int): Plex index number for the clip.
            media (List<:class:`~plexapi.media.Media`>): List of media objects.
            originallyAvailableAt (datetime): Datetime the clip was released.
            skipDetails (int): Unknown.
            subtype (str): Type of clip (trailer, behindTheScenes, sceneOrSample, etc.).
            thumbAspectRatio (str): Aspect ratio of the thumbnail image.
            viewOffset (int): View offset in milliseconds.
            year (int): Year clip was released.
    r!   clipc                    t         j                  | |       t        j                  | |       || _        t	        j
                  |j                  j                  d            | _        t	        j                  t        |j                  j                  d            | _        t	        j                  t        |j                  j                  d            | _        t	        j                  t        |j                  j                  d            | _        | j                  |t        j                         | _        t	        j
                  |j                  j                  d      d      | _        t	        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d	      | _        t	        j                  t        |j                  j                  d
d            | _        t	        j                  t        |j                  j                  d            | _        y)r#   r$   r   	extraTyperp  r   r   skipDetailssubtypethumbAspectRatior   r   r   N)r!   rK   r   r:   r   r;   r<   r=   r$   rC   rD   r   r  rp  r>   r   r  r   r  r  r  r   r   rG   s     rJ   rK   zClip._loadData|  sj   d#4&
''	(BC

3
(CDC)EFZZT[[__W%=>
^^D%++6
%*%5%5KKOO34j&B" ::c4;;??=+IJ{{y1 $0B C**S$++//,*JKJJsDKKOOF$;<	rL   c                 b    | j                         D cg c]  }|s|j                   c}S c c}w )z This does not exist in plex xml response but is added to have a common
            interface to get the locations of the clip.

            Returns:
                List<str> of file paths where the clip is found on disk.
        r  rQ   s     rJ   r  zClip.locations  r  r  c                     | j                   S )rA  rg   rh   s    rJ   rC  zClip._prettyfilename  rj   rL   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S rV  r[  r]  s     rJ   r_  zClip.metadataDirectory  r`  rL   N)r   r   r   r   ra  rb  r   rK   rc  r  rC  r_  r   rL   rJ   r  r  c  sN    
  CDM=$ @ @ [ [rL   r  c                   (     e Zd ZdZ fdZd Z xZS )Extraz< Represents a single Extra (trailer, behindTheScenes, etc). c                     t         t        |   |       | j                         }|j                  | _        |j
                  | _        |j                  | _        yr#   N)superr  rK   _parentr,   r-   r.   )rH   rI   parentr  s      rJ   rK   zExtra._loadData  sG    eT$T* & 7 7!'!9!9#)#=#= rL   c                 :    | j                    d| j                   dS r@  )r4   r  rh   s    rJ   rC  zExtra._prettyfilename  s    **R~Q//rL   )r   r   r   r   rK   rC  __classcell__)r  s   @rJ   r  r    s    F>0rL   r  c                       e Zd ZdZdZd Zy)MovieSessionzh Represents a single Movie session
        loaded from :func:`~plexapi.server.PlexServer.sessions`.
    Tc                 \    t         j                  | |       t        j                  | |       yr!  )r   rK   r   rG   s     rJ   rK   zMovieSession._loadData       d#dD)rL   Nr   r   r   r   _SESSIONTYPErK   r   rL   rJ   r(  r(         L*rL   r(  c                       e Zd ZdZdZd Zy)EpisodeSessionzj Represents a single Episode session
        loaded from :func:`~plexapi.server.PlexServer.sessions`.
    Tc                 \    t         j                  | |       t        j                  | |       yr!  )r  rK   r   rG   s     rJ   rK   zEpisodeSession._loadData  "    $%dD)rL   Nr+  r   rL   rJ   r/  r/    r-  rL   r/  c                       e Zd ZdZdZd Zy)ClipSessionzg Represents a single Clip session
        loaded from :func:`~plexapi.server.PlexServer.sessions`.
    Tc                 \    t         j                  | |       t        j                  | |       yr!  )r  rK   r   rG   s     rJ   rK   zClipSession._loadData       tT"dD)rL   Nr+  r   rL   rJ   r3  r3    r-  rL   r3  c                       e Zd ZdZdZd Zy)MovieHistoryzm Represents a single Movie history entry
        loaded from :func:`~plexapi.server.PlexServer.history`.
    Tc                 \    t         j                  | |       t        j                  | |       yr!  )r   rK   r
   rG   s     rJ   rK   zMovieHistory._loadData  r*  rL   Nr   r   r   r   _HISTORYTYPErK   r   rL   rJ   r7  r7    r-  rL   r7  c                       e Zd ZdZdZd Zy)EpisodeHistoryzo Represents a single Episode history entry
        loaded from :func:`~plexapi.server.PlexServer.history`.
    Tc                 \    t         j                  | |       t        j                  | |       yr!  )r  rK   r
   rG   s     rJ   rK   zEpisodeHistory._loadData  r1  rL   Nr9  r   rL   rJ   r<  r<    r-  rL   r<  c                       e Zd ZdZdZd Zy)ClipHistoryzl Represents a single Clip history entry
        loaded from :func:`~plexapi.server.PlexServer.history`.
    Tc                 \    t         j                  | |       t        j                  | |       yr!  )r  rK   r
   rG   s     rJ   rK   zClipHistory._loadData  r5  rL   Nr9  r   rL   rJ   r?  r?    r-  rL   r?  )3rs   	functoolsr   pathlibr   urllib.parser   plexapir   r   plexapi.baser   r	   r
   r   plexapi.exceptionsr   plexapi.mixinsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   registerPlexObjectr   r   r   r  r  r  r(  r/  r3  r7  r<  r?  r   rL   rJ   <module>rI     sc   	 %  #   N N )     xH2 xHv	 ^[	8?,={IWbij^[ ^[B X]	?,={IWbijX] X]v c]	;im	c] c]L m]	8im	m] m]` <[	8<[ <[~0D 0  	*; 	* 	* 	*[' 	* 	* 	*+t 	* 	* 	*; 	* 	* 	*[' 	* 	* 	*+t 	* 	*rL   