
    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
 d dlmZmZmZ d dlmZmZmZ d dlmZmZ d d	lmZ e
j0                   G d
 deee             Zy)    N)groupby)Path)
quote_plusunquote)mediautils)PlayablePlexPartialObjectcached_data_property)
BadRequestNotFoundUnsupported)LibrarySectionMusicSection)PlaylistMixinsc                      e Zd ZdZd ZdZd Ze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ed        Zd Zed        Zd Zd Zed        Zd Zd Zd Zd Zd&dZd'dZd Z d Z!e"d        Z#e"d(d       Z$e"d         Z%e"	 	 d)d!       Z&d" Z'	 	 d*d#Z(d&d$Z)ed%        Z*y)+Playlista   Represents a single Playlist.

        Attributes:
            TAG (str): 'Playlist'
            TYPE (str): 'playlist'
            addedAt (datetime): Datetime the playlist was added to the server.
            allowSync (bool): True if you allow syncing playlists.
            composite (str): URL to composite image (/playlist/<ratingKey>/composite/<compositeid>)
            content (str): The filter URI string for smart playlists.
            duration (int): Duration of the playlist in milliseconds.
            durationInSeconds (int): Duration of the playlist in seconds.
            fields (List<:class:`~plexapi.media.Field`>): List of field objects.
            guid (str): Plex GUID for the playlist (com.plexapp.agents.none://XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX).
            icon (str): Icon URI string for smart playlists.
            key (str): API URL (/playlist/<ratingkey>).
            leafCount (int): Number of items in the playlist view.
            librarySectionID (int): Library section identifier (radio only)
            librarySectionKey (str): Library section key (radio only)
            librarySectionTitle (str): Library section title (radio only)
            playlistType (str): 'audio', 'video', or 'photo'
            radio (bool): If this playlist represents a radio station
            ratingKey (int): Unique key identifying the playlist.
            smart (bool): True if the playlist is a smart playlist.
            summary (str): Summary of the playlist.
            title (str): Name of the playlist.
            titleSort (str): Title to use when sorting (defaults to title).
            type (str): 'playlist'
            updatedAt (datetime): Datetime the playlist was updated.
    playlistc                    t        j                  | |       t        j                  |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _	        |j                  j                  d      | _
        |j                  j                  d      | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d	d
      j#                  dd
      | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d      | _        t        j                  t        |j                  j                  dd            | _        t        j                  t        |j                  j                  d            | _        t        j                  t        |j                  j                  d            | _        |j                  j                  d      | _        |j                  j                  d      | _        |j                  j                  d| j8                        | _        |j                  j                  d      | _        t        j                  |j                  j                  d            | _        y)z/ Load attribute values from Plex XML response. addedAt	allowSync	compositecontentdurationdurationInSecondsguidiconkey /items	leafCountlibrarySectionIDlibrarySectionKeylibrarySectionTitleplaylistTyperadior   	ratingKeysmartsummarytitle	titleSorttype	updatedAtN) r	   	_loadDatar   
