muvid.lyricvid.tools¶
The SSOT verbs for the lyric-video subgenre.
Plain functions, JSON-able arguments in, JSON-able dict out, and
deliberately agnostic about CLI/MCP/HTTP/agent — following ir.tools, which
muvid’s design record already names as the reference for this shape. The CLI
(python -m muvid.lyricvid), the MCP tools, the shipped skill and a
production frontend all call these, so there is one implementation and one
place a behaviour changes.
Nothing here imports a renderer, an LLM client or numpy at module scope, so
import muvid.lyricvid.tools stays cheap and safe.
Functions
|
Every installed subgenre, without importing any renderer. |
The closed vocabularies a treatment may draw on. |
|
JSON Schema for a treatment spec — also the model's output constraint. |
|
|
Measure a song's words and report what a director needs to know. |
|
Propose |
|
Validate a treatment, and return the repaired version alongside. |
|
Render a lyric video. |
|
Write one caption file per language for a saved timing (muvid#145). |
- muvid.lyricvid.tools.analyze_song(audio, *, lyrics=None, subtitles=None, project=None, aligner=None, max_lines=40)[source]¶
Measure a song’s words and report what a director needs to know.
Returns the section/line structure, the duration, the words-per-second the treatment has to keep up with, and — importantly — whether the word times were measured or interpolated from line times. A caller that ignores that flag will ship a video that looks subtly out of sync.
- muvid.lyricvid.tools.catalog()[source]¶
Every installed subgenre, without importing any renderer.
>>> c = catalog() >>> 'lyric-video' in [s['slug'] for s in c['subgenres']] True
- muvid.lyricvid.tools.export_captions(timed_text, output_dir, tracks, *, offset_s=0.0, lead_s=None, min_s=None, tail_s=None, stem='captions', fmt='srt')[source]¶
Write one caption file per language for a saved timing (muvid#145).
timed_textis a TimedText JSON file (e.g.glyphs’ output);tracksmaps a BCP-47 tag to a named transform ("hepburn","original") or a{line text: caption}mapping.offset_sshifts every caption — by a title card put in front of the video, say. Returns{"tracks": {language: {"path", "n_captions"}}}; each path goes straight intoyb.youtube.CaptionTrack(path, language).
- muvid.lyricvid.tools.propose_treatments(audio, *, lyrics=None, subtitles=None, project=None, n=3, title='', reference_image=None, use_llm=False, model=None)[source]¶
Propose
ntreatments, ranked, each with its rationale.use_llm=False(the default) runs the heuristic director: no network, no API key, no cost.use_llm=Trueasks a model, and the returned payload then carries acostblock — unknown cost is reported as unknown, never as zero.
- muvid.lyricvid.tools.render_lyric_video(audio, output, *, lyrics=None, subtitles=None, project=None, timed_text=None, treatment=None, renderer='auto', title='', persona=None, aligner=None, width=1920, height=1080, fps=30, workdir=None, captions=None)[source]¶
Render a lyric video. The one verb that produces a file.
captions({language: transform}, or that as JSON) also writes one.srtper language beside it — seeexport_captions().Everything else in this module exists so that a caller can decide what to render before paying for it.
- muvid.lyricvid.tools.treatment_schema()[source]¶
JSON Schema for a treatment spec — also the model’s output constraint.
>>> treatment_schema()['type'] 'object'
- muvid.lyricvid.tools.validate_treatment(treatment)[source]¶
Validate a treatment, and return the repaired version alongside.
A treatment that is nearly right is repaired rather than rejected, because a mechanical substitution renders something good now where a retry costs a round trip and may fail the same way. Every substitution is reported.
>>> r = validate_treatment({'scenes': [{'archetype': 'swirl'}]}) >>> r['valid'], r['repairs'] (False, ["scenes[0].archetype 'swirl' -> 'one_word_centred'"])