feat: add a {{channel:number}} variable for remote source urls - #216
Open
Ministorm3 wants to merge 2 commits into
Open
feat: add a {{channel:number}} variable for remote source urls#216Ministorm3 wants to merge 2 commits into
Ministorm3 wants to merge 2 commits into
Conversation
A playout item's remote source uri is fixed apart from {{ENV_VAR}}
expansion, which resolves from the server environment and so produces the
same string for every channel. A uri that should differ per channel has to
be written out per channel.
Add {{channel:number}}, resolved at playback to the channel being
transcoded, for http and rtsp source uris.
The new form shares the {{ }} delimiters with environment templates and is
told apart by its namespace prefix. That is safe because a name containing
a colon is not a valid environment variable name, so expand_template
re-emits it verbatim instead of resolving or rejecting it. This pass runs
second and claims what the first pass left behind. A test pins that
contract, since the whole design rests on it.
Reusing the delimiters avoids a second convention. It also avoids the trap
where {{channel_number}} reads as the natural spelling but fails as a
missing environment variable.
The value comes from the lineup and is substituted verbatim. Nothing here
reads anything a request carries.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ministorm3
marked this pull request as ready for review
August 16, 2026 01:18
Ministorm3
marked this pull request as draft
August 17, 2026 21:15
Ministorm3
marked this pull request as ready for review
August 27, 2026 16:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
A remote source URI can contain
{{channel:number}}. The channel worker replaces it at playback with the number of the channel it is transcoding.On channel 30 that opens
http://origin.lan:8000/30/stream.m3u8. One playout item now serves a whole lineup. Today the same item has to be written once per channel with a literal URI.Why
A source URI supports only
{{VAR}}, whichexpand_templatereads from the server environment. Every channel gets the same string back, so the URIs differ only by a number the server already knows.The syntax matters more than this one variable. I have further features in progress that need to put server-known values into remote stream URIs. They should all use one convention, and settling its shape is what I am really asking for here.
Design
There is one delimiter,
{{ }}. What sits inside it decides who resolves it.{{MY_SECRET}}{{channel:number}}{{query:region}}A colon means the name is namespaced and the server owns it. No colon means it is an environment variable, and nothing about those changes.
Sharing the delimiter is safe because of how
expand_templatealready behaves. A name that failsis_valid_var_nameis written to the output unchanged, neither resolved nor rejected. A colon fails that check, so the environment pass walks past{{channel:number}}and the new pass claims it. That is behavior rather than a documented contract, so one test sends a URI through both passes in order.The alternative was a second delimiter,
{ }or[[ ]]. It works, but it leaves two conventions and only history to say which one a variable uses.The namespace also removes a trap.
{{channel_number}}reads like the correct spelling, and it would fail as a missing environment variable.The new pass runs on http and rtsp URIs only.
Values are substituted with no escaping, and nothing bounds which part of the URI a value can change. That is acceptable only because the operator writes the channel number. A value from a less trusted source needs percent-encoding and an origin rule, which the function documents.
Compatibility
On current main,
{{name:with:colons}}is written to the output as written, so no working URI uses this syntax today. No field is added.Cost
No new dependency. One public function, 23 lines plus tests.
Verification
cargo test --workspacepasses 126 tests, 12 of them in the new module. Clippy with-D clippy::allandcargo +nightly fmt --all -- --checkare clean.I ran nine mutations. Seven break one decision each, and each killed only the tests that cover that decision. The other two break copied text rather than substituted text, and killed eleven and nine of the twelve tests.
empty_input_stays_emptysurvives all nine, because it guards an edge case rather than a decision.It is also running successfully in my production box today.
Open questions
Is the shared delimiter right? It rests on
expand_templatepassing unknown names through. A test holds that, but you may prefer the two syntaxes kept apart. This is the answer my later features are waiting on.Is
channel:numberthe right name? It leaves room for more channel attributes later. A flat{{channel_number}}is not available, since that is a valid environment variable name.Is
ersatztv-playoutthe right home? The playout declares the templates. The alternative is the channel worker, the only caller today.