huge refactor of the entire codebase, with the goal of improving maintainability, readability, and extensibility. This commit includes changes to almost every file in the project, including:

This commit is contained in:
2026-04-19 00:41:09 -07:00
parent d9e736172a
commit bafd37fdfb
50 changed files with 3258 additions and 4177 deletions
+126 -79
View File
@@ -1505,9 +1505,9 @@ class PipelineExecutor:
"table") else None
)
# Prefer an explicit provider hint from table metadata when available.
# Prefer an explicit plugin 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 tidal.album).
# plugin key (or when they carry a table-type like tidal.album).
try:
meta = (
current_table.get_table_metadata()
@@ -1517,56 +1517,58 @@ class PipelineExecutor:
except Exception:
meta = None
if isinstance(meta, dict):
_add(meta.get("plugin"))
_add(meta.get("provider"))
except Exception:
logger.exception("Failed to inspect current_table/table metadata in _maybe_run_class_selector")
for item in selected_items or []:
if isinstance(item, dict):
_add(item.get("plugin"))
_add(item.get("provider"))
_add(item.get("store"))
_add(item.get("table"))
else:
_add(getattr(item, "plugin", None))
_add(getattr(item, "provider", None))
_add(getattr(item, "store", None))
_add(getattr(item, "table", None))
try:
from ProviderCore.registry import get_provider, is_known_provider_name
from ProviderCore.registry import get_plugin, is_known_plugin_name
except Exception:
get_provider = None # type: ignore
is_known_provider_name = None # type: ignore
get_plugin = None # type: ignore
is_known_plugin_name = None # type: ignore
# If we have a table-type like "tidal.album", also try its provider prefix ("tidal")
# when that prefix is a registered provider name.
if is_known_provider_name is not None:
# If we have a table-type like "tidal.album", also try its plugin prefix ("tidal")
# when that prefix is a registered plugin name.
if is_known_plugin_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):
if is_known_plugin_name(key):
continue
prefix = str(key).split(".", 1)[0].strip().lower()
if prefix and is_known_provider_name(prefix):
if prefix and is_known_plugin_name(prefix):
_add(prefix)
except Exception:
logger.exception("Failed while computing provider prefix heuristics in _maybe_run_class_selector")
logger.exception("Failed while computing plugin prefix heuristics in _maybe_run_class_selector")
if get_provider is not None:
if get_plugin is not None:
for key in candidates:
try:
if is_known_provider_name is not None and (
not is_known_provider_name(key)):
if is_known_plugin_name is not None and (
not is_known_plugin_name(key)):
continue
except Exception:
# If the predicate fails for any reason, fall back to legacy behavior.
logger.exception("is_known_provider_name predicate failed for key %s; falling back", key)
logger.exception("is_known_plugin_name predicate failed for key %s; falling back", key)
try:
provider = get_provider(key, config)
provider = get_plugin(key, config)
except Exception as exc:
logger.exception("Failed to load provider '%s' during selector resolution: %s", key, exc)
logger.exception("Failed to load plugin '%s' during selector resolution: %s", key, exc)
continue
selector = getattr(provider, "selector", None)
if selector is None:
@@ -1583,6 +1585,92 @@ class PipelineExecutor:
if handled:
return True
@staticmethod
def _maybe_expand_plugin_selection(
selected_items: List[Any],
*,
ctx: Any,
config: Dict[str, Any],
stage_table: Any,
) -> Optional[List[Any]]:
candidates: list[str] = []
def _add(value: Any) -> None:
text = str(value or "").strip().lower()
if text and text not in candidates:
candidates.append(text)
table_type = None
try:
table_type = stage_table.table if stage_table is not None and hasattr(stage_table, "table") else None
except Exception:
table_type = None
_add(table_type)
try:
meta = (
stage_table.get_table_metadata()
if stage_table is not None and hasattr(stage_table, "get_table_metadata")
else getattr(stage_table, "table_metadata", None)
)
except Exception:
meta = None
if isinstance(meta, dict):
_add(meta.get("plugin"))
_add(meta.get("provider"))
for item in selected_items or []:
if isinstance(item, dict):
_add(item.get("plugin"))
_add(item.get("provider"))
_add(item.get("table"))
_add(item.get("source"))
else:
_add(getattr(item, "plugin", None))
_add(getattr(item, "provider", None))
_add(getattr(item, "table", None))
_add(getattr(item, "source", None))
try:
from ProviderCore.registry import get_plugin, is_known_plugin_name
except Exception:
return None
for key in list(candidates):
if "." in key:
prefix = str(key).split(".", 1)[0].strip().lower()
if prefix and prefix not in candidates:
candidates.append(prefix)
for key in candidates:
try:
if not is_known_plugin_name(key):
continue
except Exception:
continue
try:
plugin = get_plugin(key, config)
except Exception:
continue
if plugin is None:
continue
expand = getattr(plugin, "expand_selection", None)
if not callable(expand):
continue
try:
expanded = expand(
selected_items,
ctx=ctx,
stage_is_last=False,
table_type=str(table_type or ""),
)
except Exception:
logger.exception("%s expand_selection failed", key)
return None
if expanded:
return list(expanded)
return None
store_keys: list[str] = []
for item in selected_items or []:
if isinstance(item, dict):
@@ -1998,10 +2086,10 @@ class PipelineExecutor:
# IMPORTANT: Put selected row args *before* source_args.
# Rationale: The cmdlet argument parser treats the *first* unknown
# token as a positional value (e.g., URL). If `source_args`
# contain unknown flags (like -provider which download-file does
# contain unknown flags (like a removed legacy flag that download-file does
# not declare), they could be misinterpreted as the positional
# URL argument and cause attempts to download strings like
# "-provider" (which is invalid). By placing selection args
# not accept). By placing selection args
# first we ensure the intended URL/selection token is parsed
# as the positional URL and avoid this class of parsing errors.
expanded_stage: List[str] = cmd_list + selected_row_args + source_args
@@ -2081,66 +2169,15 @@ class PipelineExecutor:
print("No items matched selection in pipeline\n")
return False, None
# Provider selection expansion (non-terminal): allow certain provider tables
# (e.g. tidal.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
if stages:
expanded = PipelineExecutor._maybe_expand_plugin_selection(
filtered,
ctx=ctx,
config=config,
stage_table=stage_table,
)
except Exception:
table_type_hint = None
if stages and isinstance(table_type_hint, str) and table_type_hint.strip().lower() == "tidal.album":
try:
from ProviderCore.registry import get_provider
prov = get_provider("tidal", 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:
logger.exception("Failed to extract/parse track metadata in album processing")
track_items.append(tr)
if track_items:
filtered = track_items
table_type_hint = "tidal.track"
if expanded:
filtered = expanded
if PipelineExecutor._maybe_run_class_selector(
ctx,
@@ -2177,6 +2214,16 @@ class PipelineExecutor:
except Exception:
logger.exception("Failed to determine current_table for selection auto-insert; defaulting to None")
current_table = None
table_type_hint = None
try:
raw_table_type = (
stage_table.table
if stage_table is not None and hasattr(stage_table, "table") else None
)
if isinstance(raw_table_type, str) and raw_table_type.strip():
table_type_hint = raw_table_type
except Exception:
table_type_hint = None
table_type = None
try:
if isinstance(table_type_hint, str) and table_type_hint.strip():