Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add update-playlist command: Remove watched items #2043

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions plextraktsync/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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)
44 changes: 44 additions & 0 deletions plextraktsync/commands/update_playlist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations

from typing import TYPE_CHECKING

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


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):
print = factory.print
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)
3 changes: 3 additions & 0 deletions plextraktsync/plex/PlexPlaylist.py
Original file line number Diff line number Diff line change
Expand Up @@ -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<name='{self.name}'>"

@cached_property
def playlist(self) -> Playlist | None:
try:
Expand Down
1 change: 1 addition & 0 deletions plextraktsync/plex/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
from plexapi.video import Episode, Movie, Show

PlexMedia = Union[Movie, Show, Episode]
PlexPlayable = Union[Movie, Episode]
Loading