[media.jellyfin] Added more metadata to the returned items.

This commit is contained in:
Fabio Manganiello 2024-10-14 21:44:31 +02:00
parent cad864f220
commit 585c2f733f
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 186 additions and 27 deletions

View file

@ -1,52 +1,72 @@
from marshmallow import fields from marshmallow import fields
from marshmallow.schema import Schema from marshmallow.schema import Schema
from platypush.schemas import DateTime
class MediaCollectionSchema(Schema): class MediaCollectionSchema(Schema):
id = fields.String( id = fields.String(
metadata=dict( metadata={
description='Collection ID', 'description': 'Collection ID',
) }
) )
name = fields.String( name = fields.String(
required=True, required=True,
metadata=dict( metadata={
description='Collection name', 'description': 'Collection name',
) },
) )
type = fields.String( type = fields.String(
metadata=dict( metadata={
description='Collection type (movies, music, series etc.)', 'description': 'Collection type (movies, music, series etc.)',
) }
) )
image = fields.URL( image = fields.URL(
metadata=dict( metadata={
description='Collection image (URL)', 'description': 'Collection image (URL)',
}
) )
path = fields.String(
metadata={
'description': 'Path to collection',
}
)
created_at = DateTime(
metadata={
'description': 'Creation date',
}
) )
class MediaArtistSchema(Schema): class MediaArtistSchema(Schema):
id = fields.String( id = fields.String(
metadata=dict( metadata={
description='Artist ID', 'description': 'Artist ID',
) }
) )
name = fields.String( name = fields.String(
required=True, required=True,
metadata=dict( metadata={
description='Artist name', 'description': 'Artist name',
) },
) )
image = fields.URL( image = fields.URL(
metadata=dict( metadata={
description='Artist main image (URL)', 'description': 'Artist main image (URL)',
}
) )
created_at = DateTime(
metadata={
'description': 'Creation date',
}
) )
@ -56,6 +76,12 @@ class MediaItemSchema(Schema):
url = fields.URL() url = fields.URL()
file = fields.String() file = fields.String()
image = fields.URL() image = fields.URL()
path = fields.String()
created_at = DateTime(
metadata={
'description': 'Creation date',
}
)
class MediaVideoSchema(MediaItemSchema): class MediaVideoSchema(MediaItemSchema):
@ -69,4 +95,3 @@ class MediaMovieSchema(MediaItemSchema):
class MediaEpisodeSchema(MediaItemSchema): class MediaEpisodeSchema(MediaItemSchema):
pass pass

View file

