Files
Medios-Macina/docs/result_table.md
T

185 lines
5.6 KiB
Markdown
Raw Normal View History

2026-05-16 15:26:08 -07:00
# ResultTable system: overview and usage
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
This document explains the `ResultTable` system used across the CLI: how tables
are built, how plugins integrate with them, and how `@N` selection, row replay,
and plugin selectors work.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
## TL;DR
- `ResultTable` is the unified object used to render tabular results and drive `@N` behavior.
- Plugins return `SearchResult` objects or dicts and can either supply row selection args or implement a `selector()` method.
- Rows can also carry an explicit `selection_action`, which the CLI replays verbatim.
- Table metadata helps plugins attach context. Some metadata keys still use older `provider` names internally.
2026-01-01 20:37:27 -08:00
---
## Key concepts
2026-05-16 15:26:08 -07:00
### ResultTable
`SYS/result_table.py` renders rows as a rich table and stores metadata used for
selection expansion.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
Important APIs:
- `add_result()`
- `set_table()`
- `set_source_command()`
- `set_row_selection_args()`
- `set_row_selection_action()`
- `set_table_metadata()`
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
### ResultRow
A row holds columns, payload data, selection args, and optionally a full
`selection_action` token list. When `selection_action` is present, `@N` uses it
instead of reconstructing a command from the source command and row args.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
### Plugin selector
If a plugin implements `selector(selected_items, ctx=..., stage_is_last=True)`,
that selector runs first when `@N` is used. If the selector returns `True`, it
has handled the selection, for example by publishing a nested table.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
### Table metadata
`ResultTable.set_table_metadata(dict)` attaches plugin-specific context for
selectors and follow-up stages. You will still see legacy keys such as
`provider` in some metadata because parts of the runtime still consume them.
2026-01-01 20:37:27 -08:00
---
2026-05-16 15:26:08 -07:00
## Building a table
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
Typical plugin flow:
2026-01-01 20:37:27 -08:00
```py
from SYS.result_table import ResultTable
2026-05-16 15:26:08 -07:00
table = ResultTable("Plugin: X results").set_preserve_order(True)
table.set_table("plugin_name")
table.set_table_metadata({"provider": "plugin_name", "view": "folders"})
table.set_source_command("search-file", ["-plugin", "plugin_name", "query"])
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
for result in results:
table.add_result(result)
2026-01-01 20:37:27 -08:00
ctx.set_last_result_table(table, payloads)
ctx.set_current_stage_table(table)
```
Notes:
2026-05-16 15:26:08 -07:00
- To drive a direct replay, call `table.set_row_selection_args(row_index, ["-open", "<id>"])`.
- For drill-in or interactive behavior, implement `plugin.selector()` and return `True` when handled.
- For exact row replay, call `table.set_row_selection_action(row_index, tokens)`.
2026-01-01 20:37:27 -08:00
---
2026-05-16 15:26:08 -07:00
## Selection flow
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
When a user enters `@N`:
1. The CLI chooses the active table.
2. It gathers the selected payloads.
3. `PipelineExecutor._maybe_run_class_selector()` runs plugin `selector()` hooks for the plugin inferred from the table or payloads.
4. If no selector handles the row, the CLI checks `row.selection_action` first.
5. If no explicit row action exists, the CLI expands `source_command + source_args + row_selection_args`.
6. Multi-selection results are piped downstream instead of being collapsed to one row replay.
2026-01-01 20:37:27 -08:00
---
2026-05-16 15:26:08 -07:00
## Columns and display
- Plugins can pass a `columns` list in the result dict or `SearchResult` to control column order and display.
- Otherwise, `ResultTable` uses sensible defaults.
- Rendering helpers such as `to_rich`, `format_json`, and `format_compact` support different CLI display paths.
2026-01-01 20:37:27 -08:00
---
2026-05-16 15:26:08 -07:00
## Plugin-specific examples
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
### AllDebrid
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
AllDebrid exposes a list of magnets as folder rows and the files inside each
magnet as file rows. The plugin uses `selector()` to drill into a magnet and
publish a new `ResultTable` of files.
2026-01-01 20:37:27 -08:00
Example commands:
2026-05-16 15:26:08 -07:00
```powershell
search-file -plugin alldebrid "*"
2026-05-16 15:26:08 -07:00
@3
2026-01-01 20:37:27 -08:00
```
2026-05-16 15:26:08 -07:00
Illustrative magnet row:
2026-01-01 20:37:27 -08:00
```py
SearchResult(
2026-05-16 15:26:08 -07:00
table="alldebrid",
title="My Magnet Title",
path="alldebrid:magnet:123",
media_kind="folder",
full_metadata={
"magnet_id": 123,
"provider": "alldebrid",
"provider_view": "folders",
},
2026-01-01 20:37:27 -08:00
)
```
2026-05-16 15:26:08 -07:00
Illustrative file row:
2026-01-01 20:37:27 -08:00
```py
SearchResult(
2026-05-16 15:26:08 -07:00
table="alldebrid",
title="Episode 01.mkv",
path="https://.../unlocked_direct_url",
media_kind="file",
full_metadata={
"magnet_id": 123,
"provider": "alldebrid",
"provider_view": "files",
},
2026-01-01 20:37:27 -08:00
)
```
2026-05-16 15:26:08 -07:00
Selection and download behavior:
- `@3` on a magnet row runs the plugin selector and shows a file table.
- `@2 | download-file` downloads the selected file row.
- `@1 | add-file -plugin local -instance <dest>` triggers add-file's plugin-aware handoff flow.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
Configure the AllDebrid plugin in `.config plugins` and add its API key before
testing these flows.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
### Bandcamp
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
Bandcamp search supports `artist:` queries. The Bandcamp plugin implements a
`selector()` that detects artist rows and expands them into a discography table.
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
Example:
2026-01-01 20:37:27 -08:00
2026-05-16 15:26:08 -07:00
```powershell
search-file -plugin bandcamp "artist:radiohead"
2026-01-01 20:37:27 -08:00
@1
```
2026-05-16 15:26:08 -07:00
Plugin selectors are the right tool when you need to replace one table with
another, such as artist to discography drill-in.
2026-01-01 20:37:27 -08:00
---
2026-05-16 15:26:08 -07:00
## Plugin author checklist
- Implement `search(query, limit, filters)` and return `SearchResult` objects or dicts.
- Include useful `full_metadata` values for drill-in and selection replay.
- Implement `download(result, output_dir)` when the plugin can materialize file bytes.
- Implement `selector(...)` for drill-in or interactive transforms.
- Add tests that cover search, select, and download flows.
2026-01-01 20:37:27 -08:00
---
## Debugging tips
2026-05-16 15:26:08 -07:00
- Use `ctx.set_last_result_table(table, payloads)` to publish a table while developing a selector.
- Add `log(...)` messages in plugin code to capture fail points.
- Inspect `full_metadata` when a selector or replay path is missing required context.
2026-01-01 20:37:27 -08:00
---
## Quick reference
2026-05-16 15:26:08 -07:00
- ResultTable implementation: `SYS/result_table.py`
- Pipeline helpers: `SYS/pipeline.py`
- Row replay and selection flow: `SYS/pipeline.py`
2026-05-21 16:19:17 -07:00
- Plugin authoring guide: `docs/plugin_authoring.md`