toDatetimeattribgetr   castboolr   r   r   intr   r   r   r   replacer   r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   )selfdatas     =/DATA/.local/lib/python3.12/site-packages/plexapi/playlist.pyr.   zPlaylist._loadData1   sX   4&''	(BCD$++//+*FG5{{y1

3
(CD!&CAT1U!VKKOOF+	KKOOF+	;;??5"-55hCC)EF %

3@R0S T!%1D!E#';;??3H#I  KKOON;ZZdkkoogq&AB
C)EFZZdkkoog&>?
{{y1[[__W-
djjAKKOOF+	))$++//+*FG    c                 V    | j                  | j                  t        j                        S N)	findItems_datar   Fieldr6   s    r8   fieldszPlaylist.fieldsK   s    ~~djj%++66r9   c                 4    t        | j                               S r;   )lenitemsr?   s    r8   __len__zPlaylist.__len__O   s    4::<  r9   c              #   >   K   | j                         D ]  }|  y wr;   rC   )r6   items     r8   __iter__zPlaylist.__iter__R   s     JJLDJ !s   c                 H    t        fd| j                         D              S )Nc              3   P   K   | ]  }|j                   j                   k(    y wr;   r   ).0iothers     r8   	<genexpr>z(Playlist.__contains__.<locals>.<genexpr>W   s     <|!155EII%|s   #&)anyrC   )r6   rN   s    `r8   __contains__zPlaylist.__contains__V   s    <tzz|<<<r9   c                 (    | j                         |   S r;   rF   )r6   r   s     r8   __getitem__zPlaylist.__getitem__Y   s    zz|C  r9   c                     | j                   S )z Alias to self.composite. )r   r?   s    r8   thumbzPlaylist.thumb\   s     ~~r9   c                 f    | j                   ry| j                  ry| j                  ryt        d      )zH Returns the type of metadata in the playlist (movie, track, or photo). movietrackphotozUnexpected playlist type)isVideoisAudioisPhotor   r?   s    r8   metadataTypezPlaylist.metadataTypea   s.     <<\\\\899r9   c                      | j                   dk(  S )z+ Returns True if this is a video playlist. videor%   r?   s    r8   rZ   zPlaylist.isVideom          G++r9   c                      | j                   dk(  S )z, Returns True if this is an audio playlist. audior`   r?   s    r8   r[   zPlaylist.isAudior   ra   r9   c                      | j                   dk(  S )z+ Returns True if this is a photo playlist. rY   r`   r?   s    r8   r\   zPlaylist.isPhotow   ra   r9   c                     | j                         D ])  }|j                  |j                  k(  s|j                  c S  t        d|j                   d      )zF Match an item to a playlist item and return the item playlistItemID. Item with title "" not found in the playlist)rC   r'   playlistItemIDr   r*   )r6   rG   _items      r8   _getPlaylistItemIDzPlaylist._getPlaylistItemID|   sJ    ZZ\E$..0+++ " *4::,6QRSSr9   c                 8    | j                  | j                        S )z Cache for filters. )_parseFiltersr   r?   s    r8   _filterszPlaylist._filters   s     !!$,,//r9   c                     | j                   S )z Returns the search filter dict for smart playlist.
            The filter dict be passed back into :func:`~plexapi.library.LibrarySection.search`
            to get the list of items.
        )rm   r?   s    r8   filterszPlaylist.filters   s    
 }}r9   c                    | j                   st        d      t        j                  dt	        | j
                  xs d            }|r?t        |j                  d            }| j                  j                  j                  |      S | j                         r!| j                         d   j                         S t        d      )z Cache for section. z4Regular playlists are not associated with a library.z/library/sections/(\d+)/allr      r   z'Unable to determine the library section)r(   r   researchr   r   r4   group_serverlibrarysectionByIDrC   sectionr   )r6   match
sectionKeys      r8   _sectionzPlaylist._section   s     zzSTT 		8'$,,BTRT:UVU[[^,J<<''33J?? ::<::<?**,,CDDr9   c                     | j                   S )aI   Returns the :class:`~plexapi.library.LibrarySection` this smart playlist belongs to.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying to get the section for a regular playlist.
                :class:`plexapi.exceptions.Unsupported`: When unable to determine the library section.
        )r{   r?   s    r8   rx   zPlaylist.section   s     }}r9   c                     | j                         D ]1  }|j                  j                         |j                         k(  s/|c S  t        d| d      )a   Returns the item in the playlist that matches the specified title.

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

            Raises:
                :class:`plexapi.exceptions.NotFound`: When the item is not found in the playlist.
        rf   rg   )rC   r*   lowerr   )r6   r*   rG   s      r8   rG   zPlaylist.item   sL     JJLDzz!U[[]2 ! *5'1LMNNr9   c                    | j                   rg S | j                   d}| j                  |      }i }|D ]v  }|j                  s|j                  j	                  d      d   }||vr;	 | j
                  j                         j                  |      j                         ||<   ||   |_        x |S # t        $ r d||<   Y w xY w)z Cache for items. r    /   N)
r&   r   
fetchItems	sourceURIsplitru   myPlexAccountresourceconnectr   )r6   r   rC   _serversrG   serverIDs         r8   _itemszPlaylist._items   s     ::I
&!$ D~~>>//4Q78+2-1\\-G-G-I-R-RS[-\-d-d-f*  (1   $ 2-1*2s   &:B..B?>B?c                     | j                   S )z. Returns a list of all items in the playlist. )r   r?   s    r8   rC   zPlaylist.items   s    {{r9   c                 $    | j                  |      S )z3 Alias to :func:`~plexapi.playlist.Playlist.item`. rG   )r6   r*   s     r8   r1   zPlaylist.get   s    yyr9   c                 ~   | j                   rt        d      |rt        |t        t        f      s|g}t        |d       D ]  \  }}g }|D ]d  }|j                  | j                  k7  r%t        d| j                   d|j                         |j                  t        |j                               f dj                  |      }|j                          d| }d|i}| j                   d	t        j                  |       }| j                   j#                  || j                   j$                  j&                  
        | S )av   Add items to the playlist.

            Parameters:
                items (List): List of :class:`~plexapi.audio.Audio`, :class:`~plexapi.video.Video`,
                    or :class:`~plexapi.photo.Photo` objects to be added to the playlist.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying to add items to a smart playlist.
        z%Cannot add items to a smart playlist.c                     | j                   S r;   )ru   r   s    r8   <lambda>z#Playlist.addItems.<locals>.<lambda>   s    dllr9   rK   z2Can not mix media types when building a playlist: z and ,/library/metadata/urir    method)r(   r   
