[media.jellyfin] Added support for photo items.

This commit is contained in:
Fabio Manganiello 2024-10-14 23:00:50 +02:00
parent e30ae16ef7
commit 9716b1da35
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 76 additions and 29 deletions

View file

@ -10,6 +10,7 @@ from platypush.schemas.media.jellyfin import (
JellyfinCollectionSchema, JellyfinCollectionSchema,
JellyfinEpisodeSchema, JellyfinEpisodeSchema,
JellyfinMovieSchema, JellyfinMovieSchema,
JellyfinPhotoSchema,
JellyfinTrackSchema, JellyfinTrackSchema,
JellyfinVideoSchema, JellyfinVideoSchema,
) )
@ -153,29 +154,24 @@ class MediaJellyfinPlugin(Plugin):
for result in search_results: for result in search_results:
if result['Type'] == 'Movie': if result['Type'] == 'Movie':
result = JellyfinMovieSchema().dump(result) result = JellyfinMovieSchema().dump(result)
result['type'] = 'movie' # type: ignore
elif result['Type'] == 'Video': elif result['Type'] == 'Video':
result = JellyfinVideoSchema().dump(result) result = JellyfinVideoSchema().dump(result)
result['type'] = 'video' # type: ignore elif result['Type'] == 'Photo':
result = JellyfinPhotoSchema().dump(result)
elif result['Type'] == 'Episode': elif result['Type'] == 'Episode':
result = JellyfinEpisodeSchema().dump(result) result = JellyfinEpisodeSchema().dump(result)
result['type'] = 'episode' # type: ignore
elif result['Type'] == 'Audio': elif result['Type'] == 'Audio':
result = JellyfinTrackSchema().dump(result) result = JellyfinTrackSchema().dump(result)
result['type'] = 'audio' # type: ignore
elif result['Type'] == 'MusicArtist': elif result['Type'] == 'MusicArtist':
result = JellyfinArtistSchema().dump(result) result = JellyfinArtistSchema().dump(result)
result['type'] = 'artist' # type: ignore
elif result['Type'] == 'MusicAlbum': elif result['Type'] == 'MusicAlbum':
result = JellyfinAlbumSchema().dump(result) result = JellyfinAlbumSchema().dump(result)
result['type'] = 'album' # type: ignore
elif result['Type'] == 'Series': elif result['Type'] == 'Series':
serialized_results += self._flatten_series_result(result) serialized_results += self._flatten_series_result(result)
for r in serialized_results: for r in serialized_results:
r['type'] = 'episode' r['type'] = 'episode'
elif result.get('IsFolder'): elif result.get('IsFolder'):
result = JellyfinCollectionSchema().dump(result) result = JellyfinCollectionSchema().dump(result)
result['type'] = 'collection' # type: ignore
if isinstance(result, dict) and result.get('type'): if isinstance(result, dict) and result.get('type'):
serialized_results.append(result) serialized_results.append(result)

View file

