From a3e6436ee14bbd912f99b3d458a93abcf427e64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 19 May 2024 12:06:14 +0300 Subject: [PATCH 1/2] Apply ruff-format to all files --- plextraktsync/cli.py | 39 +++++++++----- plextraktsync/commands/bug_report.py | 18 ++++--- plextraktsync/commands/cache.py | 8 ++- plextraktsync/commands/config.py | 1 + plextraktsync/commands/download.py | 14 ++--- plextraktsync/commands/imdb_import.py | 8 ++- plextraktsync/commands/inspect.py | 16 ++++-- plextraktsync/commands/login.py | 7 +-- plextraktsync/commands/plex_login.py | 30 ++++++++--- plextraktsync/commands/self_update.py | 4 +- plextraktsync/commands/sync.py | 8 ++- plextraktsync/commands/watch.py | 10 ++-- plextraktsync/config/Config.py | 19 +++++-- plextraktsync/config/ServerConfigFactory.py | 9 ++-- plextraktsync/config/SyncConfig.py | 47 ++++++++++------ plextraktsync/decorators/measure_time.py | 1 + plextraktsync/media/Media.py | 28 ++++++---- plextraktsync/media/MediaFactory.py | 21 ++++++-- plextraktsync/plan/Walker.py | 43 +++++++++++---- plextraktsync/plex/PlexApi.py | 54 +++++++++++++------ plextraktsync/plex/PlexIdFactory.py | 5 +- plextraktsync/plex/PlexLibraryItem.py | 8 ++- plextraktsync/plex/PlexPlaylist.py | 16 ++++-- plextraktsync/plex/PlexRatings.py | 4 +- plextraktsync/plex/PlexSectionPager.py | 15 ++++-- plextraktsync/plex/PlexServerConnection.py | 18 +++++-- plextraktsync/pytrakt_extensions.py | 4 +- plextraktsync/queue/BackgroundTask.py | 1 + plextraktsync/queue/Queue.py | 4 +- plextraktsync/queue/TraktMarkWatchedWorker.py | 10 ++-- plextraktsync/rich/RichProgressBar.py | 8 ++- plextraktsync/sync/AddCollectionPlugin.py | 4 +- plextraktsync/sync/ClearCollectedPlugin.py | 12 +++-- plextraktsync/sync/LikedListsPlugin.py | 6 ++- plextraktsync/sync/SyncRatingsPlugin.py | 10 +++- plextraktsync/sync/SyncWatchedPlugin.py | 13 +++-- plextraktsync/sync/TraktListsPlugin.py | 21 +++++--- plextraktsync/sync/WatchListPlugin.py | 41 ++++++++++---- plextraktsync/sync/WatchProgressPlugin.py | 7 ++- .../sync/plugin/SyncPluginManager.py | 9 +++- plextraktsync/trakt/PartialTraktMedia.py | 12 +++-- plextraktsync/trakt/ScrobblerProxy.py | 1 + plextraktsync/trakt/TraktApi.py | 35 +++++++++--- plextraktsync/trakt/TraktItem.py | 6 ++- plextraktsync/trakt/TraktLookup.py | 7 ++- plextraktsync/trakt/TraktUserList.py | 30 +++++++---- plextraktsync/util/Factory.py | 22 ++++---- plextraktsync/util/Rating.py | 10 ++-- plextraktsync/util/Timer.py | 1 + plextraktsync/util/local_url.py | 12 +++-- plextraktsync/watch/ProgressBar.py | 16 ++++-- plextraktsync/watch/WatchStateUpdater.py | 36 ++++++++----- tests/test_tv_lookup.py | 4 +- 53 files changed, 562 insertions(+), 231 deletions(-) diff --git a/plextraktsync/cli.py b/plextraktsync/cli.py index 337850c0e1..1b55eb8bb4 100644 --- a/plextraktsync/cli.py +++ b/plextraktsync/cli.py @@ -25,7 +25,9 @@ def wrap(*args, **kwargs): try: cmd(*args, **kwargs) except EOFError as e: - raise ClickException(f"Program requested terminal, No terminal is connected: {e}") + raise ClickException( + f"Program requested terminal, No terminal is connected: {e}" + ) except ClickException as e: from plextraktsync.factory import logging @@ -48,17 +50,22 @@ def wrap(*args, **kwargs): @click.option("--version", is_flag=True, help="Print version and exit") @click.option("--no-cache", is_flag=True, help="Disable cache for Trakt HTTP requests") @click.option("--no-progressbar", is_flag=True, help="Disable progressbar") -@click.option("--batch-delay", default=5, show_default=True, - help="Time in seconds between each collection batch submit to Trakt") +@click.option( + "--batch-delay", + default=5, + show_default=True, + help="Time in seconds between each collection batch submit to Trakt", +) @click.option("--server", help="Plex Server name from servers.yml", metavar="NAME") @click.pass_context -def cli(ctx, - version: bool, - no_cache: bool, - no_progressbar: bool, - batch_delay: int, - server: str, - ): +def cli( + ctx, + version: bool, + no_cache: bool, + no_progressbar: bool, + batch_delay: int, + server: str, +): """ Plex-Trakt-Sync is a two-way-sync between trakt.tv and Plex Media Server """ @@ -76,7 +83,9 @@ def cli(ctx, if not ctx.invoked_subcommand: logger = factory.logger - logger.warning('plextraktsync without command is deprecated. Executing "plextraktsync sync"') + logger.warning( + 'plextraktsync without command is deprecated. Executing "plextraktsync sync"' + ) sync() @@ -186,7 +195,9 @@ def plex_login(): @click.option( "--sync", "sync_option", - type=click.Choice(["all", "movies", "tv", "shows", "watchlist"], case_sensitive=False), + type=click.Choice( + ["all", "movies", "tv", "shows", "watchlist"], case_sensitive=False + ), default="all", show_default=True, help="Specify what to sync", @@ -331,7 +342,9 @@ def watched_shows(): @command() -@click.option("--urls-expire-after", is_flag=True, help="Print urls_expire_after configuration") +@click.option( + "--urls-expire-after", is_flag=True, help="Print urls_expire_after configuration" +) @click.option("--edit", is_flag=True, help="Open config file in editor") @click.option("--locate", is_flag=True, help="Locate config file in file browser") def config(): diff --git a/plextraktsync/commands/bug_report.py b/plextraktsync/commands/bug_report.py index 1e29c7927e..6efeab53b6 100644 --- a/plextraktsync/commands/bug_report.py +++ b/plextraktsync/commands/bug_report.py @@ -11,12 +11,14 @@ def bug_url(): config = factory.config version = factory.version - q = urlencode({ - 'os': version.py_platform, - 'python': version.py_version, - 'version': version.full_version, - 'config': config.dump(), - }) + q = urlencode( + { + "os": version.py_platform, + "python": version.py_version, + "version": version.full_version, + "config": config.dump(), + } + ) return URL_TEMPLATE.format(q) @@ -24,7 +26,9 @@ def bug_url(): def bug_report(): url = bug_url() - print("Opening bug report URL in browser, if that doesn't work open the link manually:") + print( + "Opening bug report URL in browser, if that doesn't work open the link manually:" + ) print("") print(url) openurl(url) diff --git a/plextraktsync/commands/cache.py b/plextraktsync/commands/cache.py index 803b056fcc..ce6598b15d 100644 --- a/plextraktsync/commands/cache.py +++ b/plextraktsync/commands/cache.py @@ -22,7 +22,9 @@ def get_sorted_cache(session: CachedSession, sorting: str, reverse: bool): yield from sorter(session.cache.responses.values()) -def responses_by_url(session: CachedSession, url: str) -> Generator[CachedRequest, Any, None]: +def responses_by_url( + session: CachedSession, url: str +) -> Generator[CachedRequest, Any, None]: return ( response for response in session.cache.responses.values() if response.url == url ) @@ -73,7 +75,9 @@ def inspect_url(session: CachedSession, url: str): matches = responses_by_url(session, url) for m in matches: content_type = m.headers["Content-Type"] - if content_type.startswith("text/xml") or content_type.startswith("application/xml"): + if content_type.startswith("text/xml") or content_type.startswith( + "application/xml" + ): print(f"") for name, value in m.headers.items(): print(f"") diff --git a/plextraktsync/commands/config.py b/plextraktsync/commands/config.py index 12c59117a3..16c2b6b28b 100644 --- a/plextraktsync/commands/config.py +++ b/plextraktsync/commands/config.py @@ -20,6 +20,7 @@ def config(urls_expire_after: bool, edit: bool, locate: bool): if edit or locate: import click + click.launch(config.config_yml, locate=locate) return diff --git a/plextraktsync/commands/download.py b/plextraktsync/commands/download.py index f9c9359cc7..e27e710c4e 100644 --- a/plextraktsync/commands/download.py +++ b/plextraktsync/commands/download.py @@ -36,12 +36,14 @@ def download_subtitles(plex: PlexApi, pm: PlexLibraryItem, savepath: Path): f" Subtitle {index}: ({sub.language}) {sub.title} (codec: {sub.codec}, selected: {sub.selected}, transient: {sub.transient})" ) - filename = ''.join([ - f"{sub.id}. ", - f"{sub.title}" if sub.title else "", - f"{sub.language}." if sub.language else "", - f"{sub.languageCode}.{sub.codec}" - ]) + filename = "".join( + [ + f"{sub.id}. ", + f"{sub.title}" if sub.title else "", + f"{sub.language}." if sub.language else "", + f"{sub.languageCode}.{sub.codec}", + ] + ) filename = Path(savepath, filename) if filename.exists(): diff --git a/plextraktsync/commands/imdb_import.py b/plextraktsync/commands/imdb_import.py index 0831a2489d..260419279f 100644 --- a/plextraktsync/commands/imdb_import.py +++ b/plextraktsync/commands/imdb_import.py @@ -75,12 +75,16 @@ def imdb_import(input: PathLike, dry_run: bool): print = factory.print for r in read_csv(input): - print(f"Importing [blue]{r.media_type} {r.imdb}[/]: {r.title} ({r.year}), rated at {r.rate_date}") + print( + f"Importing [blue]{r.media_type} {r.imdb}[/]: {r.title} ({r.year}), rated at {r.rate_date}" + ) m = trakt.search_by_id(r.imdb, "imdb", r.media_type) rating = trakt.rating(m) if r.rating == rating: print(f"Rating {rating} already exists") continue - print(f"{'Would rate' if dry_run else 'Rating'} {m} with {r.rating} (was {rating})") + print( + f"{'Would rate' if dry_run else 'Rating'} {m} with {r.rating} (was {rating})" + ) if not dry_run: trakt.rate(m, r.rating, r.rate_date) diff --git a/plextraktsync/commands/inspect.py b/plextraktsync/commands/inspect.py index 112a6b84b6..625260d6ce 100644 --- a/plextraktsync/commands/inspect.py +++ b/plextraktsync/commands/inspect.py @@ -56,11 +56,15 @@ def inspect_media(plex_id: PlexId): print("Subtitles:") for index, subtitle in enumerate(pm.subtitle_streams, start=1): - print(f" Subtitle {index}: ({subtitle.language}) {subtitle.title} (codec: {subtitle.codec}, selected: {subtitle.selected}, transient: {subtitle.transient})") + print( + f" Subtitle {index}: ({subtitle.language}) {subtitle.title} (codec: {subtitle.codec}, selected: {subtitle.selected}, transient: {subtitle.transient})" + ) print("Parts:") for index, part in enumerate(pm.parts, start=1): - print(f" Part {index} (exists: {part.exists}): [link=file://{quote_plus(part.file)}]{escape(part.file)}[/link] {part.size} bytes") + print( + f" Part {index} (exists: {part.exists}): [link=file://{quote_plus(part.file)}]{escape(part.file)}[/link] {part.size} bytes" + ) print("Markers:") for marker in pm.markers: @@ -70,12 +74,16 @@ def inspect_media(plex_id: PlexId): print("Guids:") for guid in pm.guids: - print(f" Guid: {guid.provider_link}, Id: {guid.id}, Provider: '{guid.provider}'") + print( + f" Guid: {guid.provider_link}, Id: {guid.id}, Provider: '{guid.provider}'" + ) print(f"Metadata: {pm.to_json()}") print(f"Played on Plex: {pm.is_watched}") - history = plex.history(media, device=True, account=True) if not pm.is_discover else [] + history = ( + plex.history(media, device=True, account=True) if not pm.is_discover else [] + ) print("Plex play history:") for h in history: d = h.device diff --git a/plextraktsync/commands/login.py b/plextraktsync/commands/login.py index 00bef50c60..b0105744cd 100644 --- a/plextraktsync/commands/login.py +++ b/plextraktsync/commands/login.py @@ -1,6 +1,5 @@ from plextraktsync.commands.plex_login import plex_login_autoconfig -from plextraktsync.commands.trakt_login import (has_trakt_token, - trakt_login_autoconfig) +from plextraktsync.commands.trakt_login import has_trakt_token, trakt_login_autoconfig from plextraktsync.factory import factory from plextraktsync.style import highlight, success @@ -19,7 +18,9 @@ def login(): print(highlight("Checking Plex and Trakt login credentials existence")) print("") print("It will not test if the credentials are valid, only that they are present.") - print('If you need to re-login use "plex-login" or "trakt-login" commands respectively.') + print( + 'If you need to re-login use "plex-login" or "trakt-login" commands respectively.' + ) print("") ensure_login() print(success("Done!")) diff --git a/plextraktsync/commands/plex_login.py b/plextraktsync/commands/plex_login.py index b769eb3cad..20eb0e89cc 100644 --- a/plextraktsync/commands/plex_login.py +++ b/plextraktsync/commands/plex_login.py @@ -55,7 +55,7 @@ def server_urls(server: MyPlexResource): connections = server.preferred_connections( None, locations=server.DEFAULT_LOCATION_ORDER, - schemes=server.DEFAULT_SCHEME_ORDER + schemes=server.DEFAULT_SCHEME_ORDER, ) yield from connections yield local_url() @@ -64,7 +64,9 @@ def server_urls(server: MyPlexResource): def myplex_login(username, password): while True: username = Prompt.ask(PROMPT_PLEX_USERNAME, default=username) - password = Prompt.ask(PROMPT_PLEX_PASSWORD, password=True, default=password, show_default=False) + password = Prompt.ask( + PROMPT_PLEX_PASSWORD, password=True, default=password, show_default=False + ) code = Prompt.ask(PROMPT_PLEX_CODE) try: return MyPlexAccount(username=username, password=password, code=code) @@ -106,7 +108,9 @@ def format_server(s): lines = [] product = f"{s.product}/{s.productVersion}" platform = f"{s.device}: {s.platform}/{s.platformVersion}" - lines.append(f"{s.name}: Last seen: {str(s.lastSeenAt)}, Server: {product} on {platform}") + lines.append( + f"{s.name}: Last seen: {str(s.lastSeenAt)}, Server: {product} on {platform}" + ) c: ResourceConnection for c in s.connections: lines.append(f" {c.uri}") @@ -178,7 +182,14 @@ def choose_server(account: MyPlexAccount) -> tuple[MyPlexResource, PlexServer]: plex = server.connect() return server, plex except NotFound as e: - print(Panel.fit(f"{e}. Try another server", padding=1, title="[b red]ERROR", border_style="red")) + print( + Panel.fit( + f"{e}. Try another server", + padding=1, + title="[b red]ERROR", + border_style="red", + ) + ) def plex_login_autoconfig(): @@ -197,8 +208,15 @@ def login(username: str, password: str): return account = myplex_login(username, password) - print(Panel.fit("Login to MyPlex was successful", title="Plex Login", - title_align="left", padding=1, border_style="bright_blue")) + print( + Panel.fit( + "Login to MyPlex was successful", + title="Plex Login", + title_align="left", + padding=1, + border_style="bright_blue", + ) + ) (server, plex) = choose_server(account) print(success(f"Connection to {plex.friendlyName} established successfully!")) diff --git a/plextraktsync/commands/self_update.py b/plextraktsync/commands/self_update.py index 754cb32da0..77c0b33e25 100644 --- a/plextraktsync/commands/self_update.py +++ b/plextraktsync/commands/self_update.py @@ -45,7 +45,9 @@ def self_update(pr: int): execp(f"pipx uninstall plextraktsync@{pr}") print(f"Updating PlexTraktSync to the pull request #{pr} version using pipx") - execp(f"pipx install --suffix=@{pr} --force git+https://github.com/Taxel/PlexTraktSync@refs/pull/{pr}/head") + execp( + f"pipx install --suffix=@{pr} --force git+https://github.com/Taxel/PlexTraktSync@refs/pull/{pr}/head" + ) return print("Updating PlexTraktSync to the latest version using pipx") diff --git a/plextraktsync/commands/sync.py b/plextraktsync/commands/sync.py index eff49ca1c0..ae8aa54985 100644 --- a/plextraktsync/commands/sync.py +++ b/plextraktsync/commands/sync.py @@ -38,10 +38,14 @@ def sync( dry_run=dry_run, ) if server: - logger.warning('"plextraktsync sync --server=" is deprecated use "plextraktsync --server= sync"') + logger.warning( + '"plextraktsync sync --server=" is deprecated use "plextraktsync --server= sync"' + ) config.update(server=server) if no_progress_bar: - logger.warning('"plextraktsync sync --no-progress-bar" is deprecated use "plextraktsync --no-progressbar sync"') + logger.warning( + '"plextraktsync sync --no-progress-bar" is deprecated use "plextraktsync --no-progressbar sync"' + ) config.update(progress=False) if batch_delay: logger.warning( diff --git a/plextraktsync/commands/watch.py b/plextraktsync/commands/watch.py index b666b1c1ee..d7d5309221 100644 --- a/plextraktsync/commands/watch.py +++ b/plextraktsync/commands/watch.py @@ -1,9 +1,13 @@ from __future__ import annotations from plextraktsync.factory import factory -from plextraktsync.watch.events import (ActivityNotification, Error, - PlaySessionStateNotification, - ServerStarted, TimelineEntry) +from plextraktsync.watch.events import ( + ActivityNotification, + Error, + PlaySessionStateNotification, + ServerStarted, + TimelineEntry, +) def watch(server: str): diff --git a/plextraktsync/config/Config.py b/plextraktsync/config/Config.py index b14152db8c..c68bea4359 100644 --- a/plextraktsync/config/Config.py +++ b/plextraktsync/config/Config.py @@ -6,8 +6,13 @@ from plextraktsync.config.ConfigLoader import ConfigLoader from plextraktsync.config.ConfigMergeMixin import ConfigMergeMixin from plextraktsync.mixin.ChangeNotifier import ChangeNotifier -from plextraktsync.path import (cache_dir, config_file, config_yml, - default_config_file, env_file) +from plextraktsync.path import ( + cache_dir, + config_file, + config_yml, + default_config_file, + env_file, +) class Config(ChangeNotifier, ConfigMergeMixin, dict): @@ -63,7 +68,9 @@ def log_file(self): @property def log_debug(self): - return ("log_debug_messages" in self and self["log_debug_messages"]) or self["logging"]["debug"] + return ("log_debug_messages" in self and self["log_debug_messages"]) or self[ + "logging" + ]["debug"] @property def log_append(self): @@ -81,7 +88,11 @@ def cache_path(self): def http_cache(self): from plextraktsync.config.HttpCacheConfig import HttpCacheConfig - cache = self["http_cache"] if "http_cache" in self and self["http_cache"] else {"policy": {}} + cache = ( + self["http_cache"] + if "http_cache" in self and self["http_cache"] + else {"policy": {}} + ) return HttpCacheConfig(**cache) diff --git a/plextraktsync/config/ServerConfigFactory.py b/plextraktsync/config/ServerConfigFactory.py index 9b39fc5bac..0b97fb349b 100644 --- a/plextraktsync/config/ServerConfigFactory.py +++ b/plextraktsync/config/ServerConfigFactory.py @@ -59,9 +59,12 @@ def migrate(self): def save(self): loader = ConfigLoader() - loader.write(self.config_path, { - "servers": self.servers, - }) + loader.write( + self.config_path, + { + "servers": self.servers, + }, + ) def add_server(self, **kwargs): self.load() diff --git a/plextraktsync/config/SyncConfig.py b/plextraktsync/config/SyncConfig.py index 42a80e975c..bcad138c22 100644 --- a/plextraktsync/config/SyncConfig.py +++ b/plextraktsync/config/SyncConfig.py @@ -50,11 +50,16 @@ def sync_ratings(self): @cached_property def clear_collected(self): - return self.plex_to_trakt["collection"] and self["plex_to_trakt"]["clear_collected"] + return ( + self.plex_to_trakt["collection"] + and self["plex_to_trakt"]["clear_collected"] + ) @cached_property def sync_watched_status(self): - return self.trakt_to_plex["watched_status"] or self.plex_to_trakt["watched_status"] + return ( + self.trakt_to_plex["watched_status"] or self.plex_to_trakt["watched_status"] + ) @cached_property def sync_playback_status(self): @@ -62,11 +67,17 @@ def sync_playback_status(self): @cached_property def update_plex_wl(self): - return self.trakt_to_plex["watchlist"] and not self.trakt_to_plex["watchlist_as_playlist"] + return ( + self.trakt_to_plex["watchlist"] + and not self.trakt_to_plex["watchlist_as_playlist"] + ) @cached_property def update_plex_wl_as_pl(self): - return self.trakt_to_plex["watchlist"] and self.trakt_to_plex["watchlist_as_playlist"] + return ( + self.trakt_to_plex["watchlist"] + and self.trakt_to_plex["watchlist_as_playlist"] + ) @cached_property def update_trakt_wl(self): @@ -82,18 +93,22 @@ def sync_liked_lists(self): @cached_property def sync_watchlists(self): - return any([ - self.plex_to_trakt["watchlist"], - self.trakt_to_plex["watchlist"], - ]) + return any( + [ + self.plex_to_trakt["watchlist"], + self.trakt_to_plex["watchlist"], + ] + ) @cached_property def need_library_walk(self): - return any([ - self.update_plex_wl_as_pl, - self.sync_watched_status, - self.sync_ratings, - self.plex_to_trakt["collection"], - self.sync_liked_lists, - self.sync_playback_status, - ]) + return any( + [ + self.update_plex_wl_as_pl, + self.sync_watched_status, + self.sync_ratings, + self.plex_to_trakt["collection"], + self.sync_liked_lists, + self.sync_playback_status, + ] + ) diff --git a/plextraktsync/decorators/measure_time.py b/plextraktsync/decorators/measure_time.py index 83ffffa693..8ffcefcfb2 100644 --- a/plextraktsync/decorators/measure_time.py +++ b/plextraktsync/decorators/measure_time.py @@ -19,6 +19,7 @@ def measure_time(message, *args, level=logging.INFO, logger=None, **kwargs): if inspect.ismethod(logger): log = logger else: + def log(*a, **kw): (logger or default_logger).log(level, *a, **kw) diff --git a/plextraktsync/media/Media.py b/plextraktsync/media/Media.py index 748873e322..1b60bb1ce8 100644 --- a/plextraktsync/media/Media.py +++ b/plextraktsync/media/Media.py @@ -26,12 +26,12 @@ class Media(RichMarkup): plex: PlexLibraryItem def __init__( - self, - plex: PlexLibraryItem, - trakt: TraktMedia, - plex_api: PlexApi = None, - trakt_api: TraktApi = None, - mf: MediaFactory = None, + self, + plex: PlexLibraryItem, + trakt: TraktMedia, + plex_api: PlexApi = None, + trakt_api: TraktApi = None, + mf: MediaFactory = None, ): self.plex_api = plex_api self.trakt_api = trakt_api @@ -145,7 +145,8 @@ def is_collected(self): collected = self.trakt_api.collected_shows return collected.is_collected( - self.show_trakt_id, self.season_number, self.episode_number) + self.show_trakt_id, self.season_number, self.episode_number + ) def add_to_collection(self): self.trakt_api.add_to_collection(self.trakt, self.plex) @@ -198,19 +199,26 @@ def watched_before_reset(self): if not self.is_episode: raise RuntimeError("watched_before_reset is valid for episodes only") - return self.show_reset_at and self.plex.seen_date.replace(tzinfo=None) < self.show_reset_at + return ( + self.show_reset_at + and self.plex.seen_date.replace(tzinfo=None) < self.show_reset_at + ) def reset_show(self): """ Mark unwatched all Plex episodes played before the show reset date. """ - self.plex_api.reset_show(show=self.plex.item.show(), reset_date=self.show_reset_at) + self.plex_api.reset_show( + show=self.plex.item.show(), reset_date=self.show_reset_at + ) def mark_watched_trakt(self): if self.is_movie: self.trakt_api.mark_watched(self.trakt, self.plex.seen_date) elif self.is_episode: - self.trakt_api.mark_watched(self.trakt, self.plex.seen_date, self.show_trakt_id) + self.trakt_api.mark_watched( + self.trakt, self.plex.seen_date, self.show_trakt_id + ) else: raise RuntimeError( f"mark_watched_trakt: Unsupported media type: {self.media_type}" diff --git a/plextraktsync/media/MediaFactory.py b/plextraktsync/media/MediaFactory.py index 7c1851488d..bd37b8c67b 100644 --- a/plextraktsync/media/MediaFactory.py +++ b/plextraktsync/media/MediaFactory.py @@ -21,6 +21,7 @@ class MediaFactory: """ Class that is able to resolve Trakt media item from Plex media item and vice versa and return generic Media class """ + logger = logging.getLogger(__name__) def __init__(self, plex: PlexApi, trakt: TraktApi): @@ -66,11 +67,17 @@ def resolve_guid(self, guid: PlexGuid, show: Media = None): else: tm = self.trakt.find_by_guid(guid) except (TraktException, RequestException) as e: - self.logger.warning(f"{guid.title_link}: Skipping {guid}: Trakt errors: {e}", extra={"markup": True}) + self.logger.warning( + f"{guid.title_link}: Skipping {guid}: Trakt errors: {e}", + extra={"markup": True}, + ) return None if tm is None: - self.logger.warning(f"{guid.title_link}: Skipping {guid} not found on Trakt", extra={"markup": True}) + self.logger.warning( + f"{guid.title_link}: Skipping {guid} not found on Trakt", + extra={"markup": True}, + ) return None return self.make_media(guid.pm, tm) @@ -84,11 +91,17 @@ def resolve_trakt(self, tm: TraktItem) -> Media: def make_media(self, plex: PlexLibraryItem, trakt): return Media(plex, trakt, plex_api=self.plex, trakt_api=self.trakt, mf=self) - def _guid_match(self, candidates: list[PlexLibraryItem], tm: TraktItem) -> PlexLibraryItem | None: + def _guid_match( + self, candidates: list[PlexLibraryItem], tm: TraktItem + ) -> PlexLibraryItem | None: if candidates: for pm in candidates: for guid in pm.guids: for provider in ["tmdb", "imdb", "tvdb"]: - if guid.provider == provider and hasattr(tm.item, provider) and guid.id == str(getattr(tm.item, provider)): + if ( + guid.provider == provider + and hasattr(tm.item, provider) + and guid.id == str(getattr(tm.item, provider)) + ): return pm return None diff --git a/plextraktsync/plan/Walker.py b/plextraktsync/plan/Walker.py index a4d7985af4..66b37b2fca 100644 --- a/plextraktsync/plan/Walker.py +++ b/plextraktsync/plan/Walker.py @@ -29,6 +29,7 @@ class Walker(SetWindowTitle): """ Class dealing with finding and walking library, movies/shows, episodes """ + logger = logging.getLogger(__name__) def __init__( @@ -57,10 +58,16 @@ def is_partial(self): def print_plan(self, print): if self.plan.movie_sections: - print(f"Sync Movie sections: {[x.title_link for x in self.plan.movie_sections]}", extra={"markup": True}) + print( + f"Sync Movie sections: {[x.title_link for x in self.plan.movie_sections]}", + extra={"markup": True}, + ) if self.plan.show_sections: - print(f"Sync Show sections: {[x.title_link for x in self.plan.show_sections]}", extra={"markup": True}) + print( + f"Sync Show sections: {[x.title_link for x in self.plan.show_sections]}", + extra={"markup": True}, + ) if self.plan.movies: print(f"Sync Movies: {[x.title for x in self.plan.movies]}") @@ -141,7 +148,9 @@ async def walk_shows(self, shows: set[Media], title="Processing Shows"): async for show in self.progressbar(shows, desc=title): yield show - async def get_plex_episodes(self, episodes: list[Episode]) -> Generator[Media, Any, None]: + async def get_plex_episodes( + self, episodes: list[Episode] + ) -> Generator[Media, Any, None]: it = self.progressbar(episodes, desc="Processing episodes") async for pe in it: guid = PlexGuid(pe.grandparentGuid, "show") @@ -155,9 +164,13 @@ async def get_plex_episodes(self, episodes: list[Episode]) -> Generator[Media, A me.show = show yield me - async def media_from_sections(self, sections: list[PlexLibrarySection]) -> AsyncGenerator[PlexLibraryItem, Any, None]: + async def media_from_sections( + self, sections: list[PlexLibrarySection] + ) -> AsyncGenerator[PlexLibraryItem, Any, None]: for section in sections: - with measure_time(f"{section.title_link} processed", extra={"markup": True}): + with measure_time( + f"{section.title_link} processed", extra={"markup": True} + ): self.set_window_title(f"Processing {section.title}") it = self.progressbar( section.pager(), @@ -166,9 +179,13 @@ async def media_from_sections(self, sections: list[PlexLibrarySection]) -> Async async for m in it: yield m - async def episodes_from_sections(self, sections: list[PlexLibrarySection]) -> Generator[PlexLibraryItem, Any, None]: + async def episodes_from_sections( + self, sections: list[PlexLibrarySection] + ) -> Generator[PlexLibraryItem, Any, None]: for section in sections: - with measure_time(f"{section.title_link} processed", extra={"markup": True}): + with measure_time( + f"{section.title_link} processed", extra={"markup": True} + ): self.set_window_title(f"Processing {section.title}") it = self.progressbar( section.pager("episode"), @@ -177,7 +194,9 @@ async def episodes_from_sections(self, sections: list[PlexLibrarySection]) -> Ge async for m in it: yield m - async def media_from_items(self, libtype: str, items: list) -> AsyncGenerator[PlexLibraryItem, Any, None]: + async def media_from_items( + self, libtype: str, items: list + ) -> AsyncGenerator[PlexLibraryItem, Any, None]: it = self.progressbar(items, desc=f"Processing {libtype}s") async for m in it: yield PlexLibraryItem(m, plex=self.plex) @@ -201,14 +220,18 @@ async def progressbar(self, iterable: AsyncIterable | Iterable, **kwargs): for m in iterable: yield m - async def media_from_traktlist(self, items: TraktWatchList, title="Trakt watchlist") -> Generator[Media, Any, None]: + async def media_from_traktlist( + self, items: TraktWatchList, title="Trakt watchlist" + ) -> Generator[Media, Any, None]: it = self.progressbar(items, desc=f"Processing {title}") async for media in it: tm = TraktItem(media) m = self.mf.resolve_trakt(tm) yield m - async def media_from_plexlist(self, items: PlexWatchList) -> Generator[Media, Any, None]: + async def media_from_plexlist( + self, items: PlexWatchList + ) -> Generator[Media, Any, None]: it = self.progressbar(items, desc="Processing Plex watchlist") async for media in it: pm = PlexLibraryItem(media, plex=self.plex) diff --git a/plextraktsync/plex/PlexApi.py b/plextraktsync/plex/PlexApi.py index 241ca9042c..8aba63219d 100644 --- a/plextraktsync/plex/PlexApi.py +++ b/plextraktsync/plex/PlexApi.py @@ -30,12 +30,13 @@ class PlexApi: """ Plex API class abstracting common data access and dealing with requests cache. """ + logger = logging.getLogger(__name__) def __init__( - self, - server: PlexServer, - config: PlexServerConfig, + self, + server: PlexServer, + config: PlexServerConfig, ): self.server = server self.config = config @@ -44,7 +45,9 @@ def __str__(self): return str(self.server) def plex_base_url(self, section="server"): - return f"https://app.plex.tv/desktop/#!/{section}/{self.server.machineIdentifier}" + return ( + f"https://app.plex.tv/desktop/#!/{section}/{self.server.machineIdentifier}" + ) @property def plex_discover_base_url(self): @@ -88,8 +91,16 @@ def fetch_item(self, key: int | str | PlexId) -> PlexLibraryItem | None: return PlexLibraryItem(media, plex=self) def media_url(self, m: PlexLibraryItem, discover=False): - base_url = self.plex_discover_base_url if m.is_discover or discover else self.plex_base_url("server") - key = f"/library/metadata/{m.item.guid.rsplit('/', 1)[-1]}" if discover else m.item.key + base_url = ( + self.plex_discover_base_url + if m.is_discover or discover + else self.plex_base_url("server") + ) + key = ( + f"/library/metadata/{m.item.guid.rsplit('/', 1)[-1]}" + if discover + else m.item.key + ) return f"{base_url}/details?key={key}" @@ -101,8 +112,8 @@ def download(self, m: SubtitleStream | MediaPart, **kwargs): def search_by_guid(self, guids: dict, libtype: str): r""" - fetchItem(ekey, guid__regex=r"com\.plexapp\.agents\.(imdb|themoviedb)://|tt\d+") - fetchItem(ekey, guid__id__regex=r"(imdb|tmdb|tvdb)://") + fetchItem(ekey, guid__regex=r"com\.plexapp\.agents\.(imdb|themoviedb)://|tt\d+") + fetchItem(ekey, guid__id__regex=r"(imdb|tmdb|tvdb)://") """ from plextraktsync.plex.PlexGuid import PlexGuid @@ -122,7 +133,9 @@ def search_by_guid(self, guids: dict, libtype: str): for m in result: pm = PlexLibraryItem(m, self) # Do proper matching with provider type and provider id - matched = len([[True for g1 in pm.guids if g1 == g2] for g2 in plexguids]) + matched = len( + [[True for g1 in pm.guids if g1 == g2] for g2 in plexguids] + ) if matched: results.append(pm) @@ -149,7 +162,9 @@ def library_sections(self) -> dict[int, PlexLibrarySection]: if enabled_libraries is not None: excluded_libraries = self.config.excluded_libraries or [] else: - excluded_libraries = factory.config["excluded-libraries"] + (self.config.excluded_libraries or []) + excluded_libraries = factory.config["excluded-libraries"] + ( + self.config.excluded_libraries or [] + ) for section in self.server.library.sections(): if enabled_libraries is not None: @@ -221,7 +236,9 @@ def account(self): def try_login(): if plex_owner_token: - plex_owner_account = MyPlexAccount(token=plex_owner_token, session=factory.session) + plex_owner_account = MyPlexAccount( + token=plex_owner_token, session=factory.session + ) return plex_owner_account.switchHomeUser(plex_username) elif plex_account_token: return MyPlexAccount(token=plex_account_token, session=factory.session) @@ -249,7 +266,9 @@ def watchlist(self, libtype=None) -> list[Movie | Show] | None: try: return self.account.watchlist(libtype=libtype, **params) except BadRequest as e: - self.logger.error(f"Error during {self.account.username} watchlist access: {e}") + self.logger.error( + f"Error during {self.account.username} watchlist access: {e}" + ) return None def add_to_watchlist(self, item): @@ -262,7 +281,9 @@ def remove_from_watchlist(self, item): try: self.account.removeFromWatchlist(item) except BadRequest as e: - self.logger.error(f"Error when removing {item.title} from Plex watchlist: {e}") + self.logger.error( + f"Error when removing {item.title} from Plex watchlist: {e}" + ) @retry() def search_online(self, title: str, media_type: str): @@ -286,5 +307,8 @@ def reset_show(self, show: Show, reset_date: datetime): reset_count += 1 else: self.logger.debug( - f"{show.title} {ep.seasonEpisode} watched at {ep.lastViewedAt} after reset date {reset_date}") - self.logger.debug(f"{show.title}: {reset_count} Plex episode(s) marked as unwatched.") + f"{show.title} {ep.seasonEpisode} watched at {ep.lastViewedAt} after reset date {reset_date}" + ) + self.logger.debug( + f"{show.title}: {reset_count} Plex episode(s) marked as unwatched." + ) diff --git a/plextraktsync/plex/PlexIdFactory.py b/plextraktsync/plex/PlexIdFactory.py index 37eabf4a24..8c8585b282 100644 --- a/plextraktsync/plex/PlexIdFactory.py +++ b/plextraktsync/plex/PlexIdFactory.py @@ -50,7 +50,7 @@ def from_url(url: str): if "key" in parsed: key = ",".join(parsed["key"]) if key.startswith("/library/metadata/"): - id = key[len("/library/metadata/"):] + id = key[len("/library/metadata/") :] if fragment.path == "!/provider/tv.plex.provider.discover/details": return PlexId(id, provider=PlexId.METADATA) if fragment.path == "!/provider/tv.plex.provider.vod/details": @@ -70,9 +70,10 @@ def from_trakt_url(cls, url: str): if path.startswith("/movies/"): media_type = "movie" - slug = path[len("/movies/"):] + slug = path[len("/movies/") :] else: from click import ClickException + raise ClickException(f"Unable to create PlexId: {path}") from plextraktsync.factory import factory diff --git a/plextraktsync/plex/PlexLibraryItem.py b/plextraktsync/plex/PlexLibraryItem.py index 3fb6b9dbf3..09cfc4ac49 100644 --- a/plextraktsync/plex/PlexLibraryItem.py +++ b/plextraktsync/plex/PlexLibraryItem.py @@ -330,9 +330,13 @@ def _get_episodes(self): show_id = self.item.parentRatingKey season = self.item.seasonNumber - return self.library.search(libtype="episode", filters={"show.id": show_id, "season.index": season}) + return self.library.search( + libtype="episode", filters={"show.id": show_id, "season.index": season} + ) - return self.library.search(libtype="episode", filters={"show.id": self.item.ratingKey}) + return self.library.search( + libtype="episode", filters={"show.id": self.item.ratingKey} + ) @cached_property def season_number(self): diff --git a/plextraktsync/plex/PlexPlaylist.py b/plextraktsync/plex/PlexPlaylist.py index 4c732d9aab..063200f2d6 100644 --- a/plextraktsync/plex/PlexPlaylist.py +++ b/plextraktsync/plex/PlexPlaylist.py @@ -37,8 +37,10 @@ def playlist(self) -> Playlist | None: playlists = self.server.playlists(title=self.name, title__iexact=self.name) playlist: Playlist = playlists[0] if len(playlists) > 1: - self.logger.warning(f"Found multiple playlists ({len(playlists)}) with same name: '{self.name}', " - f"Using first playlist with id {playlist.ratingKey}") + self.logger.warning( + f"Found multiple playlists ({len(playlists)}) with same name: '{self.name}', " + f"Using first playlist with id {playlist.ratingKey}" + ) self.logger.debug(f"Loaded plex list: '{self.name}'") return playlist except IndexError: @@ -63,7 +65,10 @@ def update(self, items: list[PlexMedia], description=None) -> bool: del self.__dict__["playlist"] del self.__dict__["items"] playlist = self.server.createPlaylist(self.name, items=items) - self.logger.info(f"Created plex playlist {self.title_link} with {len(items)} items", extra={"markup": True}) + self.logger.info( + f"Created plex playlist {self.title_link} with {len(items)} items", + extra={"markup": True}, + ) # Skip if playlist could not be made/retrieved if playlist is None: @@ -72,7 +77,10 @@ def update(self, items: list[PlexMedia], description=None) -> bool: updated = False if description is not None and description != playlist.summary: playlist.editSummary(summary=description) - self.logger.debug(f"Updated {self.title_link} description: '{description}'", extra={"markup": True}) + self.logger.debug( + f"Updated {self.title_link} description: '{description}'", + extra={"markup": True}, + ) updated = True # Skip if nothing to update diff --git a/plextraktsync/plex/PlexRatings.py b/plextraktsync/plex/PlexRatings.py index 70799fe969..f7f1a7860c 100644 --- a/plextraktsync/plex/PlexRatings.py +++ b/plextraktsync/plex/PlexRatings.py @@ -54,5 +54,7 @@ def ratings(section: PlexLibrarySection, media_type: str): ] } - for item in section.search(filters=filters, libtype=libtype, includeGuids=False): + for item in section.search( + filters=filters, libtype=libtype, includeGuids=False + ): yield item.ratingKey, Rating.create(item.userRating, item.lastRatedAt) diff --git a/plextraktsync/plex/PlexSectionPager.py b/plextraktsync/plex/PlexSectionPager.py index fd8c185201..474a379911 100644 --- a/plextraktsync/plex/PlexSectionPager.py +++ b/plextraktsync/plex/PlexSectionPager.py @@ -13,7 +13,9 @@ class PlexSectionPager: - def __init__(self, section: ShowSection | MovieSection, plex: PlexApi, libtype: str = None): + def __init__( + self, section: ShowSection | MovieSection, plex: PlexApi, libtype: str = None + ): self.section = section self.plex = plex self.libtype = libtype if libtype is not None else section.TYPE @@ -23,11 +25,18 @@ def __len__(self): @cached_property def total_size(self): - return self.section.totalViewSize(libtype=self.libtype, includeCollections=False) + return self.section.totalViewSize( + libtype=self.libtype, includeCollections=False + ) @retry() def fetch_items(self, start: int, size: int): - return self.section.search(libtype=self.libtype, container_start=start, container_size=size, maxresults=size) + return self.section.search( + libtype=self.libtype, + container_start=start, + container_size=size, + maxresults=size, + ) def __iter__(self): from plexapi import X_PLEX_CONTAINER_SIZE diff --git a/plextraktsync/plex/PlexServerConnection.py b/plextraktsync/plex/PlexServerConnection.py index f7ff7f9486..7cf36e2c07 100644 --- a/plextraktsync/plex/PlexServerConnection.py +++ b/plextraktsync/plex/PlexServerConnection.py @@ -40,9 +40,13 @@ def connect(self, urls: list[str], token: str): # 2. url without ssl # 3. local url (localhost) for url in urls: - self.logger.info(f"Connecting with url: {url}, timeout {self.timeout} seconds") + self.logger.info( + f"Connecting with url: {url}, timeout {self.timeout} seconds" + ) try: - return PlexServer(baseurl=url, token=token, session=self.session, timeout=self.timeout) + return PlexServer( + baseurl=url, token=token, session=self.session, timeout=self.timeout + ) except SSLError as e: self.logger.error(e) message = str(e.__context__) @@ -58,7 +62,9 @@ def connect(self, urls: list[str], token: str): # ) if "doesn't match '*." in message and ".plex.direct" in url: url = self.extract_plex_direct(url, message) - self.logger.warning(f"Adding rewritten plex.direct url to connect with: {url}") + self.logger.warning( + f"Adding rewritten plex.direct url to connect with: {url}" + ) urls.append(url) continue @@ -69,7 +75,9 @@ def connect(self, urls: list[str], token: str): # 2. if url and url[:5] == "https": url = url.replace("https", "http") - self.logger.warning(f"Adding rewritten http url to connect with: {url}") + self.logger.warning( + f"Adding rewritten http url to connect with: {url}" + ) urls.append(url) continue except Unauthorized as e: @@ -84,7 +92,7 @@ def extract_plex_direct(url: str, message: str): The url must be with .plex.direct domain. """ hash_pos = message.find("*.") + 2 - hash_value = message[hash_pos:hash_pos + 32] + hash_value = message[hash_pos : hash_pos + 32] end_pos = url.find(".plex.direct") return url[: end_pos - 32] + hash_value + url[end_pos:] diff --git a/plextraktsync/pytrakt_extensions.py b/plextraktsync/pytrakt_extensions.py index d531e60afd..b1a7952eda 100644 --- a/plextraktsync/pytrakt_extensions.py +++ b/plextraktsync/pytrakt_extensions.py @@ -135,7 +135,9 @@ def add(self, trakt_id, season, episode): season_prog = {"number": season, "episodes": [episode_prog]} if trakt_id in self.shows: if season in self.shows[trakt_id].seasons: - self.shows[trakt_id].seasons[season].episodes[episode] = EpisodeProgress(**episode_prog) + self.shows[trakt_id].seasons[season].episodes[episode] = ( + EpisodeProgress(**episode_prog) + ) else: self.shows[trakt_id].seasons[season] = SeasonProgress(**season_prog) else: diff --git a/plextraktsync/queue/BackgroundTask.py b/plextraktsync/queue/BackgroundTask.py index fe0919a92b..b7f6455a74 100644 --- a/plextraktsync/queue/BackgroundTask.py +++ b/plextraktsync/queue/BackgroundTask.py @@ -17,6 +17,7 @@ class BackgroundTask: """ Class to read events from queue and invoke them at tasks to flush them at interval set by the timer """ + logger = logging.getLogger(__name__) def __init__(self, timer: Timer = None, *tasks): diff --git a/plextraktsync/queue/Queue.py b/plextraktsync/queue/Queue.py index 1aa342b880..04111d9ba0 100644 --- a/plextraktsync/queue/Queue.py +++ b/plextraktsync/queue/Queue.py @@ -47,7 +47,9 @@ def add_queue(self, queue: str, data: Any): def start_daemon(self, runner): from threading import Thread - daemon = Thread(target=runner, args=(self.queue,), daemon=True, name="BackgroundTask") + daemon = Thread( + target=runner, args=(self.queue,), daemon=True, name="BackgroundTask" + ) daemon.start() return daemon diff --git a/plextraktsync/queue/TraktMarkWatchedWorker.py b/plextraktsync/queue/TraktMarkWatchedWorker.py index 83103092f1..6ddb85fc78 100644 --- a/plextraktsync/queue/TraktMarkWatchedWorker.py +++ b/plextraktsync/queue/TraktMarkWatchedWorker.py @@ -41,9 +41,11 @@ def add_to_history(self, items: dict): def normalize(items: list): result = defaultdict(list) for m in items: - result[m.media_type].append({ - "ids": m.ids["ids"], - "watched_at": m.watched_at, - }) + result[m.media_type].append( + { + "ids": m.ids["ids"], + "watched_at": m.watched_at, + } + ) return result diff --git a/plextraktsync/rich/RichProgressBar.py b/plextraktsync/rich/RichProgressBar.py index 47ebce7297..dd237e45a7 100644 --- a/plextraktsync/rich/RichProgressBar.py +++ b/plextraktsync/rich/RichProgressBar.py @@ -62,8 +62,12 @@ def task_id(self): @cached_property def progress(self): - from rich.progress import (BarColumn, Progress, TimeElapsedColumn, - TimeRemainingColumn) + from rich.progress import ( + BarColumn, + Progress, + TimeElapsedColumn, + TimeRemainingColumn, + ) from tqdm.rich import FractionColumn, RateColumn args = ( diff --git a/plextraktsync/sync/AddCollectionPlugin.py b/plextraktsync/sync/AddCollectionPlugin.py index e49866f93c..d34984d51d 100644 --- a/plextraktsync/sync/AddCollectionPlugin.py +++ b/plextraktsync/sync/AddCollectionPlugin.py @@ -32,7 +32,9 @@ async def sync_collection(self, m: Media, dry_run: bool): if m.is_collected: return - self.logger.info(f"Adding to Trakt collection: {m.title_link}", extra={"markup": True}) + self.logger.info( + f"Adding to Trakt collection: {m.title_link}", extra={"markup": True} + ) if not dry_run: m.add_to_collection() diff --git a/plextraktsync/sync/ClearCollectedPlugin.py b/plextraktsync/sync/ClearCollectedPlugin.py index f49f7f88ef..0e5f53787c 100644 --- a/plextraktsync/sync/ClearCollectedPlugin.py +++ b/plextraktsync/sync/ClearCollectedPlugin.py @@ -39,8 +39,12 @@ def init(self, pm: SyncPluginManager, is_partial: bool): @hookimpl async def fini(self, dry_run: bool): - self.clear_collected(self.trakt.movie_collection, self.movie_trakt_ids, dry_run=dry_run) - self.clear_collected(self.trakt.episodes_collection, self.episode_trakt_ids, dry_run=dry_run) + self.clear_collected( + self.trakt.movie_collection, self.movie_trakt_ids, dry_run=dry_run + ) + self.clear_collected( + self.trakt.episodes_collection, self.episode_trakt_ids, dry_run=dry_run + ) @hookimpl async def walk_movie(self, movie: Media): @@ -50,7 +54,9 @@ async def walk_movie(self, movie: Media): async def walk_episode(self, episode: Media): self.episode_trakt_ids.add(episode.trakt_id) - def clear_collected(self, existing_items: Iterable[TraktMedia], keep_ids: set[int], dry_run): + def clear_collected( + self, existing_items: Iterable[TraktMedia], keep_ids: set[int], dry_run + ): from plextraktsync.trakt.trakt_set import trakt_set existing_ids = trakt_set(existing_items) diff --git a/plextraktsync/sync/LikedListsPlugin.py b/plextraktsync/sync/LikedListsPlugin.py index 6cbd46abb5..d4aec4e4e8 100644 --- a/plextraktsync/sync/LikedListsPlugin.py +++ b/plextraktsync/sync/LikedListsPlugin.py @@ -28,8 +28,10 @@ def factory(cls, sync: Sync): @hookimpl def init(self, sync: Sync, is_partial: bool, dry_run: bool): if is_partial or dry_run: - self.logger.warning("Partial walk, disabling liked lists updating. " - "Liked lists won't update because it needs full library sync.") + self.logger.warning( + "Partial walk, disabling liked lists updating. " + "Liked lists won't update because it needs full library sync." + ) if is_partial: return diff --git a/plextraktsync/sync/SyncRatingsPlugin.py b/plextraktsync/sync/SyncRatingsPlugin.py index c7a93cd55f..db22295349 100644 --- a/plextraktsync/sync/SyncRatingsPlugin.py +++ b/plextraktsync/sync/SyncRatingsPlugin.py @@ -76,11 +76,17 @@ async def sync_ratings(self, m: Media, dry_run: bool): rate = "plex" if rate == "trakt": - self.logger.info(f"Rating {m.title_link} with {m.plex_rating} on Trakt (was {m.trakt_rating})", extra={"markup": True}) + self.logger.info( + f"Rating {m.title_link} with {m.plex_rating} on Trakt (was {m.trakt_rating})", + extra={"markup": True}, + ) if not dry_run: m.trakt_rate() elif rate == "plex": - self.logger.info(f"Rating {m.title_link} with {m.trakt_rating} on Plex (was {m.plex_rating})", extra={"markup": True}) + self.logger.info( + f"Rating {m.title_link} with {m.trakt_rating} on Plex (was {m.plex_rating})", + extra={"markup": True}, + ) if not dry_run: m.plex_rate() diff --git a/plextraktsync/sync/SyncWatchedPlugin.py b/plextraktsync/sync/SyncWatchedPlugin.py index ce4eaf4c50..ab5209b459 100644 --- a/plextraktsync/sync/SyncWatchedPlugin.py +++ b/plextraktsync/sync/SyncWatchedPlugin.py @@ -42,17 +42,24 @@ async def sync_watched(self, m: Media, dry_run: bool): if m.is_episode and m.watched_before_reset: show = m.plex.item.show() - self.logger.info(f"Show '{show.title}' has been reset in trakt at {m.show_reset_at}.") + self.logger.info( + f"Show '{show.title}' has been reset in trakt at {m.show_reset_at}." + ) self.logger.info(f"Marking '{show.title}' as unwatched in Plex.") if not dry_run: m.reset_show() else: - self.logger.info(f"Marking as watched in Trakt: {m.title_link}", extra={"markup": True}) + self.logger.info( + f"Marking as watched in Trakt: {m.title_link}", + extra={"markup": True}, + ) if not dry_run: m.mark_watched_trakt() elif m.watched_on_trakt: if not self.trakt_to_plex: return - self.logger.info(f"Marking as watched in Plex: {m.title_link}", extra={"markup": True}) + self.logger.info( + f"Marking as watched in Plex: {m.title_link}", extra={"markup": True} + ) if not dry_run: m.mark_watched_plex() diff --git a/plextraktsync/sync/TraktListsPlugin.py b/plextraktsync/sync/TraktListsPlugin.py index 66b7c67593..a670ea0e7a 100644 --- a/plextraktsync/sync/TraktListsPlugin.py +++ b/plextraktsync/sync/TraktListsPlugin.py @@ -14,6 +14,7 @@ class TraktListsPlugin: """ Plugin handling syncing of Trakt lists. """ + logger = logging.getLogger(__name__) def __init__(self): @@ -21,12 +22,14 @@ def __init__(self): @staticmethod def enabled(config): - return any([ - # LikedListsPlugin - config.sync_liked_lists, - # WatchListPlugin - config.update_plex_wl_as_pl, - ]) + return any( + [ + # LikedListsPlugin + config.sync_liked_lists, + # WatchListPlugin + config.update_plex_wl_as_pl, + ] + ) @classmethod def factory(cls, sync): @@ -52,8 +55,10 @@ async def fini(self, dry_run: bool): updated = tl.plex_list.update(tl.plex_items_sorted) if not updated: continue - self.logger.info(f"Plex list {tl.title_link} ({len(tl.plex_items)} items) updated", - extra={"markup": True}) + self.logger.info( + f"Plex list {tl.title_link} ({len(tl.plex_items)} items) updated", + extra={"markup": True}, + ) @hookimpl async def walk_movie(self, movie: Media): diff --git a/plextraktsync/sync/WatchListPlugin.py b/plextraktsync/sync/WatchListPlugin.py index cb9621fa91..b3eb9b1042 100644 --- a/plextraktsync/sync/WatchListPlugin.py +++ b/plextraktsync/sync/WatchListPlugin.py @@ -40,8 +40,10 @@ def init(self, sync: Sync, is_partial: bool): return if is_partial: - self.logger.warning("Running partial library sync. " - "Watchlist as playlist won't update because it needs full library sync.") + self.logger.warning( + "Running partial library sync. " + "Watchlist as playlist won't update because it needs full library sync." + ) else: sync.trakt_lists.add_watchlist(self.trakt.watchlist_movies) @@ -52,8 +54,10 @@ async def fini(self, walker: Walker, dry_run: bool): await self.sync_watchlist(walker, dry_run=dry_run) if self.config.update_plex_wl_as_pl and dry_run: - self.logger.warning("Running partial library sync. " - "Liked lists won't update because it needs full library sync.") + self.logger.warning( + "Running partial library sync. " + "Liked lists won't update because it needs full library sync." + ) @cached_property def plex_wl(self): @@ -74,9 +78,15 @@ def trakt_wl(self): def watchlist_sync_item(self, m: Media, dry_run: bool): if m.plex is None: if self.config.update_plex_wl: - self.logger.info(f"Skipping {m.title_link} from Trakt watchlist because not found in Plex Discover", extra={"markup": True}) + self.logger.info( + f"Skipping {m.title_link} from Trakt watchlist because not found in Plex Discover", + extra={"markup": True}, + ) elif self.config.update_trakt_wl: - self.logger.info(f"Removing {m.title_link} from Trakt watchlist", extra={"markup": True}) + self.logger.info( + f"Removing {m.title_link} from Trakt watchlist", + extra={"markup": True}, + ) if not dry_run: m.remove_from_trakt_watchlist() return @@ -84,11 +94,17 @@ def watchlist_sync_item(self, m: Media, dry_run: bool): if m in self.plex_wl: if m not in self.trakt_wl: if self.config.update_trakt_wl: - self.logger.info(f"Adding {m.title_link} to Trakt watchlist", extra={"markup": True}) + self.logger.info( + f"Adding {m.title_link} to Trakt watchlist", + extra={"markup": True}, + ) if not dry_run: m.add_to_trakt_watchlist() else: - self.logger.info(f"Removing {m.title_link} from Plex watchlist", extra={"markup": True}) + self.logger.info( + f"Removing {m.title_link} from Plex watchlist", + extra={"markup": True}, + ) if not dry_run: m.remove_from_plex_watchlist() else: @@ -100,11 +116,16 @@ def watchlist_sync_item(self, m: Media, dry_run: bool): del self.trakt_wl[m] elif m in self.trakt_wl: if self.config.update_plex_wl: - self.logger.info(f"Adding {m.title_link} to Plex watchlist", extra={"markup": True}) + self.logger.info( + f"Adding {m.title_link} to Plex watchlist", extra={"markup": True} + ) if not dry_run: m.add_to_plex_watchlist() else: - self.logger.info(f"Removing {m.title_link} from Trakt watchlist", extra={"markup": True}) + self.logger.info( + f"Removing {m.title_link} from Trakt watchlist", + extra={"markup": True}, + ) if not dry_run: m.remove_from_trakt_watchlist() diff --git a/plextraktsync/sync/WatchProgressPlugin.py b/plextraktsync/sync/WatchProgressPlugin.py index 84969c85b0..ed48c27407 100644 --- a/plextraktsync/sync/WatchProgressPlugin.py +++ b/plextraktsync/sync/WatchProgressPlugin.py @@ -41,14 +41,17 @@ async def sync_progress(self, m: Media, dry_run=False): return progress = m.plex.progress_millis(p.progress) if progress == 0.0: - self.logger.warning(f"{m.title_link}: Skip progress, setting to 0 will not work", extra={"markup": True}) + self.logger.warning( + f"{m.title_link}: Skip progress, setting to 0 will not work", + extra={"markup": True}, + ) return view_offset = timedelta(milliseconds=m.plex.item.viewOffset) progress_offset = timedelta(milliseconds=progress) self.logger.info( f"{m.title_link}: Set watch progress to {p.progress:.02F}%: {view_offset} -> {progress_offset}", - extra={"markup": True} + extra={"markup": True}, ) if not dry_run: m.plex.item.updateProgress(progress) diff --git a/plextraktsync/sync/plugin/SyncPluginManager.py b/plextraktsync/sync/plugin/SyncPluginManager.py index 4ee3fb8573..97c783dbda 100644 --- a/plextraktsync/sync/plugin/SyncPluginManager.py +++ b/plextraktsync/sync/plugin/SyncPluginManager.py @@ -46,6 +46,7 @@ def plugins(self): from ..TraktListsPlugin import TraktListsPlugin from ..WatchListPlugin import WatchListPlugin from ..WatchProgressPlugin import WatchProgressPlugin + yield AddCollectionPlugin yield ClearCollectedPlugin yield LikedListsPlugin @@ -61,7 +62,11 @@ def register_plugins(self, sync: Sync): self.logger.info(f"Enable sync plugin '{plugin.__name__}': {enabled}") if not enabled: continue - with measure_time(f"Created '{plugin.__name__}' plugin", logger=self.logger.debug): + with measure_time( + f"Created '{plugin.__name__}' plugin", logger=self.logger.debug + ): p = plugin.factory(sync) - with measure_time(f"Registered '{plugin.__name__}' plugin", logger=self.logger.debug): + with measure_time( + f"Registered '{plugin.__name__}' plugin", logger=self.logger.debug + ): self.pm.register(p) diff --git a/plextraktsync/trakt/PartialTraktMedia.py b/plextraktsync/trakt/PartialTraktMedia.py index 757ec98e82..50ee8369a0 100644 --- a/plextraktsync/trakt/PartialTraktMedia.py +++ b/plextraktsync/trakt/PartialTraktMedia.py @@ -17,8 +17,10 @@ class PartialTraktMedia: @classmethod def create(cls, m: TraktMedia, **extra): - return cls(**{ - "ids": m.ids, - "media_type": m.media_type, - **extra, - }) + return cls( + **{ + "ids": m.ids, + "media_type": m.media_type, + **extra, + } + ) diff --git a/plextraktsync/trakt/ScrobblerProxy.py b/plextraktsync/trakt/ScrobblerProxy.py index ba07e44b43..60dbc5e578 100644 --- a/plextraktsync/trakt/ScrobblerProxy.py +++ b/plextraktsync/trakt/ScrobblerProxy.py @@ -13,6 +13,7 @@ class ScrobblerProxy: """ Proxy to Scrobbler that queues requests to update trakt """ + logger = logging.getLogger(__name__) def __init__(self, scrobbler: Scrobbler, threshold=80): diff --git a/plextraktsync/trakt/TraktApi.py b/plextraktsync/trakt/TraktApi.py index 41e039b1e3..306fc28991 100644 --- a/plextraktsync/trakt/TraktApi.py +++ b/plextraktsync/trakt/TraktApi.py @@ -9,8 +9,12 @@ import trakt.sync import trakt.users from click import ClickException -from trakt.errors import (ForbiddenException, NotFoundException, - OAuthException, OAuthRefreshException) +from trakt.errors import ( + ForbiddenException, + NotFoundException, + OAuthException, + OAuthRefreshException, +) from plextraktsync import pytrakt_extensions from plextraktsync.decorators.flatten import flatten_list @@ -38,6 +42,7 @@ class TraktApi: """ Trakt API class abstracting common data access and dealing with requests cache. """ + logger = logging.getLogger(__name__) def __init__(self): @@ -71,7 +76,9 @@ def liked_lists(self) -> list[TraktLikedList]: # Skip private lists # https://github.com/Taxel/PlexTraktSync/issues/1864#issuecomment-2018171311 if item["list"]["privacy"] == "private": - self.logger.warning(f"Skipping private list: {item['list']['name']} - {item['list']['share_link']}") + self.logger.warning( + f"Skipping private list: {item['list']['name']} - {item['list']['share_link']}" + ) continue tll: TraktLikedList = { "listname": item["list"]["name"], @@ -232,7 +239,9 @@ def remove_from_watchlist(self, m): self.queue.remove_from_watchlist((m.media_type, item)) def find_by_episode_guid(self, guid: PlexGuid): - ts: TVShow = self.search_by_id(guid.show_id, id_type=guid.provider, media_type="show") + ts: TVShow = self.search_by_id( + guid.show_id, id_type=guid.provider, media_type="show" + ) if not ts: return None @@ -253,7 +262,10 @@ def find_by_guid(self, guid: PlexGuid): tm = self.search_by_id(guid.id, id_type=guid.provider, media_type=guid.type) if tm is None and guid.type == "movie": if self.search_by_id(guid.id, id_type=guid.provider, media_type="show"): - self.logger.warning(f"Found match using show search: {guid.title_link}", extra={"markup": True}) + self.logger.warning( + f"Found match using show search: {guid.title_link}", + extra={"markup": True}, + ) return tm @@ -261,6 +273,7 @@ def find_by_guid(self, guid: PlexGuid): def find_by_slug(slug: str, media_type: str): if media_type == "movie": from trakt.movies import Movie + factory_method = Movie else: raise RuntimeError(f"Unsupported media_type={media_type}") @@ -272,12 +285,16 @@ def find_by_slug(slug: str, media_type: str): @rate_limit() @retry() - def search_by_id(self, media_id: str, id_type: str, media_type: str) -> TVShow | Movie | None: + def search_by_id( + self, media_id: str, id_type: str, media_type: str + ) -> TVShow | Movie | None: if id_type == "tvdb" and media_type == "movie": # Skip invalid search. # The Trakt API states that tvdb is only for shows and episodes: # https://trakt.docs.apiary.io/#reference/search/id-lookup/get-id-lookup-results - self.logger.debug(f"search_by_id: tvdb does not support movie provider, skip {id_type}/{media_type}/{media_id}") + self.logger.debug( + f"search_by_id: tvdb does not support movie provider, skip {id_type}/{media_type}/{media_id}" + ) return None if media_type == "season": # Search by season is missing @@ -297,7 +314,9 @@ def search_by_id(self, media_id: str, id_type: str, media_type: str) -> TVShow | return None if len(search) > 1: - self.logger.debug(f"search_by_id({media_id}, {id_type}, {media_type}) got {len(search)} results, taking first one") + self.logger.debug( + f"search_by_id({media_id}, {id_type}, {media_type}) got {len(search)} results, taking first one" + ) self.logger.debug([pm.to_json() for pm in search]) # TODO: sort by "score"? diff --git a/plextraktsync/trakt/TraktItem.py b/plextraktsync/trakt/TraktItem.py index 8fed150c2e..15d8448e4d 100644 --- a/plextraktsync/trakt/TraktItem.py +++ b/plextraktsync/trakt/TraktItem.py @@ -21,4 +21,8 @@ def type(self): @property def guids(self): - return {k: v for k, v in self.item.ids["ids"].items() if k in ["imdb", "tmdb", "tvdb"]} + return { + k: v + for k, v in self.item.ids["ids"].items() + if k in ["imdb", "tmdb", "tvdb"] + } diff --git a/plextraktsync/trakt/TraktLookup.py b/plextraktsync/trakt/TraktLookup.py index a3ffd2b26e..a11a03083c 100644 --- a/plextraktsync/trakt/TraktLookup.py +++ b/plextraktsync/trakt/TraktLookup.py @@ -6,8 +6,10 @@ from plextraktsync.decorators.retry import retry from plextraktsync.factory import logging -EPISODES_ORDERING_WARNING = "episodes ordering is different in Plex and Trakt. " \ - "Check your Plex media source, TMDB is recommended." +EPISODES_ORDERING_WARNING = ( + "episodes ordering is different in Plex and Trakt. " + "Check your Plex media source, TMDB is recommended." +) if TYPE_CHECKING: from trakt.tv import TVEpisode, TVShow @@ -19,6 +21,7 @@ class TraktLookup: """ Trakt lookup table to find all Trakt episodes of a TVShow """ + logger = logging.getLogger(__name__) def __init__(self, tm: TVShow): diff --git a/plextraktsync/trakt/TraktUserList.py b/plextraktsync/trakt/TraktUserList.py index 154f566ea2..d21de74261 100644 --- a/plextraktsync/trakt/TraktUserList.py +++ b/plextraktsync/trakt/TraktUserList.py @@ -18,11 +18,12 @@ class TraktUserList: plex_items: list[tuple[int, PlexLibraryItem]] logger = logging.getLogger(__name__) - def __init__(self, - trakt_id: int = None, - name: str = None, - items=None, - ): + def __init__( + self, + trakt_id: int = None, + name: str = None, + items=None, + ): self.trakt_id = trakt_id self.name = name self._items = items @@ -48,11 +49,17 @@ def items(self): @staticmethod def build_dict(pl: PublicList): - return {(f"{le.type}s", le.trakt): le.rank for le in pl if le.type in ["movie", "episode"]} + return { + (f"{le.type}s", le.trakt): le.rank + for le in pl + if le.type in ["movie", "episode"] + } def load_items(self): pl = PublicList.load(self.trakt_id) - self.logger.info(f"Downloaded Trakt list '{pl.name}' ({len(pl)} items): {pl.share_link}") + self.logger.info( + f"Downloaded Trakt list '{pl.name}' ({len(pl)} items): {pl.share_link}" + ) return pl.description, self.build_dict(pl) @@ -91,10 +98,15 @@ def add(self, m: Media): # Already in the list return - self.logger.info(f"Adding {m.title_link} ({m.plex_key}) to Plex list {self.title_link}", extra={"markup": True}) + self.logger.info( + f"Adding {m.title_link} ({m.plex_key}) to Plex list {self.title_link}", + extra={"markup": True}, + ) # Report duplicates - duplicates = [p for _, p in self.plex_items if p.key != m.plex_key and p == m.plex] + duplicates = [ + p for _, p in self.plex_items if p.key != m.plex_key and p == m.plex + ] for p in duplicates: msg = f"Duplicate {p.title_link} #{p.key} with {m.title_link} #{m.plex_key}" if p.edition_title is not None: diff --git a/plextraktsync/util/Factory.py b/plextraktsync/util/Factory.py index 3d6795e146..e16c0969ec 100644 --- a/plextraktsync/util/Factory.py +++ b/plextraktsync/util/Factory.py @@ -70,8 +70,7 @@ def get_plex_by_id(self, server_id: str): @cached_property def plex_server(self): from plextraktsync.factory import factory - from plextraktsync.plex.PlexServerConnection import \ - PlexServerConnection + from plextraktsync.plex.PlexServerConnection import PlexServerConnection server = self.server_config @@ -82,8 +81,7 @@ def plex_server(self): @cached_property def plex_lists(self): - from plextraktsync.plex.PlexPlaylistCollection import \ - PlexPlaylistCollection + from plextraktsync.plex.PlexPlaylistCollection import PlexPlaylistCollection return PlexPlaylistCollection(self.plex_server) @@ -96,14 +94,12 @@ def has_plex_token(self): @cached_property def server_config_factory(self): - from plextraktsync.config.ServerConfigFactory import \ - ServerConfigFactory + from plextraktsync.config.ServerConfigFactory import ServerConfigFactory return ServerConfigFactory() @cached_property def server_config(self): - config = self.config run_config = self.run_config server_config = self.server_config_factory @@ -233,13 +229,13 @@ def logging(self): class Logging: @staticmethod def getLogger(name): - """ Wrap getLogger and add our filters """ + """Wrap getLogger and add our filters""" logger = logging.getLogger(name) logger.addFilter(logger_filter) return logger def __getattr__(self, name): - """ Wrap log level attributes """ + """Wrap log level attributes""" return getattr(logging, name) return Logging() @@ -261,6 +257,7 @@ def logger_filter(self): def logger_filter_apply(self, logger_filter): import logging + config = self.config loggers = config["logging"]["filter_loggers"] or [] @@ -308,8 +305,7 @@ def queue(self): from plextraktsync.queue.BackgroundTask import BackgroundTask from plextraktsync.queue.Queue import Queue from plextraktsync.queue.TraktBatchWorker import TraktBatchWorker - from plextraktsync.queue.TraktMarkWatchedWorker import \ - TraktMarkWatchedWorker + from plextraktsync.queue.TraktMarkWatchedWorker import TraktMarkWatchedWorker from plextraktsync.queue.TraktScrobbleWorker import TraktScrobbleWorker workers = [ @@ -326,4 +322,6 @@ def queue(self): def batch_delay_timer(self): from plextraktsync.util.Timer import Timer - return Timer(self.run_config.batch_delay) if self.run_config.batch_delay else None + return ( + Timer(self.run_config.batch_delay) if self.run_config.batch_delay else None + ) diff --git a/plextraktsync/util/Rating.py b/plextraktsync/util/Rating.py index 6c40fb86aa..d2bc1220b8 100644 --- a/plextraktsync/util/Rating.py +++ b/plextraktsync/util/Rating.py @@ -11,7 +11,7 @@ class Rating(NamedTuple): rated_at: datetime | None def __eq__(self, other): - """ Ratings are equal if their rating value is the same """ + """Ratings are equal if their rating value is the same""" if isinstance(other, (int, float)): return self.rating == int(other) @@ -35,8 +35,10 @@ def create(cls, rating: int | float | None, rated_at: datetime | str | None): rated_at = datetime.fromisoformat(rated_at) except ValueError: # Handle older Python < 3.11 - rated_at = (datetime.strptime(rated_at, "%Y-%m-%dT%H:%M:%S.%fZ") - # https://stackoverflow.com/questions/3305413/how-to-preserve-timezone-when-parsing-date-time-strings-with-strptime/63988322#63988322 - .replace(tzinfo=timezone.utc)) + rated_at = ( + datetime.strptime(rated_at, "%Y-%m-%dT%H:%M:%S.%fZ") + # https://stackoverflow.com/questions/3305413/how-to-preserve-timezone-when-parsing-date-time-strings-with-strptime/63988322#63988322 + .replace(tzinfo=timezone.utc) + ) return cls(rating, rated_at) diff --git a/plextraktsync/util/Timer.py b/plextraktsync/util/Timer.py index dc6ea0e57f..3555d5d3c1 100644 --- a/plextraktsync/util/Timer.py +++ b/plextraktsync/util/Timer.py @@ -7,6 +7,7 @@ class Timer: """ Class dealing with limiting that something is not called more often than {delay} """ + logger = logging.getLogger(__name__) def __init__(self, delay: float): diff --git a/plextraktsync/util/local_url.py b/plextraktsync/util/local_url.py index 430dff73fe..ab76123390 100644 --- a/plextraktsync/util/local_url.py +++ b/plextraktsync/util/local_url.py @@ -9,14 +9,20 @@ def local_url(port=32400): return f"http://localhost:{port}" import socket + try: host_ip = socket.gethostbyname("host.docker.internal") except socket.gaierror: try: from subprocess import check_output - host_ip = check_output( - "ip -4 route show default | awk '{ print $3 }'", shell=True - ).decode().rstrip() + + host_ip = ( + check_output( + "ip -4 route show default | awk '{ print $3 }'", shell=True + ) + .decode() + .rstrip() + ) except Exception: host_ip = "172.17.0.1" diff --git a/plextraktsync/watch/ProgressBar.py b/plextraktsync/watch/ProgressBar.py index 739af6ccb9..da522d9cbf 100644 --- a/plextraktsync/watch/ProgressBar.py +++ b/plextraktsync/watch/ProgressBar.py @@ -20,12 +20,14 @@ def progress(self): from rich.box import MINIMAL from rich.live import Live from rich.panel import Panel - from rich.progress import (BarColumn, Progress, TextColumn, - TimeRemainingColumn) + from rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn console = factory.console progress = Progress( - TextColumn(" {task.fields[play_state]} [bold blue]{task.description}", justify="left"), + TextColumn( + " {task.fields[play_state]} [bold blue]{task.description}", + justify="left", + ), BarColumn(bar_width=None), "[progress.percentage]{task.percentage:>3.1f}%", "•", @@ -56,11 +58,15 @@ def __missing__(self, m: PlexLibraryItem): def play(self, m: PlexLibraryItem, progress: float): task_id = self[m] - self.progress.update(task_id, completed=progress, play_state=self.ICONS["playing"]) + self.progress.update( + task_id, completed=progress, play_state=self.ICONS["playing"] + ) def pause(self, m: PlexLibraryItem, progress: float): task_id = self[m] - self.progress.update(task_id, completed=progress, play_state=self.ICONS["paused"]) + self.progress.update( + task_id, completed=progress, play_state=self.ICONS["paused"] + ) def stop(self, m: PlexLibraryItem): task_id = self[m] diff --git a/plextraktsync/watch/WatchStateUpdater.py b/plextraktsync/watch/WatchStateUpdater.py index 6b2a227401..408376d544 100644 --- a/plextraktsync/watch/WatchStateUpdater.py +++ b/plextraktsync/watch/WatchStateUpdater.py @@ -5,9 +5,13 @@ from plextraktsync.factory import logging from plextraktsync.mixin.SetWindowTitle import SetWindowTitle -from plextraktsync.watch.events import (ActivityNotification, Error, - PlaySessionStateNotification, - ServerStarted, TimelineEntry) +from plextraktsync.watch.events import ( + ActivityNotification, + Error, + PlaySessionStateNotification, + ServerStarted, + TimelineEntry, +) if TYPE_CHECKING: from plextraktsync.config.Config import Config @@ -22,11 +26,11 @@ class WatchStateUpdater(SetWindowTitle): logger = logging.getLogger(__name__) def __init__( - self, - plex: PlexApi, - trakt: TraktApi, - mf: MediaFactory, - config: Config, + self, + plex: PlexApi, + trakt: TraktApi, + mf: MediaFactory, + config: Config, ): self.plex = plex self.trakt = trakt @@ -44,7 +48,9 @@ def username_filter(self): # This must be username, not email return self.plex.account.username - self.logger.warning("No permission to access sessions, disabling username filter") + self.logger.warning( + "No permission to access sessions, disabling username filter" + ) return None @cached_property @@ -73,7 +79,9 @@ def sessions(self): def scrobblers(self): from plextraktsync.trakt.ScrobblerCollection import ScrobblerCollection - return ScrobblerCollection(self.trakt, self.config["watch"]["scrobble_threshold"]) + return ScrobblerCollection( + self.trakt, self.config["watch"]["scrobble_threshold"] + ) @lru_cache(maxsize=2) def fetch_item(self, key: str): @@ -116,11 +124,15 @@ def server(self): return self.plex.server def on_start(self, event: ServerStarted): - self.logger.info(f"Server connected: {event.server.friendlyName} ({event.server.version})") + self.logger.info( + f"Server connected: {event.server.friendlyName} ({event.server.version})" + ) self.reset_title() def reset_title(self): - self.set_window_title(f"watch: {self.server.friendlyName} ({self.server.version})") + self.set_window_title( + f"watch: {self.server.friendlyName} ({self.server.version})" + ) def on_error(self, error: Error): self.logger.error(error.msg) diff --git a/tests/test_tv_lookup.py b/tests/test_tv_lookup.py index 3065ccba0f..1e431a3129 100755 --- a/tests/test_tv_lookup.py +++ b/tests/test_tv_lookup.py @@ -25,7 +25,9 @@ def test_tv_lookup(): @pytest.mark.skip(reason="Broken in CI") def test_show_episodes_plex(): - m = PlexLibraryItem(make(cls="plexapi.video.Show", guid="imdb://tt10584350", type="show")) + m = PlexLibraryItem( + make(cls="plexapi.video.Show", guid="imdb://tt10584350", type="show") + ) guid = m.guids[0] show = trakt.find_by_guid(guid) From 7d32ab103433279216fcc01738cf59bd54975741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 8 Jun 2024 11:11:12 +0300 Subject: [PATCH 2/2] Replace flake8 Lint with Ruff Lint --- .github/workflows/lint.yml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b91acb0e91..2b6b496a97 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,22 +1,13 @@ -name: flake8 Lint +name: Ruff Lint on: - pull_request -env: - DEFAULT_PYTHON: 3.8 - jobs: - flake8-lint: + ruff: runs-on: ubuntu-latest - name: Lint steps: - - name: Check out source repository - uses: actions/checkout@v4 - - name: Set up Python environment - uses: actions/setup-python@v5 - with: - python-version: ${{ env.DEFAULT_PYTHON }} - - name: flake8 Lint - uses: py-actions/flake8@v2 + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + # vim:ts=2:sw=2:et