
    lj                        d dl 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mZ d dlmZ d dlmZmZmZmZmZmZ  G d d	e
e      Zej0                   G d
 dee	e             Zej0                   G d dee             Zej0                   G d dee             Zej0                   G d dee	e             Zej0                   G d dee	e             Z G d de      Zej0                   G d dee             Zej0                   G d dee             Z ej0                   G d dee             Z!ej0                   G d dee             Z"ej0                   G d dee             Z#ej0                   G d  d!ee             Z$y)"    N)Path)
quote_plus)mediautils)PlayablePlexPartialObjectPlexHistoryPlexSessioncached_data_property)
BadRequest)MovieMixins
ShowMixinsSeasonMixinsEpisodeMixins
ClipMixinsPlayedUnplayedMixinc                   x    e Zd ZdZd Zed        Ze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                  j                  d      | _        |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| j*                        | _        |j                  j                  d      | _        t        j                  |j                  j                  d            | _        t        j                  t2        |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)r   
toDatetimeattribgetr   r   r   r   r   r   r   castintr   r    r!   listTyper#   r$   r%   r&   r'   r(   r)   r*   floatr+   r,   selfdatas     :/DATA/.local/lib/python3.12/site-packages/plexapi/video.py	_loadDatazVideo._loadData*   s   ''	(BC;;??5);;??=9KKOOF+	;;??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                 V    | j                  | j                  t        j                        S N)	findItems_datar   Fieldr5   s    r7   fieldszVideo.fieldsB       ~~djj%++66r9   c                 V    | j                  | j                  t        j                        S r;   )r<   r=   r   Imager?   s    r7   imageszVideo.imagesF   rA   r9   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r5   parts     r7   rH   z	Video.urlJ   s#    <@t||48JdJr9   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     r7   	<genexpr>z%Video.augmentation.<locals>.<genexpr>V   s)      <*Fw;;":: ]]*Fs   %'NActiveopt_outz+Requires Plex Pass and Tidal Music enabled.z?asyncAugmentMetadata=1augmentationKey)rG   myPlexAccountnextonlineMediaSourcessubscriptionStatusr   queryr   r.   r/   
fetchItems)r5   accounttidalOptOutr6   rS   s        r7   augmentationzVideo.augmentationN   s     ,,,,.<'*D*D*F <

 %%1[I5MJKK||!!$((-F"FG++//*;<//r9   c                     | j                   S )0 Returns str, default title for a new syncItem. r'   r?   s    r7   _defaultSyncTitlezVideo._defaultSyncTitle`       zzr9   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)r'   formatAcceptztext/plain, */*rb)r6   paramsheaders)
r   ospathbasenamesplitextopenrG   rX   _sessionpost)r5   filepathrH   filename	subFormatrh   ri   subfiles           r7   uploadSubtitleszVideo.uploadSubtitlesd   s     
*%77##H-GG$$X.q1!"5	
 ./(D!WLLsDLL$9$9$>$>WU[elm " "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forcedrc   )r   r   joinArgsrY   )r5   rw   rx   ry   rh   r   s         r7   searchSubtitleszVideo.searchSubtitlesv   sC    ( !.

 
*U^^F%;$<=s##r9   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`.
        rc   r   )rh   )r   rG   rX   ro   put)r5   subtitleStreamr   rh   s       r7   downloadSubtitleszVideo.downloadSubtitles   sR     