@ -17,27 +17,28 @@ class JellyfinSchema(Schema):
self.fields['id'].attribute = 'Id' self.fields['id'].attribute = 'Id'
if 'path' in self.fields: if 'path' in self.fields:
self.fields['path'].attribute = 'Path' self.fields['path'].attribute = 'Path'
if 'created_at' in self.fields:
self.fields['created_at'].attribute = 'DateCreated'
if 'name' in self.fields: if 'name' in self.fields:
self.fields['name'].attribute = 'Name' self.fields['name'].attribute = 'Name'
elif 'title' in self.fields: if 'title' in self.fields:
self.fields['title'].attribute = 'Name' self.fields['title'].attribute = 'Name'
@post_dump @property
def gen_img_url(self, data: dict, **_) -> dict: def _plugin(self):
if 'image' in self.fields and data.get('id') and not data.get('image'): p = get_plugin('media.jellyfin')
plugin = get_plugin('media.jellyfin') assert p, 'The media.jellyfin plugin is not configured'
assert plugin, 'The media.jellyfin plugin is not configured' return p
data['image'] = (
plugin.server + f'/Items/{data["id"]}' # type: ignore
'/Images/Primary?fillHeight=333&fillWidth=222&quality=96'
)
return data @property
def _server(self):
return self._plugin.server
@property
def _api_key(self):
return self._plugin._api_key # pylint: disable=protected-access
@pre_dump @pre_dump
def _gen_video_url(self, data, **_): def _gen_video_url(self, data, **_):
data = data or {}
if data.get('MediaType') != 'Video': if data.get('MediaType') != 'Video':
return data return data
@ -59,26 +60,34 @@ class JellyfinSchema(Schema):
video_format = list(available_containers)[0] video_format = list(available_containers)[0]
plugin = get_plugin('media.jellyfin')
assert plugin, 'The media.jellyfin plugin is not configured'
data['url'] = ( data['url'] = (
f'{plugin.server}/Videos/{data["Id"]}' f'{self._server}/Videos/{data["Id"]}'
f'/stream.{video_format}' f'/stream.{video_format}'
f'?Static=true&api_key={plugin._api_key}' f'?Static=true&api_key={self._api_key}'
) )
return data return data
@pre_dump @pre_dump
def _gen_audio_url(self, data, **_): def _gen_audio_url(self, data, **_):
data = data or {}
if data.get('MediaType') != 'Audio': if data.get('MediaType') != 'Audio':
return data return data
plugin = get_plugin('media.jellyfin')
assert plugin, 'The media.jellyfin plugin is not configured'
data['url'] = ( data['url'] = (
f'{plugin.server}/Audio/{data["Id"]}' f'{self._server}/Audio/{data["Id"]}'
f'/stream?Static=true&api_key={plugin._api_key}' f'/stream?Static=true&api_key={self._api_key}'
)
return data
@post_dump
def gen_img_url(self, data: dict, **_) -> dict:
data = data or {}
if 'image' in self.fields and data.get('id') and not data.get('image'):
data['image'] = (
self._server + f'/Items/{data["id"]}' # type: ignore
'/Images/Primary?fillHeight=333&fillWidth=222&quality=96'
) )
return data return data
@ -91,11 +100,13 @@ class JellyfinSchema(Schema):
class JellyfinArtistSchema(JellyfinSchema, MediaArtistSchema, MediaCollectionSchema): class JellyfinArtistSchema(JellyfinSchema, MediaArtistSchema, MediaCollectionSchema):
type = fields.Constant('artist')
item_type = fields.Constant('artist') item_type = fields.Constant('artist')
collection_type = fields.Constant('music') collection_type = fields.Constant('music')
class JellyfinTrackSchema(JellyfinSchema): class JellyfinTrackSchema(JellyfinSchema):
type = fields.Constant('audio')
item_type = fields.Constant('track') item_type = fields.Constant('track')
id = fields.String(attribute='Id') id = fields.String(attribute='Id')
url = fields.URL() url = fields.URL()
@ -138,6 +149,7 @@ class JellyfinTrackSchema(JellyfinSchema):
class JellyfinAlbumSchema(JellyfinSchema, MediaCollectionSchema): class JellyfinAlbumSchema(JellyfinSchema, MediaCollectionSchema):
id = fields.String(attribute='Id') id = fields.String(attribute='Id')
type = fields.Constant('album')
item_type = fields.Constant('album') item_type = fields.Constant('album')
collection_type = fields.Constant('music') collection_type = fields.Constant('music')
name = fields.String(attribute='Name') name = fields.String(attribute='Name')
@ -163,12 +175,16 @@ class JellyfinCollectionSchema(JellyfinSchema, MediaCollectionSchema):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['type'].attribute = 'CollectionType' self.fields['type'].attribute = 'CollectionType'
type = fields.Constant('collection')
item_type = fields.Constant('collection')
collection_type = fields.String(attribute='CollectionType') collection_type = fields.String(attribute='CollectionType')
image = fields.String() image = fields.String()
created_at = DateTime(attribute='DateCreated') created_at = DateTime(attribute='DateCreated')
class JellyfinVideoSchema(JellyfinSchema, MediaVideoSchema): class JellyfinVideoSchema(JellyfinSchema, MediaVideoSchema):
type = fields.Constant('video')
item_type = fields.Constant('video')
path = fields.String(attribute='Path') path = fields.String(attribute='Path')
duration = fields.Number(attribute='RunTimeTicks') duration = fields.Number(attribute='RunTimeTicks')
community_rating = fields.Number(attribute='CommunityRating') community_rating = fields.Number(attribute='CommunityRating')
@ -233,10 +249,14 @@ class JellyfinVideoSchema(JellyfinSchema, MediaVideoSchema):
class JellyfinMovieSchema(JellyfinVideoSchema): class JellyfinMovieSchema(JellyfinVideoSchema):
pass type = fields.Constant('movie')
item_type = fields.Constant('movie')
class JellyfinEpisodeSchema(JellyfinVideoSchema): class JellyfinEpisodeSchema(JellyfinVideoSchema):
type = fields.Constant('episode')
item_type = fields.Constant('episode')
@pre_dump @pre_dump
def _normalize_episode_name(self, data: dict, **_) -> dict: def _normalize_episode_name(self, data: dict, **_) -> dict:
prefix = '' prefix = ''
@ -254,3 +274,34 @@ class JellyfinEpisodeSchema(JellyfinVideoSchema):
data['Name'] = prefix + data.get('Name', '') data['Name'] = prefix + data.get('Name', '')
return data return data
class JellyfinPhotoSchema(JellyfinSchema):
id = fields.String(attribute='Id')
name = fields.String(attribute='Name')
url = fields.URL()
type = fields.Constant('photo')
item_type = fields.Constant('photo')
path = fields.String(attribute='Path')
created_at = DateTime(attribute='PremiereDate')
width = fields.Number(attribute='Width')
height = fields.Number(attribute='Height')
camera_make = fields.String(attribute='CameraMake')
camera_model = fields.String(attribute='CameraModel')
software = fields.String(attribute='Software')
exposure_time = fields.Float(attribute='ExposureTime')
focal_length = fields.Float(attribute='FocalLength')
image_orientation = fields.String(attribute='ImageOrientation')
aperture = fields.Float(attribute='Aperture')
iso = fields.Number(attribute='IsoSpeedRating')
@pre_dump
def _gen_photo_url(self, data, **_):
data = data or {}
base_url = f'{self._server}/Items/{data["Id"]}'
data['preview_url'] = (
f'{base_url}/Images/Primary?api_key={self._api_key}'
f'&fillHeight=489&fillWidth=367&quality=96'
)
data['url'] = f'{base_url}/Download?api_key={self._api_key}'
return data