feat(media-actions-menu): bulk media list actions

This commit is contained in:
Benexl
2025-07-29 12:36:17 +03:00
parent 9cfbc0bdcf
commit 87372e41be
2 changed files with 92 additions and 6 deletions

View File

@@ -73,6 +73,9 @@ def media_actions(ctx: Context, state: State) -> State | InternalDirective:
f"{' ' if icons else ''}Add/Update List": _manage_user_media_list(
ctx, state
),
f"{' ' if icons else ''}Add/Update List (Bulk)": _manage_user_media_list_in_bulk(
ctx, state
),
f"{'' if icons else ''}Score Anime": _score_anime(ctx, state),
f"{' ' if icons else ''}View Info": _view_info(ctx, state),
f"{'📀 ' if icons else ''}Change Provider (Current: {ctx.config.general.provider.value.upper()})": _change_provider(
@@ -202,7 +205,7 @@ def _manage_user_media_list(ctx: Context, state: State) -> MenuAction:
return InternalDirective.RELOAD
status = ctx.selector.choose(
"Select list status:", choices=[t.value for t in UserMediaListStatus]
"Select list status", choices=[t.value for t in UserMediaListStatus]
)
if status:
# local
@@ -212,11 +215,84 @@ def _manage_user_media_list(ctx: Context, state: State) -> MenuAction:
status=UserMediaListStatus(status),
)
# remote
ctx.media_api.update_list_entry(
if not ctx.media_api.update_list_entry(
UpdateUserMediaListEntryParams(
media_item.id, status=UserMediaListStatus(status)
)
):
print(f"Failed to update {media_item.title.english}")
return InternalDirective.RELOAD
return action
def _manage_user_media_list_in_bulk(ctx: Context, state: State) -> MenuAction:
def action():
feedback = ctx.feedback
search_result = state.media_api.search_result
if not search_result:
return InternalDirective.RELOAD
if not ctx.media_api.is_authenticated():
feedback.warning(
"You are not authenticated",
)
return InternalDirective.RELOAD
choice_map: Dict[str, MediaItem] = {
item.title.english: item for item in search_result.values()
}
preview_command = None
if ctx.config.general.preview != "none":
from ....utils.preview import create_preview_context
with create_preview_context() as preview_ctx:
preview_command = preview_ctx.get_anime_preview(
list(choice_map.values()),
list(choice_map.keys()),
ctx.config,
)
selected_titles = ctx.selector.choose_multiple(
"Select anime to download",
list(choice_map.keys()),
preview=preview_command,
)
else:
selected_titles = ctx.selector.choose_multiple(
"Select anime to download",
list(choice_map.keys()),
)
if not selected_titles:
feedback.warning("No anime selected. Aborting download.")
return InternalDirective.RELOAD
anime_to_update_status = [choice_map[title] for title in selected_titles]
status = ctx.selector.choose(
"Select list status", choices=[t.value for t in UserMediaListStatus]
)
if not status:
feedback.warning("No status selected. Aborting bulk action.")
return InternalDirective.RELOAD
with feedback.progress(
"Updating media list...", total=len(anime_to_update_status)
) as (task_id, progress):
for media_item in anime_to_update_status:
feedback.info(f"Updating media status for {media_item.title.english}")
ctx.media_registry.update_media_index_entry(
media_id=media_item.id,
media_item=media_item,
status=UserMediaListStatus(status),
)
# remote
if not ctx.media_api.update_list_entry(
UpdateUserMediaListEntryParams(
media_item.id, status=UserMediaListStatus(status)
)
):
print(f"Failed to update {media_item.title.english}")
progress.update(task_id, advance=1)
return InternalDirective.RELOAD
return action

View File

@@ -3,7 +3,13 @@ from typing import Optional
import click
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.progress import (
BarColumn,
Progress,
SpinnerColumn,
TaskProgressColumn,
TextColumn,
)
console = Console()
@@ -60,6 +66,8 @@ class FeedbackService:
def progress(
self,
message: str,
total: Optional[float] = None,
transient: bool = True,
success_msg: Optional[str] = None,
error_msg: Optional[str] = None,
):
@@ -67,12 +75,14 @@ class FeedbackService:
with Progress(
SpinnerColumn(),
TextColumn(f"[cyan]{message}..."),
transient=True,
BarColumn(),
TaskProgressColumn(),
transient=transient,
console=console,
) as progress:
progress.add_task("", total=None)
task_id = progress.add_task("", total=total)
try:
yield
yield task_id, progress
if success_msg:
self.success(success_msg)
except Exception as e: