From 49fd0e989ca98021a46ca1f964ce2335a35209e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 31 Aug 2024 19:18:41 +0300 Subject: [PATCH 1/6] Add update_playlist command --- plextraktsync/commands/update_playlist.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 plextraktsync/commands/update_playlist.py diff --git a/plextraktsync/commands/update_playlist.py b/plextraktsync/commands/update_playlist.py new file mode 100644 index 0000000000..d98b2668ef --- /dev/null +++ b/plextraktsync/commands/update_playlist.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from plextraktsync.decorators.coro import coro +from plextraktsync.factory import factory + + +@coro +async def update_playlist(playlist: str, remove_watched: bool, dry_run: bool): + print = factory.print + pl = playlist + print(f"Update playlist: '{pl}'") + print(f"Remove watched from playlist: {remove_watched}") + print(f"Dry run: {dry_run}") From c88f8ae1e3b183a353be695d3e58059e1adab585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 31 Aug 2024 19:20:24 +0300 Subject: [PATCH 2/6] Register update_playlist command --- plextraktsync/cli.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/plextraktsync/cli.py b/plextraktsync/cli.py index 8f3a832a45..601a5391dc 100644 --- a/plextraktsync/cli.py +++ b/plextraktsync/cli.py @@ -276,6 +276,29 @@ def unmatched(): """ +@command() +@click.option( + "--remove-watched", + type=bool, + default=False, + is_flag=True, + help="Remove watched items from playlist", +) +@click.option( + "--dry-run", + "dry_run", + type=bool, + default=False, + is_flag=True, + help="Dry run: Do not make changes", +) +@click.argument("playlist", nargs=1) +def update_playlist(): + """ + Update playlist: Remove watched items + """ + + @command() @click.option( "--server", @@ -379,5 +402,6 @@ def config(): cli.add_command(sync) cli.add_command(trakt_login) cli.add_command(unmatched) +cli.add_command(update_playlist) cli.add_command(watch) cli.add_command(watched_shows) From ff52202c12607e565842fb12622647fc1aed8bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 31 Aug 2024 19:30:18 +0300 Subject: [PATCH 3/6] Add PlexPlayable type --- plextraktsync/plex/types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plextraktsync/plex/types.py b/plextraktsync/plex/types.py index b33f136434..66d598fc93 100644 --- a/plextraktsync/plex/types.py +++ b/plextraktsync/plex/types.py @@ -5,3 +5,4 @@ from plexapi.video import Episode, Movie, Show PlexMedia = Union[Movie, Show, Episode] +PlexPlayable = Union[Movie, Episode] From 634e8c5dc74e3c784865a0409ae906463d2545cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 31 Aug 2024 19:31:43 +0300 Subject: [PATCH 4/6] Add __str__ to PlexPlaylist --- plextraktsync/plex/PlexPlaylist.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plextraktsync/plex/PlexPlaylist.py b/plextraktsync/plex/PlexPlaylist.py index 063200f2d6..e792530c41 100644 --- a/plextraktsync/plex/PlexPlaylist.py +++ b/plextraktsync/plex/PlexPlaylist.py @@ -31,6 +31,9 @@ def __len__(self): def __contains__(self, m: Media): return m.plex_key in self.items + def __str__(self): + return f"PlexPlaylist" + @cached_property def playlist(self) -> Playlist | None: try: From 03a0483e0cbeb0340a8350e5791626bcdbe1108c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 31 Aug 2024 20:04:57 +0300 Subject: [PATCH 5/6] Add update_playlist helper --- plextraktsync/commands/update_playlist.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plextraktsync/commands/update_playlist.py b/plextraktsync/commands/update_playlist.py index d98b2668ef..dd9d47ef36 100644 --- a/plextraktsync/commands/update_playlist.py +++ b/plextraktsync/commands/update_playlist.py @@ -1,8 +1,27 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from plextraktsync.decorators.coro import coro from plextraktsync.factory import factory +if TYPE_CHECKING: + from plextraktsync.plex.types import PlexPlayable + + +def format_title(p: PlexPlayable): + library_title = p._data.attrib.get("librarySectionTitle") + title = f"'{p.title}'" + if p.year: + title += f" ({p.year})" + + if library_title: + title += f" (in '{library_title}')" + if p.sourceURI: + title += f" (on {p.sourceURI})" + + return title + @coro async def update_playlist(playlist: str, remove_watched: bool, dry_run: bool): From 8ace61509a453bb329bcd410c15a4c3e1548a28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 31 Aug 2024 20:14:05 +0300 Subject: [PATCH 6/6] Implement cleaning up playlist of watched items --- plextraktsync/commands/update_playlist.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plextraktsync/commands/update_playlist.py b/plextraktsync/commands/update_playlist.py index dd9d47ef36..14ce208557 100644 --- a/plextraktsync/commands/update_playlist.py +++ b/plextraktsync/commands/update_playlist.py @@ -4,6 +4,7 @@ from plextraktsync.decorators.coro import coro from plextraktsync.factory import factory +from plextraktsync.plex.PlexPlaylist import PlexPlaylist if TYPE_CHECKING: from plextraktsync.plex.types import PlexPlayable @@ -26,7 +27,18 @@ def format_title(p: PlexPlayable): @coro async def update_playlist(playlist: str, remove_watched: bool, dry_run: bool): print = factory.print - pl = playlist - print(f"Update playlist: '{pl}'") + print(f"Update playlist: '{playlist}'") print(f"Remove watched from playlist: {remove_watched}") print(f"Dry run: {dry_run}") + + pl = PlexPlaylist(factory.plex_server, playlist) + print(f"Playlist: {pl}") + items = pl.playlist.items().copy() + p: PlexPlayable + for p in items: + if remove_watched and p.isPlayed: + print(f"{'Remove' if not dry_run else 'Would remove'} from playlist: {format_title(p)}") + items.remove(p) + print(f"Update playlist: {len(pl)} -> {len(items)} items") + if not dry_run: + pl.update(items)