*%++,3 5 5 9 9&Ir9   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r;   )idr'   )rN   streamstreamIDstreamTitles     r7   rP   z(Video.removeSubtitles.<locals>.<genexpr>   s0      &)?v699,v||0K )?s   *-zSubtitle stream with ID 'z' or title 'z' not found.)	rU   subtitleStreamsStopIterationr   rG   rX   r   ro   delete)r5   r~   r   r   s     ``r7   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   rG   librarytagstaglowerr   r/   r   section
_locations
isinstanceShowSeasonr   uuidcreater`   scopestrrM   r1   	unwatchedcreateVideovideoQualityvideoResolutionmaxVideoBitrater   rz   rX   ro   r}   )r5   r'   targetdeviceProfiler   
locationIDlimitr   r   r   r   backgroundProcessingr   tr   targetTagIDr   locationlibraryLocationIDsuripolicyrh   mediaSettingsrH   s                           r7   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$VAUXX[[AU$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   rG   rT   r`   r'   	rootTitler2   contentTypeMETADATA_TYPEmetadataTypemachineIdentifierr   sectionByIDr   r   r   r   r   r   r   r   r   sync)r5   r   r   r   r   r   r'   r   r   r   myplex	sync_itemr   s                r7   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Gr9   )enr   r   NNN)r   r   r   Nr   NF)NNNFN)__name__
__module____qualname____doc__r8   r   r@   rD   rH   r\   r`   ru   r{   r   r   r   r    r9   r7   r   r      sp    <J0 7 7 7 7K0$$$60 LP6;kZ#Hr9   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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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) Movieu   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.
            commonSenseMedia (:class:`~plexapi.media.CommonSenseMedia`): Common Sense Media object.
            contentRating (str) Content rating (PG-13; NR; TV-G).
            countries (List<:class:`~plexapi.media.Country`>): List of country 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                    t         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      | _        t        j                  t        |j                  j                  dd            | _        |j                  j                  d	      | _        t        j"                  |j                  j                  d
      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                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  dd            | _        t        j                  t        |j                  j                  dd            | _        t        j                  t        |j                  j                  d            | _        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   r8   r   r   r0   r3   r.   r/   r   r   r   r   r1   r   r   r   r   r-   r   r   r   r   r   r   	sourceURIr   r   r   r   r   r   r4   s     r7   r8   zMovie._loadData  s:   d#4&#jj@P0QR#';;??3H#I ![[___=![[___=

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

3@RTX0Y Z**S$++//,*JKJJsDKKOOF$;<	r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Chapterr?   s    r7   chapterszMovie.chapters      ~~djj%--88r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   
Collectionr?   s    r7   collectionszMovie.collections      ~~djj%*:*:;;r9   c                 V    | j                  | j                  t        j                        S r;   findItemr=   r   CommonSenseMediar?   s    r7   commonSenseMediazMovie.commonSenseMedia      }}TZZ)?)?@@r9   c                 V    | j                  | j                  t        j                        S r;   )r<   r=   r   Countryr?   s    r7   	countrieszMovie.countries  r   r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Directorr?   s    r7   	directorszMovie.directors      ~~djj%..99r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Genrer?   s    r7   genreszMovie.genres  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Guidr?   s    r7   guidszMovie.guids      ~~djj%**55r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Labelr?   s    r7   labelszMovie.labels  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Markerr?   s    r7   markerszMovie.markers      ~~djj%,,77r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Mediar?   s    r7   r   zMovie.media  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Producerr?   s    r7   	producerszMovie.producers  r  r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Ratingr?   s    r7   ratingszMovie.ratings  r  r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Roler?   s    r7   roleszMovie.roles  r
  r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Similarr?   s    r7   similarzMovie.similar  r   r9   c                 V    | j                  | j                  t        j                        S r;   r   r=   r   UltraBlurColorsr?   s    r7   ultraBlurColorszMovie.ultraBlurColors      }}TZZ)>)>??r9   c                 V    | j                  | j                  t        j                        S r;   r<   r=   r   Writerr?   s    r7   writerszMovie.writers  r  r9   c                     | j                   S z Alias to self.roles. r"  r?   s    r7   actorszMovie.actors       zzr9   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filerI   s     r7   	locationszMovie.locations  +     '+nn&6?&6d$		&6???   ,,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r)   rN   markers     r7   rP   z)Movie.hasCreditsMarker.<locals>.<genexpr>       G,6;;)+,   anyr  r?   s    r7   hasCreditsMarkerzMovie.hasCreditsMarker       G$,,GGGr9   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rN   r   s     r7   rP   z)Movie.hasVoiceActivity.<locals>.<genexpr>       Bze5))z   rF  r   r?   s    r7   rM  zMovie.hasVoiceActivity       BtzzBBBr9   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rN   r   rJ   s      r7   rP   z-Movie.hasPreviewThumbnails.<locals>.<genexpr>  (     ]*QVQ\Q\4,,Q\,*   ')rQ  r?   s    r7   rX  zMovie.hasPreviewThumbnails       ]$**]]]r9   c                 :    | j                    d| j                   dS ) Returns a filename for use in download. z ())r'   r   r?   s    r7   _prettyfilenamezMovie._prettyfilename  s    **R		{!,,r9   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   rY   r   Reviewr5   r   s     r7   reviewszMovie.reviews  s,    
+,s7CCr9   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   r#   r   search)r5   rj  s     r7   editionszMovie.editions  s5    
 II>>
 ||~$$W$55r9   c                     d}d| j                   i}| j                  j                  ||| j                  j                  j                         | S z* Remove the movie from continue watching. z#/actions/removeFromContinueWatchingr#   )rh   r   r#   rG   rX   ro   r}   r5   r   rh   s      r7   removeFromContinueWatchingz Movie.removeFromContinueWatching  C    3t~~.3vdll6K6K6O6OPr9   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   rd   N.bundler   sha1hashr   r   r   r5   	guid_hashs     r7   metadataDirectoryzMovie.metadataDirectory  G     NN499-	4
#h.1=9QR=/QX@YYZZr9   N)$r   r   r   r   TAGTYPEr   r8   r   r   r   r   r   r   r  r	  r  r  r   r  r  r"  r&  r*  r/  propertyr3  r9  rG  rM  rX  ra  rh  rl  rq  r}  r   r9   r7   r   r   K  s   .^ CDM=4 9 9 < < A A 9 9 : : 7 7 6 6 7 7 8 8 7 7 : : 8 8 6 6 9 9 @ @ 8 8   @ @ H H C C ^ ^-D
6 [ [r9   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ed
        Zed        Zed        Zed        Zed        Ze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.
            commonSenseMedia (:class:`~plexapi.media.CommonSenseMedia`): Common Sense Media object.
            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
                  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            | _        t        j                  t        |j
                  j                  d            | _        | j(                  j+                  dd      | _        |j
                  j                  d      | _        t        j                  t        |j
                  j                  d            | _        |j
                  j                  d      | _        t        j2                  |j
                  j                  d      d      | _        |j
                  j                  d      | _        t        j                  t        |j
                  j                  d            | _        t        j                  t        |j
                  j                  d| j                              | _        |j
                  j                  d      | _        |j
                  j                  d      | _        |j
                  j                  d      | _         |j
                  j                  dd      | _!        t        j                  t        |j
                  j                  dd            | _"        |j
                  j                  d      | _#        |j
                  j                  d      | _$        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   	leafCountnetworkr   r   r   r   seasonCountshowOrderingr   r   subtitleLanguagesubtitleModer   r   r   viewedLeafCountr   N)(r   r8   r   r0   r3   r.   r/   r   r   r  r1   r  r  r  r   r   r   r  r  r  r   replacer   r  r  r-   r   r   r   r  r  r   r   r  r  r   r   r   r  r   r4   s     r7   r8   zShow._loadData^  sj   d##jj@P0QR#';;??3H#I ![[___bA6;jj!I3O7Q349JJ!GM5O1**S$++//,*GH![[___=

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

3@RTX0Y Z$zz#t{{?P/QRJJsDKKOOF$;<	r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r   zShow.collections  r   r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r   zShow.commonSenseMedia  r   r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zShow.genres  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r	  z
Show.guids  r
  r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zShow.labels  rA   r9   c                 >    | j                  | j                  dd      S )Nrk   r   )etag)	listAttrsr=   r?   s    r7   r9  zShow.locations  s    ~~djj&z~BBr9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zShow.ratings  r  r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r"  z
Show.roles  r
  r9   c                 V    | j                  | j                  t        j                        S r;   r$  r?   s    r7   r&  zShow.similar  r   r9   c                 V    | j                  | j                  t        j                        S r;   r(  r?   s    r7   r*  zShow.ultraBlurColors  r+  r9   c              #   >   K   | j                         D ]  }|  y wr;   )seasons)r5   seasons     r7   __iter__zShow.__iter__  s     llnFL %   c                     | j                   S r1  r2  r?   s    r7   r3  zShow.actors  r4  r9   c                 F    t        | j                  | j                  k(        S )z+ Returns True if the show is fully played. boolr  r  r?   s    r7   isPlayedzShow.isPlayed       D((DNN:;;r9   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OnDeckrc  Nr   rU   iterrY   Episoderg  s     r7   onDeckzShow.onDeck  6     
*+D'IJDQQr9   Nc                 *   | j                  | j                   d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.
        r   rd   excludeAllLeavestitle__iexactr  z-Missing argument: title or season is required)_buildQueryKeyr   r   r1   r   r   r   )r5   r'   r  r   r  s        r7   r  zShow.season  s     !!TXXJi"81!MZs%;>>#vU>CC:eS#9%%>>#vU>;;HIIr9   c                     | j                  | j                   dd      } | j                  |t        fd| j                  i|S )zG Returns a list of :class:`~plexapi.video.Season` objects in the show. r   rd   r  container_size)r  r   rY   r   r  r5   kwargsr   s      r7   r  zShow.seasons  sC    !!TXXJi"81!MtsFU4??UfUUr9   c                     | j                  | 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  parentIndexr  z:Missing argument: title or season and episode are required)r  r   r   r  r   )r5   r'   r  r  r   s        r7   r  zShow.episode  sh     !!TXXJj"9:>>#we>DDG$7>>#wF'>RRUVVr9   c                 n    | j                  | j                   d      } | j                  |t        fi |S )zH Returns a list of :class:`~plexapi.video.Episode` objects in the show. r  r  r   rY   r  r  s      r7   episodeszShow.episodes  s5    !!TXXJj"9:tsG6v66r9   c                 (    | j                  |||      S )z/ Alias to :func:`~plexapi.video.Show.episode`. r  )r5   r'   r  r  s       r7   r/   zShow.get  s    ||E6733r9   c                 &    | j                  d      S zB Returns list of watched :class:`~plexapi.video.Episode` objects. r   )viewCount__gtr  r?   s    r7   watchedzShow.watched      }}1}--r9   c                 &    | j                  d      S zD Returns list of unwatched :class:`~plexapi.video.Episode` objects. r   )r,   r  r?   s    r7   r   zShow.unwatched      }}q}))r9   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  rj   rk   joinr   seasonNumberzfilldownload)r5   savepathkeep_original_name
subfoldersr  	filepathsr  	_savepaths           r7   r  zShow.download  sy     	}}GblXW=Q=Q9R9X9XYZ9[8\/]^rzI))))5GR6RRI ' r9   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S ru  rv  zTV Showsr   rd   Nrx  ry  r{  s     r7   r}  zShow.metadataDirectory  sG     NN499-	4
#j09Q<?Yqr]OSZB[[\\r9   NNr   )NFF)!r   r   r   r   r  r  r   r8   r   r   r   r  r	  r  r9  r  r"  r&  r*  r  r  r3  r  r  r  r  r  r  r/   r  r   r  r}  r   r9   r7   r   r     sa   :v CDM"=H < < A A 7 7 6 6 7 7 C C 8 8 6 6 9 9 @ @   < <RJ*V
W$7
4.*  ] ]r9   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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.
    r  r  r  c                    t         j                  | |       t        j                  t        |j
                  j                  d            | _        |j
                  j                  dd      | _        t        j                  t        |j
                  j                  d            | _
        | j                  j                  d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      | _        |j
                  j                  d      | _        |j
                  j                  d      | _        t        j                  t        |j
                  j                  d            | _        |j
                  j                  dd      | _        t        j                  t        |j
                  j                  dd            | _        t        j                  t        |j
                  j                  d            | _        t        j                  t        |j
                  j                  d            | _        y)r   r   r  r   r  r   r  
parentGuidr  	parentKeyparentRatingKey
parentSlugparentStudioparentThemeparentThumbparentTitler   r  r  r   r  r   N)r   r8   r   r0   r3   r.   r/   r   r  r1   r  r   r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r   r4   s     r7   r8   zSeason._loadData:  s   d##jj@P0QR![[___bAZZT[[__W%=>
88##K4C)EF++//,7 ::c4;;??=+IJ5$zz#t{{?P/QR++//,7 KKOON;;;??=9;;??=9;;??=9jj(AB $0BB G!JJsDKKOOND,QR$zz#t{{?P/QRJJsDKKOOF$;<	r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r   zSeason.collectionsQ  r   r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r	  zSeason.guidsU  r
  r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zSeason.labelsY  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zSeason.ratings]  r  r9   c                 V    | j                  | j                  t        j                        S r;   r(  r?   s    r7   r*  zSeason.ultraBlurColorsa  r+  r9   c              #   >   K   | j                         D ]  }|  y wr;   r  )r5   r  s     r7   r  zSeason.__iter__e  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    -   )re   r  	__class__r   r   r  r  r  r5   ps     r7   __repr__zSeason.__repr__i  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  r?   s    r7   r  zSeason.isPlayedr  r  r9   c                     | j                   S )z Returns the season number. r  r?   s    r7   r  zSeason.seasonNumberw  r4  r9   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  rc  Nr  rg  s     r7   r  zSeason.onDeck|  r  r9   Nc                 <   | j                  | 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   r   r1   r   r  r  r   )r5   r'   r  r   r  s        r7   r  zSeason.episode  s     !!TXXJi"89Zs%;>>#we>DD Juc$:%%>>#wDJJe>TTIJJr9   c                 n    | j                  | j                   d      } | j                  |t        fi |S )zJ Returns a list of :class:`~plexapi.video.Episode` objects in the season. r   r  r  s      r7   r  zSeason.episodes  s5    !!TXXJi"89tsG6v66r9   c                 &    | j                  ||      S )z1 Alias to :func:`~plexapi.video.Season.episode`. r  )r5   r'   r  s      r7   r/   z
Season.get  s    ||E7++r9   c                 V    | j                  | j                  | j                              S )z3 Return the season's :class:`~plexapi.video.Show`. r   r  r  r?   s    r7   r  zSeason.show       ~~d11$..ABBr9   c                 &    | j                  d      S r  r  r?   s    r7   r  zSeason.watched  r  r9   c                 &    | j                  d      S r  r  r?   s    r7   r   zSeason.unwatched  r  r9   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  )r5   r  r  r  r  r  s         r7   r  zSeason.download  s?     	}}G)))(4FQ&QQI 'r9   c                 8    | j                    d| j                   S )r^    - )r  r'   r?   s    r7   r`   zSeason._defaultSyncTitle  s    ""#3tzzl33r9   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S r  )r   rz  r  r   r   r{  s     r7   r}  zSeason.metadataDirectory  sG     NN4??3	4
#j09Q<?Yqr]OSZB[[\\r9   r  )NF)r   r   r   r   r  r  r   r8   r   r   r	  r  r  r*  r  r  r  r  r  r  r  r  r/   r  r  r   r  r`   r}  r   r9   r7   r   r     s    > CDM=. < < 6 6 7 7 8 8 @ @
 < <  RK*7