isinstancelisttupler   listTyper%   appendstrr'   join_uriRootr   r   joinArgsru   query_sessionput)	r6   rC   serverr   
ratingKeysrG   r   argsr   s	            r8   addItemszPlaylist.addItems   s+    ::DEEED%=9GE &e1JKNFFJ==D$5$55$'Y(,(9(9':%&P Q Q!!#dnn"56	  *-J__&''9*FC3<DXXJfU^^D%9$:;CLLs4<<+@+@+D+DE L  r9   c                 2   | j                   rt        d      |rt        |t        t        f      s|g}|D ]_  }| j                  |      }| j                   d| }| j                  j                  || j                  j                  j                         a | S )a   Remove items from the playlist.

            Parameters:
                items (List): List of :class:`~plexapi.audio.Audio`, :class:`~plexapi.video.Video`,
                    or :class:`~plexapi.photo.Photo` objects to be removed from the playlist.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying to remove items from a smart playlist.
                :class:`plexapi.exceptions.NotFound`: When the item does not exist in the playlist.
        z*Cannot remove items from a smart playlist./items/r   )r(   r   r   r   r   rj   r   ru   r   r   delete)r6   rC   rG   rh   r   s        r8   removeItemszPlaylist.removeItems   s     ::IJJED%=9GED!44T:NXXJgn%56CLLs4<<+@+@+G+GH  r9   Nc                 &   | j                   rt        d      | j                  |      }| j                   d| d}|r| j                  |      }|d| z  }| j                  j                  || j                  j                  j                         | S )a   Move an item to a new position in the playlist.

            Parameters:
                items (obj): :class:`~plexapi.audio.Audio`, :class:`~plexapi.video.Video`,
                    or :class:`~plexapi.photo.Photo` objects to be moved in the playlist.
                after (obj): :class:`~plexapi.audio.Audio`, :class:`~plexapi.video.Video`,
                    or :class:`~plexapi.photo.Photo` objects to move the item after in the playlist.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying to move items in a smart playlist.
                :class:`plexapi.exceptions.NotFound`: When the item or item after does not exist in the playlist.
        z&Cannot move items in a smart playlist.r   z/movez?after=r   )r(   r   rj   r   ru   r   r   r   )r6   rG   afterrh   r   afterPlaylistItemIDs         r8   moveItemzPlaylist.moveItem  s     ::EFF006
'.!17"&"9"9%"@W0122C3t||'<'<'@'@Ar9   c                    | j                   st        d      | j                         } |j                  d||j                  ||d|}| j
                  j                          | }d|i}| j                   dt        j                  |       }	| j
                  j                  |	| j
                  j                  j                         | S )aS   Update the filters for a smart playlist.

            Parameters:
                limit (int): Limit the number of items in the playlist.
                sort (str or list, optional): A string of comma separated sort fields
                    or a list of sort fields in the format ``column:dir``.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                filters (dict): A dictionary of advanced filters.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                **kwargs (dict): Additional custom filters to apply to the search results.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When trying update filters for a regular playlist.
        z-Cannot update filters for a regular playlist.sortlibtypelimitro   r   r    r    )r(   r   rx   _buildSearchKeyMETADATA_TYPEru   r   r   r   r   r   r   r   )
r6   r   r   ro   kwargsrx   	searchKeyr   r   r   s
             r8   updateFilterszPlaylist.updateFilters,  s      zzLMM,,.+G++ ^w44E7^V\^	&&())5s|
