h
This commit is contained in:
163
CLI.py
163
CLI.py
@@ -2168,6 +2168,20 @@ class PipelineExecutor:
|
||||
table if current_table and hasattr(current_table,
|
||||
"table") else None
|
||||
)
|
||||
|
||||
# Prefer an explicit provider hint from table metadata when available.
|
||||
# This keeps @N selectors working even when row payloads don't carry a
|
||||
# provider key (or when they carry a table-type like hifi.album).
|
||||
try:
|
||||
meta = (
|
||||
current_table.get_table_metadata()
|
||||
if current_table is not None and hasattr(current_table, "get_table_metadata")
|
||||
else getattr(current_table, "table_metadata", None)
|
||||
)
|
||||
except Exception:
|
||||
meta = None
|
||||
if isinstance(meta, dict):
|
||||
_add(meta.get("provider"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -2187,6 +2201,23 @@ class PipelineExecutor:
|
||||
get_provider = None # type: ignore
|
||||
is_known_provider_name = None # type: ignore
|
||||
|
||||
# If we have a table-type like "hifi.album", also try its provider prefix ("hifi")
|
||||
# when that prefix is a registered provider name.
|
||||
if is_known_provider_name is not None:
|
||||
try:
|
||||
for key in list(candidates):
|
||||
if not isinstance(key, str):
|
||||
continue
|
||||
if "." not in key:
|
||||
continue
|
||||
if is_known_provider_name(key):
|
||||
continue
|
||||
prefix = str(key).split(".", 1)[0].strip().lower()
|
||||
if prefix and is_known_provider_name(prefix):
|
||||
_add(prefix)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if get_provider is not None:
|
||||
for key in candidates:
|
||||
try:
|
||||
@@ -2401,15 +2432,37 @@ class PipelineExecutor:
|
||||
if not selection_indices:
|
||||
return True, None
|
||||
|
||||
# Selection should operate on the *currently displayed* selectable table.
|
||||
# Some navigation flows (e.g. @.. back) can show a display table without
|
||||
# updating current_stage_table. Provider selectors rely on current_stage_table
|
||||
# to detect table type (e.g. hifi.album -> tracks), so sync it here.
|
||||
display_table = None
|
||||
try:
|
||||
if not ctx.get_current_stage_table_source_command():
|
||||
display_table = (
|
||||
ctx.get_display_table() if hasattr(ctx,
|
||||
"get_display_table") else None
|
||||
display_table = (
|
||||
ctx.get_display_table() if hasattr(ctx, "get_display_table") else None
|
||||
)
|
||||
except Exception:
|
||||
display_table = None
|
||||
|
||||
current_stage_table = None
|
||||
try:
|
||||
current_stage_table = (
|
||||
ctx.get_current_stage_table()
|
||||
if hasattr(ctx, "get_current_stage_table") else None
|
||||
)
|
||||
except Exception:
|
||||
current_stage_table = None
|
||||
|
||||
try:
|
||||
if display_table is not None and hasattr(ctx, "set_current_stage_table"):
|
||||
ctx.set_current_stage_table(display_table)
|
||||
elif current_stage_table is None and hasattr(ctx, "set_current_stage_table"):
|
||||
last_table = (
|
||||
ctx.get_last_result_table()
|
||||
if hasattr(ctx, "get_last_result_table") else None
|
||||
)
|
||||
table_for_stage = display_table or ctx.get_last_result_table()
|
||||
if table_for_stage:
|
||||
ctx.set_current_stage_table(table_for_stage)
|
||||
if last_table is not None:
|
||||
ctx.set_current_stage_table(last_table)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -2600,6 +2653,67 @@ class PipelineExecutor:
|
||||
print("No items matched selection in pipeline\n")
|
||||
return False, None
|
||||
|
||||
# Provider selection expansion (non-terminal): allow certain provider tables
|
||||
# (e.g. hifi.album) to expand to multiple downstream items when the user
|
||||
# pipes into another stage (e.g. @N | .mpv or @N | add-file).
|
||||
table_type_hint = None
|
||||
try:
|
||||
table_type_hint = (
|
||||
stage_table.table
|
||||
if stage_table is not None and hasattr(stage_table, "table")
|
||||
else None
|
||||
)
|
||||
except Exception:
|
||||
table_type_hint = None
|
||||
|
||||
if stages and isinstance(table_type_hint, str) and table_type_hint.strip().lower() == "hifi.album":
|
||||
try:
|
||||
from ProviderCore.registry import get_provider
|
||||
|
||||
prov = get_provider("hifi", config)
|
||||
except Exception:
|
||||
prov = None
|
||||
|
||||
if prov is not None and hasattr(prov, "_extract_album_selection_context") and hasattr(prov, "_tracks_for_album"):
|
||||
try:
|
||||
album_contexts = prov._extract_album_selection_context(filtered) # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
album_contexts = []
|
||||
|
||||
track_items: List[Any] = []
|
||||
seen_track_ids: set[int] = set()
|
||||
for album_id, album_title, artist_name in album_contexts or []:
|
||||
try:
|
||||
track_results = prov._tracks_for_album( # type: ignore[attr-defined]
|
||||
album_id=album_id,
|
||||
album_title=album_title,
|
||||
artist_name=artist_name,
|
||||
limit=500,
|
||||
)
|
||||
except Exception:
|
||||
track_results = []
|
||||
for tr in track_results or []:
|
||||
try:
|
||||
md = getattr(tr, "full_metadata", None)
|
||||
tid = None
|
||||
if isinstance(md, dict):
|
||||
raw_id = md.get("trackId") or md.get("id")
|
||||
try:
|
||||
tid = int(raw_id) if raw_id is not None else None
|
||||
except Exception:
|
||||
tid = None
|
||||
if tid is not None:
|
||||
if tid in seen_track_ids:
|
||||
continue
|
||||
seen_track_ids.add(tid)
|
||||
except Exception:
|
||||
pass
|
||||
track_items.append(tr)
|
||||
|
||||
if track_items:
|
||||
filtered = track_items
|
||||
table_type_hint = "hifi.track"
|
||||
|
||||
if PipelineExecutor._maybe_run_class_selector(
|
||||
ctx,
|
||||
config,
|
||||
@@ -2634,11 +2748,20 @@ class PipelineExecutor:
|
||||
current_table = ctx.get_last_result_table()
|
||||
except Exception:
|
||||
current_table = None
|
||||
table_type = (
|
||||
current_table.table
|
||||
if current_table and hasattr(current_table,
|
||||
"table") else None
|
||||
)
|
||||
table_type = None
|
||||
try:
|
||||
if isinstance(table_type_hint, str) and table_type_hint.strip():
|
||||
table_type = table_type_hint
|
||||
else:
|
||||
table_type = (
|
||||
current_table.table
|
||||
if current_table and hasattr(current_table, "table") else None
|
||||
)
|
||||
except Exception:
|
||||
table_type = (
|
||||
current_table.table
|
||||
if current_table and hasattr(current_table, "table") else None
|
||||
)
|
||||
|
||||
def _norm_cmd(name: Any) -> str:
|
||||
return str(name or "").replace("_", "-").strip().lower()
|
||||
@@ -2981,11 +3104,27 @@ class PipelineExecutor:
|
||||
display_table = None
|
||||
|
||||
stage_table = ctx.get_current_stage_table()
|
||||
# Selection should operate on the table the user sees.
|
||||
# If a display overlay table exists, force it as the current-stage table
|
||||
# so provider selectors (e.g. hifi.album -> tracks) behave consistently.
|
||||
try:
|
||||
if display_table is not None and hasattr(ctx, "set_current_stage_table"):
|
||||
ctx.set_current_stage_table(display_table)
|
||||
stage_table = display_table
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not stage_table and display_table is not None:
|
||||
stage_table = display_table
|
||||
if not stage_table:
|
||||
stage_table = ctx.get_last_result_table()
|
||||
|
||||
try:
|
||||
if hasattr(ctx, "debug_table_state"):
|
||||
ctx.debug_table_state(f"selection {selection_token}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if display_table is not None and stage_table is display_table:
|
||||
items_list = ctx.get_last_result_items() or []
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user