narraoke has two entry points, split by how the source is rendered:
|
Input |
Rendering |
narraoke |
structured markdown |
styled HTML, screenshotted by a headless browser — keeps code blocks, tables, typography |
narraoke-article |
a URL, text file, or pasted prose |
text drawn onto generated frames with PIL — no browser, no structure assumed |
They share utils, tts_engine, and timing. What differs is the front end (fetch + extract vs. read a local file) and the renderer, and the renderers are genuinely incompatible: one needs a DOM to screenshot, the other needs no structure at all.
Today the user picks by choosing a command. That is a decision they should not have to make — the input usually implies the answer.
Proposal
One narraoke entry point that inspects the input and dispatches, with an override for when the guess is wrong.
Detection, in order
- Looks like a URL (
http://, https://) → fetch, extract, plain renderer.
- HTML — by extension, or by content sniffing → extract, plain renderer.
article_to_video._looks_like_html already does this and can move somewhere shared.
- Markdown with structure —
.md and the parse finds headings, code blocks, or tables → rich renderer.
- Anything else —
.txt, bare prose, a .md with no structure → plain renderer.
Step 3 is the interesting one: extension alone is not enough, because a .md file that is one long paragraph gains nothing from a browser screenshot and costs a Chromium round trip to find that out. The existing load_narration_blocks already classifies blocks by kind, so the signal is available before any rendering happens.
Override
--renderer rich|plain forces the choice. Needed for two reasons: a wrong guess should be recoverable without restructuring the document, and a user comparing the two renderers on the same input should be able to.
Behaviour to preserve
narraoke-article keeps working, or is aliased, so existing invocations do not break.
- The
article extra stays optional. A rich-renderer run must not require the extraction stack; detection has to fail gracefully when it is absent — if a URL is passed without the extra installed, say so rather than raising an ImportError.
- Both renderers stay. This is a dispatch change, not a consolidation of rendering code.
Open questions
- Should detection be reported in the run summary? Probably yes — "why did it pick the plain renderer?" is the obvious first support question.
- What happens with a structured markdown file passed to the plain renderer via
--renderer plain? Presumably strip the markup and narrate the text, but the fenced-code handling needs thought.
- Is there a case for a third mode where a URL is fetched and then rendered richly? The extracted HTML could in principle be screenshotted. Out of scope here, but worth not designing it out.
Not doing
Merging the renderers themselves. They solve different problems and both are needed regardless.
narraoke has two entry points, split by how the source is rendered:
narraokenarraoke-articleThey share
utils,tts_engine, andtiming. What differs is the front end (fetch + extract vs. read a local file) and the renderer, and the renderers are genuinely incompatible: one needs a DOM to screenshot, the other needs no structure at all.Today the user picks by choosing a command. That is a decision they should not have to make — the input usually implies the answer.
Proposal
One
narraokeentry point that inspects the input and dispatches, with an override for when the guess is wrong.Detection, in order
http://,https://) → fetch, extract, plain renderer.article_to_video._looks_like_htmlalready does this and can move somewhere shared..mdand the parse finds headings, code blocks, or tables → rich renderer..txt, bare prose, a.mdwith no structure → plain renderer.Step 3 is the interesting one: extension alone is not enough, because a
.mdfile that is one long paragraph gains nothing from a browser screenshot and costs a Chromium round trip to find that out. The existingload_narration_blocksalready classifies blocks by kind, so the signal is available before any rendering happens.Override
--renderer rich|plainforces the choice. Needed for two reasons: a wrong guess should be recoverable without restructuring the document, and a user comparing the two renderers on the same input should be able to.Behaviour to preserve
narraoke-articlekeeps working, or is aliased, so existing invocations do not break.articleextra stays optional. A rich-renderer run must not require the extraction stack; detection has to fail gracefully when it is absent — if a URL is passed without the extra installed, say so rather than raising an ImportError.Open questions
--renderer plain? Presumably strip the markup and narrate the text, but the fenced-code handling needs thought.Not doing
Merging the renderers themselves. They solve different problems and both are needed regardless.