&!5 673t||'<'<'@'@Ar9   c                 0   t        | j                  t              r| j                  j                  |       | S | j                   t        j                  |       }| j                  j                  || j                  j                  j                         | S )z Actually edit the playlist. r   )r   _editsdictupdater   r   r   ru   r   r   r   )r6   r   r   s      r8   _editzPlaylist._editI  so    dkk4(KKv&K
5>>&1233t||'<'<'@'@Ar9   c                     | j                   j                  | j                  | j                   j                  j                         y)z Delete the playlist. r   N)ru   r   r   r   r   r?   s    r8   r   zPlaylist.deleteS  s-    488DLL,A,A,H,HIr9   c                    |st        d      |rt        |t        t        f      s|g}|d   j                  }g }|D ]@  }|j                  |k7  rt        d      |j                  t        |j                               B dj                  |      }|j                          d| }|||dd}dt        j                  |       }	|j                  |	|j                  j                        d   }
 | ||
|		      S )
z Create a regular playlist. z5Must include items to add when creating new playlist.r   z1Can not mix media types when building a playlist.r   r   r   r,   r*   r(   
/playlistsr   initpath)r   r   r   r   r   r   r   r'   r   r   r   r   r   r   post)clsr   r*   rC   r   r   rG   r   r   r   r7   s              r8   _createzPlaylist._createW  s     TUUED%=9GE8$$
D}}( !TUUc$..12 
 XXj)
"##5j\BHuqI5>>$/01||C(<(<|=a@64#..r9   c                    t        |t              s|j                  j                  |      }|xs |j                  } |j
                  d||||d|}	|j                          |	 }
|
|j                  |dd}dt        j                  |       }|j                  ||j                  j                        d   } | |||      S )	z Create a smart playlist. r   rq   r   r   r   r   r   r   )r   r   rv   rx   r   r   r   CONTENT_TYPEr   r   r   r   r   )r   r   r*   rx   r   r   r   ro   r   r   r   r   r   r7   s                 r8   _createSmartzPlaylist._createSmarto  s     '>2nn,,W5G2W22+G++ PweWPHNP	"#I;/G$8$85STU5>>$/01||C(<(<|=a@64#..r9   c                    t        |t              s|j                  j                  |      }t        |t              st        d      |j                  |d}dt        j                  |       }|j                  ||j                  j                         	 |j                  |j                  |      d   j                  |      j                         S # t        $ r t        d      dw xY w)	z/ Create a playlist from uploading an m3u file. z<Can only create playlists from m3u files in a music library.)	sectionIDpathz/playlists/uploadr   )	sectionIdguid__endswithr   z(Failed to create playlist from m3u file.N)r   r   rv   rx   r   r   r   r   r   r   r   r   	playlists	editTitlereload
IndexError)r   r   r*   rx   m3ufilepathr   r   s          r8   _createFromM3UzPlaylist._createFromM3U  s     '>2nn,,W5G'<0[\\$[[+>!%.."6!78S!5!56	S##gkk+#VWXYccdijqqss 	SGHdR	Ss   <C C)c           	          |
r| j                  ||||
      S |r&|rt        d       | j                  |||||||	fi |S | j                  |||      S )a"	   Create a playlist.

            Parameters:
                server (:class:`~plexapi.server.PlexServer`): Server to create the playlist on.
                title (str): Title of the playlist.
                section (:class:`~plexapi.library.LibrarySection`, str): Smart playlists and m3u import only,
                    the library section to create the playlist in.
                items (List): Regular playlists only, list of :class:`~plexapi.audio.Audio`,
                    :class:`~plexapi.video.Video`, or :class:`~plexapi.photo.Photo` objects to be added to the playlist.
                smart (bool): True to create a smart playlist. Default False.
                limit (int): Smart playlists only, limit the number of items in the playlist.
                libtype (str): Smart playlists only, the specific type of content to filter
                    (movie, show, season, episode, artist, album, track, photoalbum, photo).
                sort (str or list, optional): Smart playlists only, a string of comma separated sort fields
                    or a list of sort fields in the format ``column:dir``.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                filters (dict): Smart playlists only, a dictionary of advanced filters.
                    See :func:`~plexapi.library.LibrarySection.search` for more info.
                m3ufilepath (str): Music playlists only, the full file path to an m3u file to import.
                    Note: This will overwrite any playlist previously created from the same m3u file.
                **kwargs (dict): Smart playlists only, additional custom filters to apply to the
                    search results. See :func:`~plexapi.library.LibrarySection.search` for more info.

            Raises:
                :class:`plexapi.exceptions.BadRequest`: When no items are included to create the playlist.
                :class:`plexapi.exceptions.BadRequest`: When mixing media types in the playlist.
                :class:`plexapi.exceptions.BadRequest`: When attempting to import m3u file into non-music library.
                :class:`plexapi.exceptions.BadRequest`: When failed to import m3u file.

            Returns:
                :class:`~plexapi.playlist.Playlist`: A new instance of the created Playlist.
        z*Cannot create a smart playlist with items.)r   r   r   r   )r   r   r*   rx   rC   r(   r   r   r   ro   r   r   s               r8   createzPlaylist.create  sj    F %%feWkJJ !MNN#3##FE7E7DRYd]cdd;;vue44r9   c                     | j                   j                  |      }| j                  || j                  | j	                               S )z Copy playlist to another user account.

            Parameters:
                user (:class:`~plexapi.myplex.MyPlexUser` or str): `MyPlexUser` object, username,
                    email, or user id of the user to copy the playlist to.
        )r   r*   rC   )ru   