,C.*4 ] ]r9   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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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   r  c                 X	   t         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      | _        t        j                  t        |j                  j                  d	            | _        |j                  j                  d
      | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        t        j.                  |j                  j                  d      d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        t        j                  t
        |j                  j                  d            | _        t        j                  t<        |j                  j                  dd            | _        |j                  j                  d      | _         t        j                  t        |j                  j                  dd            | _!        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grandparentTitler  r   r   r  r  r  
parentYearr   
skipParentr  r   r   r   r   r  r  r  N)&r   r8   r   r   r0   r3   r.   r/   r   r   r   r   r1   r   r  r  r  r  r  r  r  r  r  r-   r   r  r  r  r  r   r  r  r   r   r   
_parentKey_parentRatingKey_parentThumbr4   s     r7   r8   zEpisode._loadData  s   d#4&#jj@P0QR#';;??3H#I ![[___=![[___=

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

3@Q0R S KKOOM:r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r   zEpisode.chapters   r   r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r   zEpisode.collections$  r   r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r   zEpisode.directors(  r  r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r	  zEpisode.guids,  r
  r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zEpisode.labels0  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zEpisode.markers4  r  r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r   zEpisode.media8  rA   r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zEpisode.producers<  r  r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r  zEpisode.ratings@  r  r9   c                 V    | j                  | j                  t        j                        S r;   r   r?   s    r7   r"  zEpisode.rolesD  r
  r9   c                 V    | j                  | j                  t        j                        S r;   r-  r?   s    r7   r/  zEpisode.writersH  r  r9   c                 V    | j                  | j                  t        j                        S r;   r(  r?   s    r7   r*  zEpisode.ultraBlurColorsL  r+  r9   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  r?   s    r7   r  zEpisode.parentKeyP  s5     ????"'(<(<'=>>r9   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   r0   r1   split_seasonr#   r?   s    r7   r  zEpisode.parentRatingKeyY  sz       ,(((!2!2!=!=>R!S::c4#4#4#:#:3#?#BCC<<<<)))r9   c                 x    | j                   r| j                   S | j                  r| j                  j                  S y)z; Returns the parentThumb. Refer to the Episode attributes. N)r  r-  r%   r?   s    r7   r  zEpisode.parentThumbf  s3     $$$<<<<%%%r9   c                     | j                   rH| j                  <| j                  | j                    dd| j                        }| j                  |      S y)zX Returns the :class:`~plexapi.video.Season` object by querying for the show's children. Nr   rd   )r  r  )r  r  r  r   rg  s     r7   r-  zEpisode._seasono  s^     4#3#3#?%%&&'y1!"&& & C
 >>#&&r9   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  )re   r  r  r   r   r  r  seasonEpisoder  s     r7   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 )r_  r
  )r  r1  r'   r?   s    r7   ra  zEpisode._prettyfilename  s+    ''(D,>,>+?s4::,OOr9   c                     | j                   S r1  r2  r?   s    r7   r3  zEpisode.actors  r4  r9   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.
        r6  rI   s     r7   r9  zEpisode.locations  r:  r;  c                     | j                   S )z Returns the episode number. r  r?   s    r7   episodeNumberzEpisode.episodeNumber  r4  r9   c                     t        | j                  t              r| j                  S | j                  r| j                  j                  S y)z& Returns the episode's season number. N)r   r  r1   r-  r  r?   s    r7   r  zEpisode.seasonNumber  s:     d&&,###\\<<%%%r9   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  r6  r?   s    r7   r1  zEpisode.seasonEpisode  sF     3t(()//231S9K9K5L5R5RST5U4VWWr9   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@  rA  s     r7   rP   z.Episode.hasCommercialMarker.<locals>.<genexpr>  s     J\66;;,.\rD  rE  r?   s    r7   hasCommercialMarkerzEpisode.hasCommercialMarker  s     JT\\JJJr9   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@  rA  s     r7   rP   z)Episode.hasIntroMarker.<locals>.<genexpr>  s     Ef6;;')rD  rE  r?   s    r7   hasIntroMarkerzEpisode.hasIntroMarker  s     EEEEr9   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@  rA  s     r7   rP   z+Episode.hasCreditsMarker.<locals>.<genexpr>  rC  rD  rE  r?   s    r7   rG  zEpisode.hasCreditsMarker  rH  r9   c                 :    t        d | j                  D              S )rJ  c              3   4   K   | ]  }|j                     y wr;   rL  rN  s     r7   rP   z+Episode.hasVoiceActivity.<locals>.<genexpr>  rO  rP  rQ  r?   s    r7   rM  zEpisode.hasVoiceActivity  rR  r9   c                 :    t        d | j                  D              S )rT  c              3   V   K   | ]!  }|j                   D ]  }|j                    # y wr;   rV  rY  s      r7   rP   z/Episode.hasPreviewThumbnails.<locals>.<genexpr>  rZ  r[  rQ  r?   s    r7   rX  zEpisode.hasPreviewThumbnails  r\  r9   c                 V    | j                  | j                  | j                              S )z7" Return the episode's :class:`~plexapi.video.Season`. r  r?   s    r7   r  zEpisode.season  r  r9   c                 V    | j                  | j                  | j                              S )z5" Return the episode's :class:`~plexapi.video.Show`. )r   r  r  r?   s    r7   r  zEpisode.show  s"    ~~d11$2E2EFGGr9   c                 l    | j                    d| j                   d| j                   d| j                   S )r^   r
  z - (z) )r  r  r1  r'   r?   s    r7   r`   zEpisode._defaultSyncTitle  s=    ''(D,<,<+=T$BTBTAUUWX\XbXbWcddr9   c                     d}d| j                   i}| j                  j                  ||| j                  j                  j                         | S rn  ro  rp  s      r7   rq  z"Episode.removeFromContinueWatching  rr  r9   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S r  )r   rz  r  r   r   r{  s     r7   r}  zEpisode.metadataDirectory  sI     NN4#7#78	4
