Compare commits
1 Commits
main
...
aa2e450454
| Author | SHA1 | Date | |
|---|---|---|---|
|
aa2e450454
|
@@ -5,7 +5,14 @@ import logging
|
|||||||
|
|
||||||
|
|
||||||
class DiscordRPC:
|
class DiscordRPC:
|
||||||
|
"""
|
||||||
|
Client for interacting with Discord Rich Presence (RPC).
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Initializes the Discord RPC client and connects to Discord via IPC.
|
||||||
|
"""
|
||||||
self.logger = logging.getLogger('DiscordRPC')
|
self.logger = logging.getLogger('DiscordRPC')
|
||||||
|
|
||||||
self.logger.info("Connecting to Discord RPC...")
|
self.logger.info("Connecting to Discord RPC...")
|
||||||
@@ -14,6 +21,12 @@ class DiscordRPC:
|
|||||||
self.logger.info("Connected to Discord RPC.")
|
self.logger.info("Connected to Discord RPC.")
|
||||||
|
|
||||||
def update(self, payload: DiscordRPCUpdatePayload):
|
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.logger.info("Updating Discord RPC presence...")
|
||||||
self.rpc.update(
|
self.rpc.update(
|
||||||
activity_type=payload.activity_type,
|
activity_type=payload.activity_type,
|
||||||
@@ -27,6 +40,9 @@ class DiscordRPC:
|
|||||||
self.logger.info("Discord RPC presence updated.")
|
self.logger.info("Discord RPC presence updated.")
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
"""
|
||||||
|
Clears the Discord RPC presence.
|
||||||
|
"""
|
||||||
self.logger.info("Clearing Discord RPC presence...")
|
self.logger.info("Clearing Discord RPC presence...")
|
||||||
self.rpc.clear()
|
self.rpc.clear()
|
||||||
self.logger.info("Discord RPC presence cleared.")
|
self.logger.info("Discord RPC presence cleared.")
|
||||||
|
|||||||
@@ -3,13 +3,21 @@ from jellyfin_apiclient_python import JellyfinClient
|
|||||||
from getmac import get_mac_address
|
from getmac import get_mac_address
|
||||||
from jellyfin.models import JellyfinMediaItem, JellyfinMediaType, JellyfinMusicMediaMetadata, JellyfinMovieMediaMetadata, JellyfinEpisodeMediaMetadata
|
from jellyfin.models import JellyfinMediaItem, JellyfinMediaType, JellyfinMusicMediaMetadata, JellyfinMovieMediaMetadata, JellyfinEpisodeMediaMetadata
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Optional, Tuple
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class JellyfinApiClient:
|
class JellyfinApiClient:
|
||||||
|
"""
|
||||||
|
Client for interacting with the Jellyfin server API.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Initializes the Jellyfin API client and authenticates with the server.
|
||||||
|
"""
|
||||||
machine_name = os.uname().nodename
|
machine_name = os.uname().nodename
|
||||||
unique_id = get_mac_address(hostname="localhost")
|
unique_id = get_mac_address(hostname="localhost")
|
||||||
|
|
||||||
@@ -26,6 +34,9 @@ class JellyfinApiClient:
|
|||||||
self.logger.info("Connected to Jellyfin server.")
|
self.logger.info("Connected to Jellyfin server.")
|
||||||
|
|
||||||
def authenticate(self):
|
def authenticate(self):
|
||||||
|
"""
|
||||||
|
Authenticates with the Jellyfin server.
|
||||||
|
"""
|
||||||
self.logger.info("Authenticating with Jellyfin server...")
|
self.logger.info("Authenticating with Jellyfin server...")
|
||||||
self.client.auth.connect_to_address(settings.jellyfin_server_url)
|
self.client.auth.connect_to_address(settings.jellyfin_server_url)
|
||||||
self.client.auth.login(
|
self.client.auth.login(
|
||||||
@@ -37,6 +48,12 @@ class JellyfinApiClient:
|
|||||||
self.logger.info("Authenticated with Jellyfin server.")
|
self.logger.info("Authenticated with Jellyfin server.")
|
||||||
|
|
||||||
def get_current_playback(self) -> JellyfinMediaItem | None:
|
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:
|
if time.time() - self.last_auth_time > settings.jellyfin_auth_timeout:
|
||||||
self.authenticate()
|
self.authenticate()
|
||||||
|
|
||||||
@@ -60,10 +77,26 @@ class JellyfinApiClient:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def get_image_url(self, media_id: str) -> str:
|
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('/')
|
server_address = settings.jellyfin_server_url.rstrip('/')
|
||||||
return f"{server_address}/Items/{media_id}/Images/Primary?maxWidth=300&maxHeight=300"
|
return f"{server_address}/Items/{media_id}/Images/Primary?maxWidth=300&maxHeight=300"
|
||||||
|
|
||||||
def to_model(self, item: dict) -> JellyfinMediaItem:
|
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')
|
media_type = item.get('Type')
|
||||||
|
|
||||||
if media_type == 'Audio':
|
if media_type == 'Audio':
|
||||||
@@ -73,7 +106,16 @@ class JellyfinApiClient:
|
|||||||
elif media_type == 'Movie':
|
elif media_type == 'Movie':
|
||||||
return self.to_movie_model(item)
|
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')
|
play_state = media.get('PlayState')
|
||||||
is_paused = play_state.get('IsPaused')
|
is_paused = play_state.get('IsPaused')
|
||||||
|
|
||||||
@@ -92,6 +134,14 @@ class JellyfinApiClient:
|
|||||||
return (start, end)
|
return (start, end)
|
||||||
|
|
||||||
def to_music_model(self, item: dict) -> JellyfinMediaItem:
|
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')
|
media_id = item.get('Id')
|
||||||
parent_id = item.get('ParentId')
|
parent_id = item.get('ParentId')
|
||||||
premiere_date = item.get('PremiereDate')
|
premiere_date = item.get('PremiereDate')
|
||||||
@@ -115,6 +165,14 @@ class JellyfinApiClient:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def to_movie_model(self, item: dict) -> JellyfinMediaItem:
|
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')
|
media_id = item.get('Id')
|
||||||
premiere_date = item.get('PremiereDate')
|
premiere_date = item.get('PremiereDate')
|
||||||
|
|
||||||
@@ -134,6 +192,14 @@ class JellyfinApiClient:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def to_episode_model(self, item: dict) -> JellyfinMediaItem:
|
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')
|
media_id = item.get('Id')
|
||||||
parent = self.client.jellyfin.get_item(item.get('ParentId'))
|
parent = self.client.jellyfin.get_item(item.get('ParentId'))
|
||||||
parent_id = parent.get('ParentId')
|
parent_id = parent.get('ParentId')
|
||||||
|
|||||||
@@ -4,6 +4,14 @@ from pypresence.types import ActivityType
|
|||||||
|
|
||||||
|
|
||||||
def to_rpc_payload(media_item: JellyfinMediaItem) -> DiscordRPCUpdatePayload:
|
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:
|
if media_item.type == JellyfinMediaType.AUDIO:
|
||||||
return DiscordRPCUpdatePayload(
|
return DiscordRPCUpdatePayload(
|
||||||
id=media_item.id,
|
id=media_item.id,
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
|
|||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
"""
|
||||||
|
Application settings loaded from environment variables or a .env file.
|
||||||
|
"""
|
||||||
jellyfin_server_url: str = Field(..., env="JELLYFIN_SERVER_URL")
|
jellyfin_server_url: str = Field(..., env="JELLYFIN_SERVER_URL")
|
||||||
jellyfin_username: str = Field(..., env="JELLYFIN_USERNAME")
|
jellyfin_username: str = Field(..., env="JELLYFIN_USERNAME")
|
||||||
jellyfin_password: str = Field(..., env="JELLYFIN_PASSWORD")
|
jellyfin_password: str = Field(..., env="JELLYFIN_PASSWORD")
|
||||||
|
|||||||
Reference in New Issue
Block a user