[media.jellyfin] Playlists support (backend implementation).

This commit is contained in:
Fabio Manganiello 2024-11-08 00:53:15 +01:00
parent 7c7b80c942
commit b967cb1969
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 78 additions and 3 deletions

View file

@ -1,4 +1,4 @@
from typing import Iterable, List, Optional, Type from typing import Collection, Iterable, List, Optional, Type
import requests import requests
from marshmallow import Schema from marshmallow import Schema
@ -12,6 +12,7 @@ from platypush.schemas.media.jellyfin import (
JellyfinEpisodeSchema, JellyfinEpisodeSchema,
JellyfinMovieSchema, JellyfinMovieSchema,
JellyfinPhotoSchema, JellyfinPhotoSchema,
JellyfinPlaylistSchema,
JellyfinTrackSchema, JellyfinTrackSchema,
JellyfinVideoSchema, JellyfinVideoSchema,
) )
@ -46,7 +47,9 @@ class MediaJellyfinPlugin(Plugin):
self._api_key = api_key self._api_key = api_key
self.__user_id = None self.__user_id = None
def _execute(self, method: str, url: str, *args, **kwargs) -> dict: def _execute(
self, method: str, url: str, *args, return_json: bool = True, **kwargs
) -> dict:
url = '/' + url.lstrip('/') url = '/' + url.lstrip('/')
url = self.server + url url = self.server + url
@ -59,7 +62,7 @@ class MediaJellyfinPlugin(Plugin):
rs = getattr(requests, method.lower())(url, *args, **kwargs) rs = getattr(requests, method.lower())(url, *args, **kwargs)
rs.raise_for_status() rs.raise_for_status()
return rs.json() return rs.json() if return_json else {}
@property @property
def _user_id(self) -> str: def _user_id(self) -> str:
@ -165,6 +168,8 @@ class MediaJellyfinPlugin(Plugin):
result = JellyfinEpisodeSchema().dump(result) result = JellyfinEpisodeSchema().dump(result)
elif result['Type'] == 'Audio': elif result['Type'] == 'Audio':
result = JellyfinTrackSchema().dump(result) result = JellyfinTrackSchema().dump(result)
elif result['Type'] == 'Playlist':
result = JellyfinPlaylistSchema().dump(result)
elif result['Type'] == 'MusicArtist': elif result['Type'] == 'MusicArtist':
result = JellyfinArtistSchema().dump(result) result = JellyfinArtistSchema().dump(result)
elif result['Type'] == 'MusicAlbum': elif result['Type'] == 'MusicAlbum':
@ -379,3 +384,58 @@ class MediaJellyfinPlugin(Plugin):
) )
return self._serialize_search_results(results) return self._serialize_search_results(results)
@action
def create_playlist(
self, name: str, public: bool = True, item_ids: Optional[Collection[str]] = None
) -> dict:
"""
Create a new playlist.
:param name: Name of the playlist.
:param public: Whether the playlist should be visible to any logged-in user.
:param item_ids: List of item IDs to add to the playlist.
"""
playlist = self._execute(
'POST',
'/Playlists',
json={
'Name': name,
'UserId': self._user_id,
'IsPublic': public,
'Items': item_ids or [],
},
)
return dict(
JellyfinPlaylistSchema().dump(
{
'Name': name,
'IsPublic': public,
**playlist,
}
)
)
@action
def delete_item(self, item_id: str) -> dict:
"""
Delete an item from the server.
:param item_id: ID of the item to delete.
"""
return self._execute('DELETE', f'/Items/{item_id}', return_json=False)
@action
def add_to_playlist(self, playlist_id: str, item_ids: Collection[str]) -> dict:
"""
Add items to a playlist.
:param playlist_id: ID of the playlist.
:param item_ids: List of item IDs to add to the playlist.
"""
return self._execute(
'POST',
f'/Playlists/{playlist_id}/Items',
params={'ids': ','.join(item_ids)},
)

View file

@ -313,3 +313,18 @@ class JellyfinBookSchema(JellyfinSchema):
] = f'{self._server}/Items/{data["Id"]}/Download?api_key={self._api_key}' ] = f'{self._server}/Items/{data["Id"]}/Download?api_key={self._api_key}'
data['embed_url'] = f'{self._server}/web/#/details?id={data["Id"]}' data['embed_url'] = f'{self._server}/web/#/details?id={data["Id"]}'
return data return data
class JellyfinPlaylistSchema(JellyfinSchema, MediaCollectionSchema):
id = fields.String(attribute='Id')
type = fields.Constant('playlist')
item_type = fields.Constant('playlist')
collection_type = fields.Constant('music')
name = fields.String(attribute='Name')
image = fields.String()
public = fields.Boolean(attribute='IsPublic')
duration = fields.Number(attribute='RunTimeTicks')
n_items = fields.Number(attribute='ChildCount')
genres = fields.List(fields.String, attribute='Genres')
tags = fields.List(fields.String, attribute='Tags')
created_at = DateTime(attribute='DateCreated')