#j09Q<?Yqr]OSZB[[\\r9   N)+r   r   r   r   r  r  r   r8   r   r   r   r   r	  r  r  r   r  r  r"  r/  r*  r  r  r  r-  r  ra  r  r3  r9  r6  r  r1  r>  rB  rG  rM  rX  r  r  r`   rq  r}  r   r9   r7   r  r    so   -\ CDM";H 9 9 < < : : 6 6 7 7 8 8 7 7 : : 8 8 6 6 8 8 @ @   
 
   	 	
P   @ @     X X K K F F H H C C ^ ^CHe ] ]r9   r  c                   X    e Zd ZdZdZdZdZd Ze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                 L   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            | _        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   	extraTyper  r   r   skipDetailssubtypethumbAspectRatior   r   r   N)r   r8   r   r   r-   r.   r/   r   r0   r1   r   rR  r  r   rS  rT  rU  r   r   r4   s     r7   r8   zClip._loadData  sM   d#4&''	(BC

3
(CDC)EFZZT[[__W%=>
%*%5%5KKOO34j&B" ::c4;;??=+IJ{{y1 $0B C**S$++//,*JKJJsDKKOOF$;<	r9   c                 V    | j                  | j                  t        j                        S r;   r  r?   s    r7   r   z
Clip.media  rA   r9   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.
        r6  rI   s     r7   r9  zClip.locations	  r:  r;  c                     | j                   S )r_  r_   r?   s    r7   ra  zClip._prettyfilename  ra   r9   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S rt  ry  r{  s     r7   r}  zClip.metadataDirectory  r~  r9   N)r   r   r   r   r  r  r   r8   r   r   r  r9  ra  r}  r   r9   r7   rO  rO    sb      CDM=  7 7 @ @ [ [r9   rO  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[  r8   _parentr   r    r!   )r5   r6   parentr  s      r7   r8   zExtra._loadData!  sG    eT$T* & 7 7!'!9!9#)#=#= r9   c                 :    | j                    d| j                   dS r^  )r'   rT  r?   s    r7   ra  zExtra._prettyfilename)  s    **R~Q//r9   )r   r   r   r   r8   ra  __classcell__)r  s   @r7   r[  r[    s    F>0r9   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   r8   r
   r4   s     r7   r8   zMovieSession._loadData5       d#dD)r9   Nr   r   r   r   _SESSIONTYPEr8   r   r9   r7   rd  rd  .       L*r9   rd  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  r8   r
   r4   s     r7   r8   zEpisodeSession._loadDataB  "    $%dD)r9   Nrg  r   r9   r7   rk  rk  ;  ri  r9   rk  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]  )rO  r8   r
   r4   s     r7   r8   zClipSession._loadDataO       tT"dD)r9   Nrg  r   r9   r7   ro  ro  H  ri  r9   ro  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   r8   r	   r4   s     r7   r8   zMovieHistory._loadData\  rf  r9   Nr   r   r   r   _HISTORYTYPEr8   r   r9   r7   rs  rs  U  ri  r9   rs  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  r8   r	   r4   s     r7   r8   zEpisodeHistory._loadDatai  rm  r9   Nru  r   r9   r7   rx  rx  b  ri  r9   rx  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]  )rO  r8   r	   r4   s     r7   r8   zClipHistory._loadDatav  rq  r9   Nru  r   r9   r7   r{  r{  o  ri  r9   r{  )%rj   pathlibr   urllib.parser   plexapir   r   plexapi.baser   r   r	   r
   r   plexapi.exceptionsr   plexapi.mixinsr   r   r   r   r   r   r   registerPlexObjectr   r   r   r  rO  r[  rd  rk  ro  rs  rx  r{  r   r9   r7   <module>r     s   	  #   d d ) p p}H2 }H@
 L[	8[L[ L[^ t]	:t] t]n o]	<o] o]d S]	8]S] S]l =[	8Z=[ =[@0D 0  	*; 	* 	* 	*[' 	* 	* 	*+t 	* 	* 	*; 	* 	* 	*[' 	* 	* 	*+t 	* 	*r9   