From aa2e450454ef95df648a2fae27719e4704b52c60 Mon Sep 17 00:00:00 2001 From: Zvonimir Rudinski Date: Wed, 10 Dec 2025 03:45:39 +0100 Subject: [PATCH] add documentation --- discord/rpc.py | 16 ++++++++++ jellyfin/api_client.py | 68 +++++++++++++++++++++++++++++++++++++++++- jellyfin/utils.py | 8 +++++ settings/__init__.py | 3 ++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/discord/rpc.py b/discord/rpc.py index 244874e..ede11e5 100644 --- a/discord/rpc.py +++ b/discord/rpc.py @@ -5,7 +5,14 @@ import logging class DiscordRPC: + """ + Client for interacting with Discord Rich Presence (RPC). + """ + def __init__(self): + """ + Initializes the Discord RPC client and connects to Discord via IPC. + """ self.logger = logging.getLogger('DiscordRPC') self.logger.info("Connecting to Discord RPC...") @@ -14,6 +21,12 @@ class DiscordRPC: self.logger.info("Connected to Discord RPC.") def update(self, payload: DiscordRPCUpdatePayload): + """ + Updates the Discord RPC presence with the provided payload. + + Args: + payload (DiscordRPCUpdatePayload): The payload containing presence information. + """ self.logger.info("Updating Discord RPC presence...") self.rpc.update( activity_type=payload.activity_type, @@ -27,6 +40,9 @@ class DiscordRPC: self.logger.info("Discord RPC presence updated.") def clear(self): + """ + Clears the Discord RPC presence. + """ self.logger.info("Clearing Discord RPC presence...") self.rpc.clear() self.logger.info("Discord RPC presence cleared.") diff --git a/jellyfin/api_client.py b/jellyfin/api_client.py index 1d22ce7..ae6aba7 100644 --- a/jellyfin/api_client.py +++ b/jellyfin/api_client.py @@ -3,13 +3,21 @@ from jellyfin_apiclient_python import JellyfinClient from getmac import get_mac_address from jellyfin.models import JellyfinMediaItem, JellyfinMediaType, JellyfinMusicMediaMetadata, JellyfinMovieMediaMetadata, JellyfinEpisodeMediaMetadata from datetime import datetime +from typing import Optional, Tuple import logging import time import os class JellyfinApiClient: + """ + Client for interacting with the Jellyfin server API. + """ + def __init__(self): + """ + Initializes the Jellyfin API client and authenticates with the server. + """ machine_name = os.uname().nodename unique_id = get_mac_address(hostname="localhost") @@ -26,6 +34,9 @@ class JellyfinApiClient: self.logger.info("Connected to Jellyfin server.") def authenticate(self): + """ + Authenticates with the Jellyfin server. + """ self.logger.info("Authenticating with Jellyfin server...") self.client.auth.connect_to_address(settings.jellyfin_server_url) self.client.auth.login( @@ -37,6 +48,12 @@ class JellyfinApiClient: self.logger.info("Authenticated with Jellyfin server.") def get_current_playback(self) -> JellyfinMediaItem | None: + """ + Fetches the current playback information from the Jellyfin server. + + Returns: + JellyfinMediaItem | None: The current playback media item or None if no active playback is found. + """ if time.time() - self.last_auth_time > settings.jellyfin_auth_timeout: self.authenticate() @@ -60,10 +77,26 @@ class JellyfinApiClient: return None def get_image_url(self, media_id: str) -> str: + """ + Constructs the image URL for a given media item. + + Args: + media_id (str): The ID of the media item. + Returns: + str: The constructed image URL. + """ server_address = settings.jellyfin_server_url.rstrip('/') return f"{server_address}/Items/{media_id}/Images/Primary?maxWidth=300&maxHeight=300" def to_model(self, item: dict) -> JellyfinMediaItem: + """ + Converts a Jellyfin media item dictionary to a JellyfinMediaItem model. + + Args: + item (dict): The Jellyfin media item dictionary. + Returns: + JellyfinMediaItem: The converted JellyfinMediaItem model. + """ media_type = item.get('Type') if media_type == 'Audio': @@ -73,7 +106,16 @@ class JellyfinApiClient: elif media_type == 'Movie': return self.to_movie_model(item) - def get_playback_info(self, media: dict) -> tuple[int, int]: + def get_playback_info( + self, media: dict) -> Tuple[Optional[int], Optional[int]]: + """ + Extracts playback start and end timestamps from a media item. + + Args: + media (dict): The Jellyfin media item dictionary. + Returns: + Tuple[Optional[int], Optional[int]]: A tuple containing the start and end timestamps in seconds, or (None, None) if the media is paused. + """ play_state = media.get('PlayState') is_paused = play_state.get('IsPaused') @@ -92,6 +134,14 @@ class JellyfinApiClient: return (start, end) def to_music_model(self, item: dict) -> JellyfinMediaItem: + """ + Converts a Jellyfin music media item dictionary to a JellyfinMediaItem model. + + Args: + item (dict): The Jellyfin music media item dictionary. + Returns: + JellyfinMediaItem: The converted JellyfinMediaItem model. + """ media_id = item.get('Id') parent_id = item.get('ParentId') premiere_date = item.get('PremiereDate') @@ -115,6 +165,14 @@ class JellyfinApiClient: ) def to_movie_model(self, item: dict) -> JellyfinMediaItem: + """ + Converts a Jellyfin movie media item dictionary to a JellyfinMediaItem model. + + Args: + item (dict): The Jellyfin movie media item dictionary. + Returns: + JellyfinMediaItem: The converted JellyfinMediaItem model. + """ media_id = item.get('Id') premiere_date = item.get('PremiereDate') @@ -134,6 +192,14 @@ class JellyfinApiClient: ) def to_episode_model(self, item: dict) -> JellyfinMediaItem: + """ + Converts a Jellyfin episode media item dictionary to a JellyfinMediaItem model. + + Args: + item (dict): The Jellyfin episode media item dictionary. + Returns: + JellyfinMediaItem: The converted JellyfinMediaItem model. + """ media_id = item.get('Id') parent = self.client.jellyfin.get_item(item.get('ParentId')) parent_id = parent.get('ParentId') diff --git a/jellyfin/utils.py b/jellyfin/utils.py index a6c8bde..2d53d1c 100644 --- a/jellyfin/utils.py +++ b/jellyfin/utils.py @@ -4,6 +4,14 @@ from pypresence.types import ActivityType def to_rpc_payload(media_item: JellyfinMediaItem) -> DiscordRPCUpdatePayload: + """ + Converts a JellyfinMediaItem to a DiscordRPCUpdatePayload. + + Args: + media_item (JellyfinMediaItem): The Jellyfin media item to convert. + Returns: + DiscordRPCUpdatePayload: The converted Discord RPC update payload. + """ if media_item.type == JellyfinMediaType.AUDIO: return DiscordRPCUpdatePayload( id=media_item.id, diff --git a/settings/__init__.py b/settings/__init__.py index 352aa35..34827bd 100644 --- a/settings/__init__.py +++ b/settings/__init__.py @@ -3,6 +3,9 @@ from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): + """ + Application settings loaded from environment variables or a .env file. + """ jellyfin_server_url: str = Field(..., env="JELLYFIN_SERVER_URL") jellyfin_username: str = Field(..., env="JELLYFIN_USERNAME") jellyfin_password: str = Field(..., env="JELLYFIN_PASSWORD")