Compare commits

...

1 Commits

Author SHA1 Message Date
aa2e450454 add documentation 2025-12-10 03:45:39 +01:00
4 changed files with 94 additions and 1 deletions

View File

@@ -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.")

View File

@@ -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')

View File

@@ -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,

View File

@@ -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")