Black/LINT for Jellyfin plugin.

This commit is contained in:
Fabio Manganiello 2023-11-07 00:13:22 +01:00
parent a94ddd3f05
commit e7bd61e0d4
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 85 additions and 61 deletions

View file

@ -4,8 +4,13 @@ import requests
from marshmallow import Schema
from platypush.plugins import Plugin, action
from platypush.schemas.media.jellyfin import JellyfinArtistSchema, \
JellyfinCollectionSchema, JellyfinMovieSchema, JellyfinEpisodeSchema
from platypush.schemas.media.jellyfin import (
JellyfinArtistSchema,
JellyfinCollectionSchema,
JellyfinMovieSchema,
JellyfinVideoSchema,
JellyfinEpisodeSchema,
)
class MediaJellyfinPlugin(Plugin):
@ -20,7 +25,9 @@ class MediaJellyfinPlugin(Plugin):
# Maximum number of results returned per query action
_default_limit = 100
def __init__(self, server: str, api_key: str, username: Optional[str] = None, **kwargs):
def __init__(
self, server: str, api_key: str, username: Optional[str] = None, **kwargs
):
"""
:param server: Jellyfin base server URL (including ``http://`` or ``https://``).
:param api_key: Server API key. You can generate one from
@ -35,16 +42,14 @@ class MediaJellyfinPlugin(Plugin):
self._api_key = api_key
self.__user_id = None
def _execute(
self, method: str, url: str, *args, **kwargs
) -> dict:
def _execute(self, method: str, url: str, *args, **kwargs) -> dict:
url = '/' + url.lstrip('/')
url = self.server + url
kwargs['headers'] = {
**kwargs.get('headers', {}),
'X-Emby-Authorization': 'MediaBrowser Client="Platypush", Device="Platypush", '
f'Token="{self._api_key}"'
f'Token="{self._api_key}"',
}
rs = getattr(requests, method.lower())(url, *args, **kwargs)
@ -58,19 +63,21 @@ class MediaJellyfinPlugin(Plugin):
try:
self.__user_id = self._execute('GET', '/Users/Me')['Id']
except requests.exceptions.HTTPError as e:
assert e.response.status_code == 400, (
f'Could not get the current user: {e}'
)
assert (
e.response.status_code == 400
), f'Could not get the current user: {e}'
self.__user_id = self._execute('GET', '/Users')[0]['Id']
return self.__user_id
def _query(
self, url: str,
self,
url: str,
schema_class: Optional[Type[Schema]] = None,
query: Optional[str] = None,
limit: Optional[int] = _default_limit, offset: int = 0,
limit: Optional[int] = _default_limit,
offset: int = 0,
parent_id: Optional[str] = None,
is_played: Optional[bool] = None,
is_favourite: Optional[bool] = None,
@ -78,7 +85,7 @@ class MediaJellyfinPlugin(Plugin):
genres: Optional[Iterable[str]] = None,
tags: Optional[Iterable[str]] = None,
years: Optional[Iterable[int]] = None,
**kwargs
**kwargs,
) -> Iterable[dict]:
filters = []
if is_played is not None:
@ -107,35 +114,40 @@ class MediaJellyfinPlugin(Plugin):
return results
def _flatten_series_result(
self, search_result: dict
) -> Iterable[dict]:
def _flatten_series_result(self, search_result: dict) -> Iterable[dict]:
episodes = []
show_id = search_result['Id']
seasons = self._execute(
'get', f'/Shows/{show_id}/Seasons',
'get',
f'/Shows/{show_id}/Seasons',
params={
'userId': self._user_id,
}
},
).get('Items', [])
for i, season in enumerate(seasons):
episodes.extend(
JellyfinEpisodeSchema().dump([
{**episode, 'SeasonIndex': i+1}
JellyfinEpisodeSchema().dump(
[
{**episode, 'SeasonIndex': i + 1}
for episode in self._execute(
'get', f'/Shows/{show_id}/Episodes',
'get',
f'/Shows/{show_id}/Episodes',
params={
'userId': self._user_id,
'seasonId': season['Id'],
}
},
).get('Items', [])
], many=True)
],
many=True,
)
)
return episodes
def _serialize_search_results(self, search_results: Iterable[dict]) -> Iterable[dict]:
def _serialize_search_results(
self, search_results: Iterable[dict]
) -> Iterable[dict]:
serialized_results = []
for result in search_results:
if result['Type'] == 'CollectionFolder':
@ -144,9 +156,9 @@ class MediaJellyfinPlugin(Plugin):
elif result['Type'] == 'Movie':
result = JellyfinMovieSchema().dump(result)
result['type'] = 'movie' # type: ignore
elif result['Type'] == 'Movie':
result = JellyfinMovieSchema().dump(result)
result['type'] = 'movie' # type: ignore
elif result['Type'] == 'Video':
result = JellyfinVideoSchema().dump(result)
result['type'] = 'video' # type: ignore
elif result['Type'] == 'Series':
serialized_results += self._flatten_series_result(result)
for r in serialized_results:
@ -185,10 +197,17 @@ class MediaJellyfinPlugin(Plugin):
:return: .. schema:: media.jellyfin.JellyfinArtistSchema(many=True)
"""
return self._query(
'/Artists', schema_class=JellyfinArtistSchema,
limit=limit, offset=offset, is_favourite=is_favourite,
is_played=is_played, is_liked=is_liked, genres=genres,
query=query, tags=tags, years=years
'/Artists',
schema_class=JellyfinArtistSchema,
limit=limit,
offset=offset,
is_favourite=is_favourite,
is_played=is_played,
is_liked=is_liked,
genres=genres,
query=query,
tags=tags,
years=years,
)
@action
@ -202,7 +221,7 @@ class MediaJellyfinPlugin(Plugin):
f'/Users/{self._user_id}/Items',
parent_id=None,
schema_class=JellyfinCollectionSchema,
params=dict(recursive=False),
params={'recursive': False},
)
@action
@ -260,7 +279,8 @@ class MediaJellyfinPlugin(Plugin):
if collection:
collections = self.get_collections().output # type: ignore
matching_collections = [
c for c in collections
c
for c in collections
if c['id'] == collection or c['name'].lower() == collection.lower()
]
@ -272,28 +292,36 @@ class MediaJellyfinPlugin(Plugin):
results = self._query(
f'/Users/{self._user_id}/Items',
limit=limit, offset=offset, is_favourite=is_favourite,
is_played=is_played, is_liked=is_liked, genres=genres,
query=query, tags=tags, years=years, parent_id=parent_id,
limit=limit,
offset=offset,
is_favourite=is_favourite,
is_played=is_played,
is_liked=is_liked,
genres=genres,
query=query,
tags=tags,
years=years,
parent_id=parent_id,
params={
**(
{'sortOrder': 'Descending' if sort_desc else 'Ascending'}
if sort_desc is not None else {}
if sort_desc is not None
else {}
),
**(
{'hasSubtitles': has_subtitles}
if has_subtitles is not None else {}
{'hasSubtitles': has_subtitles} if has_subtitles is not None else {}
),
**(
{'minCriticRating': minimum_critic_rating}
if minimum_critic_rating is not None else {}
if minimum_critic_rating is not None
else {}
),
**(
{'minCommunityRating': minimum_community_rating}
if minimum_community_rating is not None else {}
if minimum_community_rating is not None
else {}
),
}
},
)
return self._serialize_search_results(results)

