This commit is contained in:
nose
2025-11-25 22:34:41 -08:00
parent 00a1371793
commit 4df4fb3bd9
7 changed files with 228 additions and 94 deletions

View File

@@ -2459,6 +2459,38 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any], emit_results:
if downloaded_files or files_downloaded_directly > 0:
total_files = len(downloaded_files) + files_downloaded_directly
log(f"✓ Successfully downloaded {total_files} file(s)", flush=True)
# Create a result table for the downloaded files
# This ensures that subsequent @N commands select from these files
# instead of trying to expand the previous command (e.g. search-file)
if downloaded_files:
from result_table import ResultTable
table = ResultTable("Downloaded Files")
for i, file_path in enumerate(downloaded_files):
row = table.add_row()
row.add_column("#", str(i + 1))
row.add_column("File", file_path.name)
row.add_column("Path", str(file_path))
try:
size_mb = file_path.stat().st_size / (1024*1024)
row.add_column("Size", f"{size_mb:.1f} MB")
except OSError:
row.add_column("Size", "?")
# Set selection args to just the file path (or index if we want item selection)
# For item selection fallback, we don't strictly need row args if source command is None
# But setting them helps if we want to support command expansion later
table.set_row_selection_args(i, [str(file_path)])
# Register the table but DO NOT set a source command
# This forces CLI to use item-based selection (filtering the pipe)
# instead of command expansion
pipeline_context.set_last_result_table_overlay(table, downloaded_files)
pipeline_context.set_current_stage_table(table)
# Also print the table so user sees what they got
log(str(table), flush=True)
if db:
db.update_worker_status(worker_id, 'completed')
return 0

View File

@@ -104,6 +104,29 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
clear_mode = parsed.get("clear")
list_mode = parsed.get("list")
play_mode = parsed.get("play")
pause_mode = parsed.get("pause")
# Handle Play/Pause commands
if play_mode:
cmd = {"command": ["set_property", "pause", False], "request_id": 103}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
log("Resumed playback")
return 0
else:
log("Failed to resume playback (MPV not running?)", file=sys.stderr)
return 1
if pause_mode:
cmd = {"command": ["set_property", "pause", True], "request_id": 104}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
log("Paused playback")
return 0
else:
log("Failed to pause playback (MPV not running?)", file=sys.stderr)
return 1
# Handle piped input (add to playlist)
if result:
@@ -132,15 +155,19 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
if target:
# Add to MPV playlist
# We use loadfile with append flag
# Configure 1080p limit for streams (bestvideo<=1080p + bestaudio)
options = {
"ytdl-format": "bestvideo[height<=?1080]+bestaudio/best[height<=?1080]"
}
# Use memory:// M3U hack to pass title to MPV
# This avoids "invalid parameter" errors with loadfile options
# and ensures the title is displayed in the playlist/window
if title:
options["force-media-title"] = title
# Sanitize title for M3U (remove newlines)
safe_title = title.replace('\n', ' ').replace('\r', '')
m3u_content = f"#EXTM3U\n#EXTINF:-1,{safe_title}\n{target}"
target_to_send = f"memory://{m3u_content}"
else:
target_to_send = target
cmd = {"command": ["loadfile", target, "append", options], "request_id": 200}
cmd = {"command": ["loadfile", target_to_send, "append"], "request_id": 200}
resp = _send_ipc_command(cmd)
if resp is None:
@@ -154,6 +181,18 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
log(f"Queued: {title}")
else:
log(f"Queued: {target}")
else:
error_msg = str(resp.get('error'))
log(f"Failed to queue item: {error_msg}", file=sys.stderr)
# If error indicates parameter issues, try without options
# (Though memory:// should avoid this, we keep fallback just in case)
if "option" in error_msg or "parameter" in error_msg:
cmd = {"command": ["loadfile", target, "append"], "request_id": 201}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
added_count += 1
log(f"Queued (fallback): {title or target}")
if added_count > 0:
# If we added items, we might want to play the first one if nothing is playing?
@@ -198,6 +237,10 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
cmd = {"command": ["playlist-play-index", idx], "request_id": 102}
resp = _send_ipc_command(cmd)
if resp and resp.get("error") == "success":
# Ensure playback starts (unpause)
unpause_cmd = {"command": ["set_property", "pause", False], "request_id": 103}
_send_ipc_command(unpause_cmd)
log(f"Playing: {title}")
return 0
else:
@@ -275,8 +318,6 @@ def _start_mpv(items: List[Any]) -> None:
cmd.append('--ytdl-format=bestvideo[height<=?1080]+bestaudio/best[height<=?1080]')
# Add items
first_title_set = False
for item in items:
target = None
title = None
@@ -291,10 +332,13 @@ def _start_mpv(items: List[Any]) -> None:
target = item
if target:
if not first_title_set and title:
cmd.append(f'--force-media-title={title}')
first_title_set = True
cmd.append(target)
if title:
# Use memory:// M3U hack to pass title
safe_title = title.replace('\n', ' ').replace('\r', '')
m3u_content = f"#EXTM3U\n#EXTINF:-1,{safe_title}\n{target}"
cmd.append(f"memory://{m3u_content}")
else:
cmd.append(target)
if len(cmd) > 3: # mpv + ipc + format + at least one file
try:
@@ -329,6 +373,16 @@ CMDLET = Cmdlet(
type="flag",
description="List items (default)"
),
CmdletArg(
name="play",
type="flag",
description="Resume playback"
),
CmdletArg(
name="pause",
type="flag",
description="Pause playback"
),
],
exec=_run
)