diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c6e1d1ab..d85d5973b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- The API host (e.g. `http://localhost:8409`)
- The build id (a UUID string that is required on all API calls)
- The playout build mode (e.g. `reset` or `continue`, normally only used for specific logic when resetting a playout)
+ - Custom arguments can be included in the `Scripted Schedule` field in the playout editor
+ - Custom arguments will be passed *after* required arguments
+ - For example, a `Scripted Schedule` of `/home/jason/schedule.sh "party central" 23` will be executed like
+ - `/home/jason/schedule.sh http://localhost:8409 00000000-0000...0000 reset "party central" 23`
+ - This enables wrapper script re-use across multiple scripted schedules
## [25.5.0] - 2025-09-01
### Added
diff --git a/ErsatzTV.Core/ErsatzTV.Core.csproj b/ErsatzTV.Core/ErsatzTV.Core.csproj
index 47b091395..42185a219 100644
--- a/ErsatzTV.Core/ErsatzTV.Core.csproj
+++ b/ErsatzTV.Core/ErsatzTV.Core.csproj
@@ -31,6 +31,7 @@
+
diff --git a/ErsatzTV.Core/Scheduling/ScriptedScheduling/ScriptedPlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/ScriptedScheduling/ScriptedPlayoutBuilder.cs
index 6d62c25c5..6cf5616ee 100644
--- a/ErsatzTV.Core/Scheduling/ScriptedScheduling/ScriptedPlayoutBuilder.cs
+++ b/ErsatzTV.Core/Scheduling/ScriptedScheduling/ScriptedPlayoutBuilder.cs
@@ -1,3 +1,4 @@
+using System.CommandLine.Parsing;
using CliWrap;
using CliWrap.Buffered;
using ErsatzTV.Core.Domain;
@@ -30,15 +31,35 @@ public class ScriptedPlayoutBuilder(
try
{
- if (!localFileSystem.FileExists(playout.ScheduleFile))
+ var args = CommandLineParser.SplitCommandLine(playout.ScheduleFile).ToList();
+
+ string scriptFile = args[0];
+ string[] scriptArgs = args.Skip(1).ToArray();
+
+ if (!localFileSystem.FileExists(scriptFile))
{
logger.LogError(
"Cannot build scripted playout; schedule file {File} does not exist",
- playout.ScheduleFile);
+ scriptFile);
return result;
}
- logger.LogInformation("Building scripted playout with id {BuildId} ...", buildId);
+ var arguments = new List
+ {
+ $"http://localhost:{Settings.UiPort}",
+ buildId.ToString(),
+ mode.ToString().ToLowerInvariant()
+ };
+
+ if (scriptArgs.Length > 0)
+ {
+ arguments.AddRange(scriptArgs);
+ }
+
+ logger.LogInformation(
+ "Building scripted playout {Script} with arguments {Arguments}",
+ scriptFile,
+ arguments);
int daysToBuild = await GetDaysToBuild(cancellationToken);
DateTimeOffset finish = start.AddDays(daysToBuild);
@@ -54,13 +75,8 @@ public class ScriptedPlayoutBuilder(
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token);
- Command command = Cli.Wrap(playout.ScheduleFile)
- .WithArguments(
- [
- $"http://localhost:{Settings.UiPort}",
- buildId.ToString(),
- mode.ToString().ToLowerInvariant()
- ])
+ Command command = Cli.Wrap(scriptFile)
+ .WithArguments(arguments)
.WithValidation(CommandResultValidation.None);
var commandResult = await command.ExecuteBufferedAsync(linkedCts.Token);