updating and refining plugin system refactor
This commit is contained in:
+59
-12
@@ -724,7 +724,7 @@ class Table:
|
||||
"""Table type (e.g., 'youtube', 'soulseek') for context-aware selection logic."""
|
||||
|
||||
self.table_metadata: Dict[str, Any] = {}
|
||||
"""Optional provider/table metadata (e.g., provider name, view)."""
|
||||
"""Optional plugin/table metadata (e.g., plugin name, view)."""
|
||||
|
||||
self.value_case: str = "preserve"
|
||||
"""Display-only value casing: 'lower', 'upper', or 'preserve' (default)."""
|
||||
@@ -754,12 +754,12 @@ class Table:
|
||||
return self
|
||||
|
||||
def set_table_metadata(self, metadata: Optional[Dict[str, Any]]) -> "Table":
|
||||
"""Attach provider/table metadata for downstream selection logic."""
|
||||
"""Attach plugin/table metadata for downstream selection logic."""
|
||||
self.table_metadata = dict(metadata or {})
|
||||
return self
|
||||
|
||||
def get_table_metadata(self) -> Dict[str, Any]:
|
||||
"""Return attached provider/table metadata (copy to avoid mutation)."""
|
||||
"""Return attached plugin/table metadata (copy to avoid mutation)."""
|
||||
try:
|
||||
return dict(self.table_metadata)
|
||||
except Exception:
|
||||
@@ -2223,6 +2223,34 @@ def extract_item_metadata(item: Any) -> Dict[str, Any]:
|
||||
return {}
|
||||
|
||||
out = {}
|
||||
|
||||
def _merge_columns(columns_value: Any) -> None:
|
||||
if not isinstance(columns_value, (list, tuple)):
|
||||
return
|
||||
for column in columns_value:
|
||||
label = None
|
||||
value = None
|
||||
if isinstance(column, (list, tuple)) and len(column) >= 2:
|
||||
label, value = column[0], column[1]
|
||||
elif isinstance(column, dict):
|
||||
label = column.get("name") or column.get("label") or column.get("key")
|
||||
value = column.get("value")
|
||||
else:
|
||||
label = getattr(column, "name", None)
|
||||
value = getattr(column, "value", None)
|
||||
|
||||
label_text = str(label or "").strip()
|
||||
if not label_text or value is None:
|
||||
continue
|
||||
|
||||
value_text = str(value).strip()
|
||||
if not value_text:
|
||||
continue
|
||||
|
||||
normalized = label_text.lower()
|
||||
if any(str(existing or "").strip().lower() == normalized for existing in out):
|
||||
continue
|
||||
out[label_text] = value_text
|
||||
|
||||
# Handle ResultModel specifically for better detail display
|
||||
if ResultModel is not None and isinstance(item, ResultModel):
|
||||
@@ -2231,6 +2259,7 @@ def extract_item_metadata(item: Any) -> Dict[str, Any]:
|
||||
if item.ext: out["Ext"] = item.ext
|
||||
if item.size_bytes: out["Size"] = format_mb(item.size_bytes)
|
||||
if item.source: out["Store"] = item.source
|
||||
_merge_columns(getattr(item, "columns", None))
|
||||
|
||||
# Merge internal metadata dict
|
||||
if item.metadata:
|
||||
@@ -2256,6 +2285,7 @@ def extract_item_metadata(item: Any) -> Dict[str, Any]:
|
||||
# Fallback to existing extraction logic for legacy objects/dicts
|
||||
# Convert once and reuse throughout to avoid repeated _as_dict() calls
|
||||
data = _as_dict(item) or {}
|
||||
_merge_columns(data.get("columns"))
|
||||
|
||||
# Use existing extractors from match-standard result table columns
|
||||
title = extract_title_value(item)
|
||||
@@ -2350,12 +2380,14 @@ class ItemDetailView(Table):
|
||||
item_metadata: Optional[Dict[str, Any]] = None,
|
||||
detail_title: Optional[str] = None,
|
||||
exclude_tags: bool = False,
|
||||
detail_order: Optional[List[str]] = None,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(title, **kwargs)
|
||||
self.item_metadata = item_metadata or {}
|
||||
self.detail_title = detail_title
|
||||
self.exclude_tags = exclude_tags
|
||||
self.detail_order = [str(value) for value in (detail_order or []) if str(value or "").strip()]
|
||||
|
||||
def to_rich(self):
|
||||
"""Render the item details panel above the standard results table."""
|
||||
@@ -2406,8 +2438,26 @@ class ItemDetailView(Table):
|
||||
|
||||
return Group(*renderables)
|
||||
|
||||
# Canonical display order for metadata
|
||||
order = ["Title", "Hash", "Store", "Path", "Ext", "Size", "Duration", "Url", "Relations"]
|
||||
def _has_renderable_value(value: Any) -> bool:
|
||||
if value is None:
|
||||
return False
|
||||
if isinstance(value, str):
|
||||
text = value.strip()
|
||||
return bool(text and text.lower() not in {"<null>", "null", "none"})
|
||||
if isinstance(value, (list, tuple, set)):
|
||||
return any(_has_renderable_value(item) for item in value)
|
||||
return True
|
||||
|
||||
# Canonical display order for metadata; plugin-specific detail views can
|
||||
# prepend a preferred order without needing to reimplement rendering.
|
||||
order: List[str] = []
|
||||
seen_order: set[str] = set()
|
||||
for key in list(self.detail_order or []) + ["Title", "Hash", "Store", "Path", "Ext", "Size", "Duration", "Url", "Relations"]:
|
||||
normalized = str(key or "").strip().lower()
|
||||
if not normalized or normalized in seen_order:
|
||||
continue
|
||||
seen_order.add(normalized)
|
||||
order.append(str(key))
|
||||
|
||||
has_details = False
|
||||
# Add ordered items first
|
||||
@@ -2431,19 +2481,16 @@ class ItemDetailView(Table):
|
||||
else:
|
||||
val = "\n".join([f"[dim]→[/dim] {r}" for r in val])
|
||||
|
||||
if val is not None and val != "":
|
||||
if _has_renderable_value(val):
|
||||
details_table.add_row(f"{key}:", str(val))
|
||||
has_details = True
|
||||
elif key in ["Url", "Relations", "Ext"]:
|
||||
# Show <null> for these important identifier fields if blank
|
||||
details_table.add_row(f"{key}:", "[dim]<null>[/dim]")
|
||||
has_details = True
|
||||
|
||||
# Add any remaining metadata not in the canonical list
|
||||
ordered_keys = {x.lower() for x in order}
|
||||
for k, v in self.item_metadata.items():
|
||||
k_norm = k.lower()
|
||||
if k_norm not in [x.lower() for x in order] and v and k_norm not in ["tags", "tag"]:
|
||||
label = k.capitalize() if len(k) > 1 else k.upper()
|
||||
if k_norm not in ordered_keys and _has_renderable_value(v) and k_norm not in ["tags", "tag"]:
|
||||
label = str(k or "")
|
||||
details_table.add_row(f"{label}:", str(v))
|
||||
has_details = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user