switchUserr   r*   rC   )r6   user
userServers      r8   
copyToUserzPlaylist.copyToUser  s7     \\,,T2
{{*DJJdjjl{SSr9   c	                    | j                   st        d      ddlm}	m}
m} | j                  j                         } |	| j                  d      }|r|n| j                  |_        | j                  |_	        | j                  |_        | j                  |_        | j                  j                  |_        dt        | j                         |_        |
j#                  ||      |_        | j&                  r|j)                  |      |_        nQ| j,                  r|j/                  |      |_        n.| j0                  r|j3                  |      |_        nt5        d      |j7                  |||      S )a   Add the playlist as a sync item for the 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. Used only when playlist contains video.
                photoResolution (str): maximum allowed resolution for synchronized photos, see PHOTO_QUALITY_* values in
                                       the module :mod:`~plexapi.sync`. Used only when playlist contains photos.
                audioBitrate (int): maximum bitrate for synchronized music, better use one of MUSIC_BITRATE_* values
                                    from the module :mod:`~plexapi.sync`. Used only when playlist contains audio.
                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 photo.

            Raises:
                :exc:`~plexapi.exceptions.BadRequest`: When playlist is not allowed to sync.
                :exc:`~plexapi.exceptions.Unsupported`: When playlist content is unsupported.

            Returns:
                :class:`~plexapi.sync.SyncItem`: A new instance of the created sync item.
        z#The playlist is not allowed to syncr   )SyncItemPolicyMediaSettingsNzplaylist:///zUnsupported playlist content)clientclientId)r   r   plexapi.syncr   r   r   ru   r   r*   	rootTitler%   contentTyper]   machineIdentifierr   r   locationr   policyrZ   createVideomediaSettingsr[   createMusicr\   createPhotor   sync)r6   videoQualityphotoResolutionaudioBitrater   r   r   	unwatchedr*   r   r   r   myplex	sync_items                 r8   r   zPlaylist.sync  s#   6 ~~BCC@@++-T\\40	#(%djj	"jj	 $ 1 1	!%!2!2	&*ll&D&D	#+Jtyy,A+BC	!==	:	<<&3&?&?&MI#\\&3&?&?&MI#\\&3&?&?&PI#<=={{9Vh{GGr9   c                 R    | j                   j                  |d| j                        S )z3 Get the Plex Web URL with the correct parameters. r   )baseendpointr   )ru   _buildWebURLr   )r6   r   s     r8   
_getWebURLzPlaylist._getWebURL  s"    ||((dZTXX(VVr9   c                     t        j                  | j                        }t        t	        d      dz  |d   z  |dd  dz        S )zL Returns the Plex Media Server data directory where the metadata is stored. Metadata	Playlistsr   rq   Nz.bundle)r   sha1hashr   r   r   )r6   	guid_hashs     r8   metadataDirectoryzPlaylist.metadataDirectory  sI     NN499-	4
#k1IaL@iPQPRm_T[C\\]]r9   r;   )NNN)NNNN)NNFNNNNN)NNNNNNFN)+__name__
__module____qualname____doc__TAGTYPEr.   r   r@   rD   rH   rQ   rS   propertyrU   r]   rZ   r[   r\   rj   rm   ro   r{   rx   rG   r   rC   r1   r   r   r   r   r   r   classmethodr   r   r   r   r   r   r   r   r   r9   r8   r   r      s   : CDH4 7 7!=!   	: 	: , , , , , ,T 0 0 E E"O  . !F.4:J / /. / /  S S  PTBF)5 )5VT rv$(4HlW ^ ^r9   r   )rr   	itertoolsr   pathlibr   urllib.parser   r   plexapir   r   plexapi.baser	   r
   r   plexapi.exceptionsr   r   r   plexapi.libraryr   r   plexapi.mixinsr   registerPlexObjectr   r   r9   r8   <module>r     sR    	   ,   J J @ @ 8 ) w^xw^ w^r9   