View file

@ -21,8 +21,8 @@ class JellyfinSchema(Schema):
def gen_img_url(self, data: dict, **_) -> dict:
if 'image' in self.fields:
data['image'] = (
get_plugin('media.jellyfin').server + # type: ignore
f'/Items/{data["id"]}'
get_plugin('media.jellyfin').server
+ f'/Items/{data["id"]}' # type: ignore
'/Images/Primary?fillHeight=333&fillWidth=222&quality=96'
)
@ -44,7 +44,8 @@ class JellyfinSchema(Schema):
if not video_format:
if not available_containers:
warnings.warn(
f'The media ID {data["Id"]} has no available video containers'
f'The media ID {data["Id"]} has no available video containers',
stacklevel=2,
)
return data
@ -53,17 +54,15 @@ class JellyfinSchema(Schema):
plugin = get_plugin('media.jellyfin')
assert plugin, 'The media.jellyfin plugin is not configured'
url = (
data['url'] = (
f'{plugin.server}/Videos/{data["Id"]}'
f'/stream.{video_format}'
f'?Static=true&api_key={plugin._api_key}'
)
data['url'] = data['file'] = url
return data
class JellyfinArtistSchema(JellyfinSchema, MediaArtistSchema):
pass
@ -99,13 +98,10 @@ class JellyfinEpisodeSchema(JellyfinVideoSchema):
episode_index = data.get('IndexNumber')
if episode_index:
season_index = data.get('SeasonIndex', 1)
episode_index = 's{:02d}e{:02d}'.format(
season_index, episode_index
)
episode_index = 's{:02d}e{:02d}'.format(season_index, episode_index)
if episode_index:
prefix += f'{" " if prefix else ""}[{episode_index}] '
data['Name'] = prefix + data.get('Name', '')
return data