@ -3,6 +3,7 @@ import logging
from marshmallow import Schema, fields, pre_dump, post_dump from marshmallow import Schema, fields, pre_dump, post_dump
from platypush.context import get_plugin from platypush.context import get_plugin
from platypush.schemas import DateTime
from . import MediaArtistSchema, MediaCollectionSchema, MediaVideoSchema from . import MediaArtistSchema, MediaCollectionSchema, MediaVideoSchema
@ -14,6 +15,10 @@ class JellyfinSchema(Schema):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if 'id' in self.fields: if 'id' in self.fields:
self.fields['id'].attribute = 'Id' self.fields['id'].attribute = 'Id'
if 'path' in self.fields:
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: elif 'title' in self.fields:
@ -21,7 +26,7 @@ class JellyfinSchema(Schema):
@post_dump @post_dump
def gen_img_url(self, data: dict, **_) -> dict: def gen_img_url(self, data: dict, **_) -> dict:
if 'image' in self.fields: if 'image' in self.fields and data.get('id') and not data.get('image'):
plugin = get_plugin('media.jellyfin') plugin = get_plugin('media.jellyfin')
assert plugin, 'The media.jellyfin plugin is not configured' assert plugin, 'The media.jellyfin plugin is not configured'
data['image'] = ( data['image'] = (
@ -38,7 +43,7 @@ class JellyfinSchema(Schema):
video_format = None video_format = None
containers_priority = ['mp4', 'mkv', 'm4a', 'mov', 'avi'] containers_priority = ['mp4', 'mkv', 'm4a', 'mov', 'avi']
available_containers = data.get('Container', '').split(',') available_containers = set(data.get('Container', '').split(','))
for container in containers_priority: for container in containers_priority:
if container in available_containers: if container in available_containers:
video_format = container video_format = container
@ -52,7 +57,7 @@ class JellyfinSchema(Schema):
return data return data
video_format = available_containers[0] video_format = list(available_containers)[0]
plugin = get_plugin('media.jellyfin') plugin = get_plugin('media.jellyfin')
assert plugin, 'The media.jellyfin plugin is not configured' assert plugin, 'The media.jellyfin plugin is not configured'
@ -64,9 +69,93 @@ class JellyfinSchema(Schema):
return data return data
@pre_dump
def _gen_audio_url(self, data, **_):
if data.get('MediaType') != 'Audio':
return data
class JellyfinArtistSchema(JellyfinSchema, MediaArtistSchema): plugin = get_plugin('media.jellyfin')
pass assert plugin, 'The media.jellyfin plugin is not configured'
data['url'] = (
f'{plugin.server}/Audio/{data["Id"]}'
f'/stream?Static=true&api_key={plugin._api_key}'
)
return data
@post_dump
def _normalize_duration(self, data: dict, **_) -> dict:
if data.get('duration'):
data['duration'] //= 1e7
return data
class JellyfinArtistSchema(JellyfinSchema, MediaArtistSchema, MediaCollectionSchema):
item_type = fields.Constant('artist')
collection_type = fields.Constant('music')
class JellyfinTrackSchema(JellyfinSchema):
item_type = fields.Constant('track')
id = fields.String(attribute='Id')
url = fields.URL()
duration = fields.Number(attribute='RunTimeTicks')
artist = fields.String()
album = fields.String(attribute='Album')
name = fields.String(attribute='Name')
track_number = fields.Number(attribute='IndexNumber')
disc_number = fields.Number(attribute='ParentIndexNumber')
year = fields.Number(attribute='ProductionYear')
image = fields.String()
created_at = DateTime(attribute='DateCreated')
@pre_dump
def _normalize_artist(self, data: dict, **_) -> dict:
artists = data.get('Artists', [])
if artists:
data['artist'] = ', '.join(artists)
return data
@post_dump
def _normalize_community_rating(self, data: dict, **_) -> dict:
if data.get('community_rating'):
data['community_rating'] *= 10
return data
@post_dump
def _normalize_duration(self, data: dict, **_) -> dict:
if data.get('duration'):
data['duration'] //= 1e7
return data
@post_dump
def _add_title(self, data: dict, **_) -> dict:
if not data.get('title'):
data['title'] = data.get('name')
return data
class JellyfinAlbumSchema(JellyfinSchema, MediaCollectionSchema):
id = fields.String(attribute='Id')
item_type = fields.Constant('album')
collection_type = fields.Constant('music')
name = fields.String(attribute='Name')
artist = fields.Nested(JellyfinArtistSchema, attribute='AlbumArtist')
duration = fields.Number(attribute='RunTimeTicks')
year = fields.Number(attribute='ProductionYear')
@pre_dump
def _expand_artist(self, data: dict, **_) -> dict:
artists = data.get('AlbumArtists', [])
if not artists:
return data
data['AlbumArtist'] = {
'Id': artists[0].get('Id'),
'Name': artists[0].get('Name'),
}
return data
class JellyfinCollectionSchema(JellyfinSchema, MediaCollectionSchema): class JellyfinCollectionSchema(JellyfinSchema, MediaCollectionSchema):
@ -74,11 +163,36 @@ class JellyfinCollectionSchema(JellyfinSchema, MediaCollectionSchema):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['type'].attribute = 'CollectionType' self.fields['type'].attribute = 'CollectionType'
collection_type = fields.String(attribute='CollectionType')
image = fields.String()
created_at = DateTime(attribute='DateCreated')
class JellyfinVideoSchema(JellyfinSchema, MediaVideoSchema): class JellyfinVideoSchema(JellyfinSchema, MediaVideoSchema):
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')
container = fields.String(
attribute='Container',
metadata={
'description': 'Available video containers',
'example': 'mp4',
},
)
critic_rating = fields.Number(attribute='CriticRating') critic_rating = fields.Number(attribute='CriticRating')
created_at = DateTime(attribute='DateCreated')
imdb_url = fields.URL(
attribute='ExternalUrl',
metadata={
'description': 'IMDb URL',
'example': 'https://www.imdb.com/title/tt1234567/',
},
)
overview = fields.String(attribute='Overview')
genres = fields.List(fields.String, attribute='Genres')
tags = fields.List(fields.String, attribute='Tags')
trailer_url = fields.URL(attribute='TrailerUrl')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -97,6 +211,26 @@ class JellyfinVideoSchema(JellyfinSchema, MediaVideoSchema):
data['duration'] //= 1e7 data['duration'] //= 1e7
return data return data
@pre_dump
def _extract_imdb_url(self, data: dict, **_) -> dict:
external_urls = data.get('ExternalUrls', [])
for url in external_urls:
if url.get('Name') == 'IMDb':
data['ExternalUrl'] = url.get('Url')
break
return data
@pre_dump
def _extract_trailer_url(self, data: dict, **_) -> dict:
trailers = data.get('RemoteTrailers', [])
for trailer in trailers:
if trailer.get('Type') == 'Trailer':
data['TrailerUrl'] = trailer.get('Url')
break
return data
class JellyfinMovieSchema(JellyfinVideoSchema): class JellyfinMovieSchema(JellyfinVideoSchema):
pass pass