diff --git a/changelog/0.1.1.md b/changelog/0.1.1.md index 0e8f6bd..be6b8e3 100644 --- a/changelog/0.1.1.md +++ b/changelog/0.1.1.md @@ -3,3 +3,4 @@ - Updated Jellyfin item fetching logic to skip items that are not `Audio`, `Episode`, or `Movie` types, preventing errors when unsupported media types are encountered - Updated Jellyfin image fetching logic to use `ParentId` for episodes and music tracks to ensure correct artwork is displayed in Discord Rich Presence - Added `coloredlogs` dependency for improved logging output +- Added a formatting script (`scripts/format.sh`) that uses `autopep8` to automatically format the codebase for better readability and consistency diff --git a/discord/models.py b/discord/models.py index 2e789dd..ae0eebe 100644 --- a/discord/models.py +++ b/discord/models.py @@ -1,6 +1,7 @@ from pydantic import BaseModel from pypresence.types import ActivityType + class DiscordRPCUpdatePayload(BaseModel): id: str title: str diff --git a/discord/rpc.py b/discord/rpc.py index 65384c8..0bb0d6d 100644 --- a/discord/rpc.py +++ b/discord/rpc.py @@ -3,6 +3,7 @@ from settings import settings from discord.models import DiscordRPCUpdatePayload import logging + class DiscordRPC: def __init__(self): self.logger = logging.getLogger('DiscordRPC') diff --git a/jellyfin/api_client.py b/jellyfin/api_client.py index bd1e5d1..5532182 100644 --- a/jellyfin/api_client.py +++ b/jellyfin/api_client.py @@ -7,6 +7,7 @@ import logging import time import os + class JellyfinApiClient: def __init__(self): machine_name = os.uname().nodename @@ -50,7 +51,8 @@ class JellyfinApiClient: session_id = session.get('Id') current_item = self.client.jellyfin.get_now_playing(session_id) - if current_item and current_item.get('Type') in ['Audio', 'Episode', 'Movie']: + if current_item and current_item.get( + 'Type') in ['Audio', 'Episode', 'Movie']: self.logger.info("Current playback information fetched.") return self.to_model(current_item) @@ -78,7 +80,7 @@ class JellyfinApiClient: total_runtime_seconds = runtime_ticks // 10_000_000 playback_position_ticks = play_state.get('PositionTicks') - playback_position_seconds = playback_position_ticks // 10_000_000 + playback_position_seconds = playback_position_ticks // 10_000_000 start = int(datetime.now().timestamp()) - playback_position_seconds end = start + total_runtime_seconds @@ -89,11 +91,11 @@ class JellyfinApiClient: media_id = item.get('Id') parent_id = item.get('ParentId') premiere_date = item.get('PremiereDate') - premiere_year = datetime.fromisoformat(premiere_date).year if premiere_date else None + premiere_year = datetime.fromisoformat( + premiere_date).year if premiere_date else None (start, end) = self.get_playback_info(item) - return JellyfinMediaItem( id=media_id, name=item.get('Name'), @@ -103,9 +105,8 @@ class JellyfinApiClient: end=end, metadata={ 'artist': item.get('AlbumArtist'), - 'album': f"{item.get('Album')} ({premiere_year})" if premiere_date else item.get('Album') - } - ) + 'album': f"{ + item.get('Album')} ({premiere_year})" if premiere_date else item.get('Album')}) def to_movie_model(self, item: dict) -> JellyfinMediaItem: media_id = item.get('Id') @@ -133,7 +134,7 @@ class JellyfinApiClient: season_number = item.get('ParentIndexNumber') episode_number = item.get('IndexNumber') - subtitle=f"S{season_number:02}E{episode_number:02} of {series_name}" + subtitle = f"S{season_number:02}E{episode_number:02} of {series_name}" (start, end) = self.get_playback_info(item) diff --git a/jellyfin/models.py b/jellyfin/models.py index ea2bf6d..24480a0 100644 --- a/jellyfin/models.py +++ b/jellyfin/models.py @@ -1,11 +1,13 @@ from pydantic import BaseModel from enum import Enum + class JellyfinMediaType(str, Enum): AUDIO = 'Audio' MOVIE = 'Movie' EPISODE = 'Episode' + class JellyfinMediaItem(BaseModel): id: str name: str diff --git a/jellyfin/utils.py b/jellyfin/utils.py index 035a89d..12f11f3 100644 --- a/jellyfin/utils.py +++ b/jellyfin/utils.py @@ -2,18 +2,24 @@ from discord.models import DiscordRPCUpdatePayload from jellyfin.models import JellyfinMediaItem, JellyfinMediaType from pypresence.types import ActivityType + def to_rpc_payload(media_item: JellyfinMediaItem) -> DiscordRPCUpdatePayload: if media_item.type == JellyfinMediaType.AUDIO: return DiscordRPCUpdatePayload( id=media_item.id, - title=f"Listening to {media_item.name}", - subtitle=f"by {media_item.metadata.get('artist', 'Unknown Artist')}", + title=f"Listening to { + media_item.name}", + subtitle=f"by { + media_item.metadata.get( + 'artist', + 'Unknown Artist')}", image_url=media_item.image_url, - details=media_item.metadata.get('album', 'Unknown Album'), + details=media_item.metadata.get( + 'album', + 'Unknown Album'), activity_type=ActivityType.LISTENING, start=media_item.start, - end=media_item.end - ) + end=media_item.end) elif media_item.type == JellyfinMediaType.MOVIE: return DiscordRPCUpdatePayload( id=media_item.id, diff --git a/main.py b/main.py index 6268b3e..689177c 100644 --- a/main.py +++ b/main.py @@ -6,11 +6,14 @@ import coloredlogs import logging import time -coloredlogs.install(level=logging.INFO, fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +coloredlogs.install( + level=logging.INFO, + fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s') discordRPC = DiscordRPC() jellyfinApiClient = JellyfinApiClient() + def main(): while True: try: @@ -27,5 +30,6 @@ def main(): discordRPC.clear() break + if __name__ == "__main__": main() diff --git a/requirements.txt b/requirements.txt index 5c947e1..d609034 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ pypresence==4.6.1 pydantic==2.12.5 pydantic-settings==2.12.0 coloredlogs==15.0.1 +autopep8==2.3.2 diff --git a/scripts/format.sh b/scripts/format.sh new file mode 100755 index 0000000..2d959b3 --- /dev/null +++ b/scripts/format.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +which autopep8 &> /dev/null || { echo "autopep8 not found, please install it."; exit 1; } + +autopep8 --in-place --aggressive --aggressive --recursive --exclude bin,lib,include,venv,.git,__pycache__ . + +echo "Code formatted with autopep8." diff --git a/settings/__init__.py b/settings/__init__.py index 2a50d48..352aa35 100644 --- a/settings/__init__.py +++ b/settings/__init__.py @@ -1,16 +1,20 @@ from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict + class Settings(BaseSettings): jellyfin_server_url: str = Field(..., env="JELLYFIN_SERVER_URL") jellyfin_username: str = Field(..., env="JELLYFIN_USERNAME") jellyfin_password: str = Field(..., env="JELLYFIN_PASSWORD") - jellyfin_auth_timeout: int = Field(10 * 60, env="JELLYFIN_AUTH_TIMEOUT") # default 10 minutes + jellyfin_auth_timeout: int = Field( + 10 * 60, env="JELLYFIN_AUTH_TIMEOUT") # default 10 minutes discord_app_id: str = Field(..., env="DISCORD_APP_ID") poll_interval: int = Field(15, env="POLL_INTERVAL") # default 15 seconds - model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") + model_config = SettingsConfigDict( + env_file=".env", env_file_encoding="utf-8") + settings = Settings()