// // // To parse this JSON data, add NuGet 'System.Text.Json' then do: // // using ErsatzTV.Core.Next.Config; // // var channelConfig = ChannelConfig.FromJson(jsonString); #nullable enable #pragma warning disable CS8618 #pragma warning disable CS8601 #pragma warning disable CS8602 #pragma warning disable CS8603 namespace ErsatzTV.Core.Next.Config { using System; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; using System.Globalization; public partial class ChannelConfig { [JsonPropertyName("ffmpeg")] public Ffmpeg Ffmpeg { get; set; } [JsonPropertyName("normalization")] public Normalization Normalization { get; set; } [JsonPropertyName("playout")] public Playout Playout { get; set; } } public partial class Ffmpeg { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("disabled_filters")] public List? DisabledFilters { get; set; } [JsonPropertyName("ffmpeg_path")] public string? FfmpegPath { get; set; } [JsonPropertyName("ffprobe_path")] public string? FfprobePath { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("preferred_filters")] public List? PreferredFilters { get; set; } [JsonPropertyName("reports_folder")] public string? ReportsFolder { get; set; } } public partial class Normalization { [JsonPropertyName("audio")] public Audio Audio { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("subtitle")] public Subtitle? Subtitle { get; set; } [JsonPropertyName("video")] public Video Video { get; set; } } public partial class Audio { [JsonPropertyName("bitrate_kbps")] public long? BitrateKbps { get; set; } [JsonPropertyName("buffer_kbps")] public long? BufferKbps { get; set; } [JsonPropertyName("channels")] public long? Channels { get; set; } [JsonPropertyName("format")] public AudioFormat? Format { get; set; } [JsonPropertyName("loudness")] public LoudnessClass? Loudness { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("normalize_loudness")] public bool? NormalizeLoudness { get; set; } [JsonPropertyName("sample_rate_hz")] public long? SampleRateHz { get; set; } } public partial class LoudnessClass { [JsonPropertyName("integrated_target")] public double? IntegratedTarget { get; set; } [JsonPropertyName("range_target")] public double? RangeTarget { get; set; } [JsonPropertyName("true_peak")] public double? TruePeak { get; set; } } public partial class Subtitle { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("mode")] public Mode? Mode { get; set; } } public partial class Video { [JsonPropertyName("accel")] public AccelEnum? Accel { get; set; } [JsonPropertyName("bit_depth")] public long? BitDepth { get; set; } [JsonPropertyName("bitrate_kbps")] public long? BitrateKbps { get; set; } [JsonPropertyName("buffer_kbps")] public long? BufferKbps { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("deinterlace")] public bool? Deinterlace { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("filters")] public Filters? Filters { get; set; } [JsonPropertyName("format")] public VideoFormat? Format { get; set; } [JsonPropertyName("height")] public long? Height { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("scaling_mode")] public ScalingMode? ScalingMode { get; set; } [JsonPropertyName("vaapi_device")] public string? VaapiDevice { get; set; } [JsonPropertyName("vaapi_driver")] public VaapiDriverEnum? VaapiDriver { get; set; } [JsonPropertyName("width")] public long? Width { get; set; } } public partial class Filters { [JsonPropertyName("bwdif")] public BwdifClass? Bwdif { get; set; } [JsonPropertyName("bwdif_cuda")] public BwdifCudaClass? BwdifCuda { get; set; } [JsonPropertyName("deinterlace_qsv")] public DeinterlaceQsvClass? DeinterlaceQsv { get; set; } [JsonPropertyName("deinterlace_vaapi")] public DeinterlaceVaapiClass? DeinterlaceVaapi { get; set; } [JsonPropertyName("libplacebo")] public LibplaceboClass? Libplacebo { get; set; } [JsonPropertyName("tonemap")] public TonemapClass? Tonemap { get; set; } [JsonPropertyName("tonemap_opencl")] public TonemapOpenclClass? TonemapOpencl { get; set; } [JsonPropertyName("w3fdif")] public W3FdifClass? W3Fdif { get; set; } [JsonPropertyName("yadif")] public YadifClass? Yadif { get; set; } [JsonPropertyName("yadif_cuda")] public YadifCudaClass? YadifCuda { get; set; } } public partial class BwdifClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class BwdifCudaClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class DeinterlaceQsvClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class DeinterlaceVaapiClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class LibplaceboClass { [JsonPropertyName("tonemapping")] public string? Tonemapping { get; set; } } public partial class TonemapClass { [JsonPropertyName("tonemap")] public string? Tonemap { get; set; } } public partial class TonemapOpenclClass { [JsonPropertyName("tonemap")] public string? Tonemap { get; set; } } public partial class W3FdifClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class YadifClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class YadifCudaClass { [JsonPropertyName("mode")] public string? Mode { get; set; } } public partial class Playout { [JsonPropertyName("folder")] public string Folder { get; set; } /// /// RFC3339 formatted date/time, e.g. 2026-04-13T00:24:21.527-05:00 /// [JsonPropertyName("virtual_start")] public string? VirtualStart { get; set; } } public enum AudioFormat { Aac, Ac3 }; public enum Mode { Burn, Convert }; public enum AccelEnum { Amf, Cuda, Qsv, Rkmpp, Vaapi, Videotoolbox, Vulkan }; public enum VideoFormat { H264, Hevc }; public enum ScalingMode { Crop, ScaleAndPad, Stretch }; public enum VaapiDriverEnum { I965, Ihd, Radeonsi }; public partial class ChannelConfig { public static ChannelConfig FromJson(string json) => JsonSerializer.Deserialize(json, ErsatzTV.Core.Next.Config.Converter.Settings); } public static class Serialize { public static string ToJson(this ChannelConfig self) => JsonSerializer.Serialize(self, ErsatzTV.Core.Next.Config.Converter.Settings); } internal static class Converter { public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General) { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, Converters = { AudioFormatConverter.Singleton, ModeConverter.Singleton, AccelEnumConverter.Singleton, VideoFormatConverter.Singleton, ScalingModeConverter.Singleton, VaapiDriverEnumConverter.Singleton, new DateOnlyConverter(), new TimeOnlyConverter(), IsoDateTimeOffsetConverter.Singleton }, }; } internal class AudioFormatConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(AudioFormat); public override AudioFormat Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); switch (value) { case "aac": return AudioFormat.Aac; case "ac3": return AudioFormat.Ac3; } throw new Exception("Cannot unmarshal type AudioFormat"); } public override void Write(Utf8JsonWriter writer, AudioFormat value, JsonSerializerOptions options) { switch (value) { case AudioFormat.Aac: JsonSerializer.Serialize(writer, "aac", options); return; case AudioFormat.Ac3: JsonSerializer.Serialize(writer, "ac3", options); return; } throw new Exception("Cannot marshal type AudioFormat"); } public static readonly AudioFormatConverter Singleton = new AudioFormatConverter(); } internal class ModeConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(Mode); public override Mode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); switch (value) { case "burn": return Mode.Burn; case "convert": return Mode.Convert; } throw new Exception("Cannot unmarshal type Mode"); } public override void Write(Utf8JsonWriter writer, Mode value, JsonSerializerOptions options) { switch (value) { case Mode.Burn: JsonSerializer.Serialize(writer, "burn", options); return; case Mode.Convert: JsonSerializer.Serialize(writer, "convert", options); return; } throw new Exception("Cannot marshal type Mode"); } public static readonly ModeConverter Singleton = new ModeConverter(); } internal class AccelEnumConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(AccelEnum); public override AccelEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); switch (value) { case "amf": return AccelEnum.Amf; case "cuda": return AccelEnum.Cuda; case "qsv": return AccelEnum.Qsv; case "rkmpp": return AccelEnum.Rkmpp; case "vaapi": return AccelEnum.Vaapi; case "videotoolbox": return AccelEnum.Videotoolbox; case "vulkan": return AccelEnum.Vulkan; } throw new Exception("Cannot unmarshal type AccelEnum"); } public override void Write(Utf8JsonWriter writer, AccelEnum value, JsonSerializerOptions options) { switch (value) { case AccelEnum.Amf: JsonSerializer.Serialize(writer, "amf", options); return; case AccelEnum.Cuda: JsonSerializer.Serialize(writer, "cuda", options); return; case AccelEnum.Qsv: JsonSerializer.Serialize(writer, "qsv", options); return; case AccelEnum.Rkmpp: JsonSerializer.Serialize(writer, "rkmpp", options); return; case AccelEnum.Vaapi: JsonSerializer.Serialize(writer, "vaapi", options); return; case AccelEnum.Videotoolbox: JsonSerializer.Serialize(writer, "videotoolbox", options); return; case AccelEnum.Vulkan: JsonSerializer.Serialize(writer, "vulkan", options); return; } throw new Exception("Cannot marshal type AccelEnum"); } public static readonly AccelEnumConverter Singleton = new AccelEnumConverter(); } internal class VideoFormatConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(VideoFormat); public override VideoFormat Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); switch (value) { case "h264": return VideoFormat.H264; case "hevc": return VideoFormat.Hevc; } throw new Exception("Cannot unmarshal type VideoFormat"); } public override void Write(Utf8JsonWriter writer, VideoFormat value, JsonSerializerOptions options) { switch (value) { case VideoFormat.H264: JsonSerializer.Serialize(writer, "h264", options); return; case VideoFormat.Hevc: JsonSerializer.Serialize(writer, "hevc", options); return; } throw new Exception("Cannot marshal type VideoFormat"); } public static readonly VideoFormatConverter Singleton = new VideoFormatConverter(); } internal class ScalingModeConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(ScalingMode); public override ScalingMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); switch (value) { case "crop": return ScalingMode.Crop; case "scale_and_pad": return ScalingMode.ScaleAndPad; case "stretch": return ScalingMode.Stretch; } throw new Exception("Cannot unmarshal type ScalingMode"); } public override void Write(Utf8JsonWriter writer, ScalingMode value, JsonSerializerOptions options) { switch (value) { case ScalingMode.Crop: JsonSerializer.Serialize(writer, "crop", options); return; case ScalingMode.ScaleAndPad: JsonSerializer.Serialize(writer, "scale_and_pad", options); return; case ScalingMode.Stretch: JsonSerializer.Serialize(writer, "stretch", options); return; } throw new Exception("Cannot marshal type ScalingMode"); } public static readonly ScalingModeConverter Singleton = new ScalingModeConverter(); } internal class VaapiDriverEnumConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(VaapiDriverEnum); public override VaapiDriverEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); switch (value) { case "i965": return VaapiDriverEnum.I965; case "ihd": return VaapiDriverEnum.Ihd; case "radeonsi": return VaapiDriverEnum.Radeonsi; } throw new Exception("Cannot unmarshal type VaapiDriverEnum"); } public override void Write(Utf8JsonWriter writer, VaapiDriverEnum value, JsonSerializerOptions options) { switch (value) { case VaapiDriverEnum.I965: JsonSerializer.Serialize(writer, "i965", options); return; case VaapiDriverEnum.Ihd: JsonSerializer.Serialize(writer, "ihd", options); return; case VaapiDriverEnum.Radeonsi: JsonSerializer.Serialize(writer, "radeonsi", options); return; } throw new Exception("Cannot marshal type VaapiDriverEnum"); } public static readonly VaapiDriverEnumConverter Singleton = new VaapiDriverEnumConverter(); } public class DateOnlyConverter : JsonConverter { private readonly string serializationFormat; public DateOnlyConverter() : this(null) { } public DateOnlyConverter(string? serializationFormat) { this.serializationFormat = serializationFormat ?? "yyyy-MM-dd"; } public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); return DateOnly.Parse(value!); } public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(serializationFormat)); } public class TimeOnlyConverter : JsonConverter { private readonly string serializationFormat; public TimeOnlyConverter() : this(null) { } public TimeOnlyConverter(string? serializationFormat) { this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff"; } public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); return TimeOnly.Parse(value!); } public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(serializationFormat)); } internal class IsoDateTimeOffsetConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(DateTimeOffset); private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; private string? _dateTimeFormat; private CultureInfo? _culture; public DateTimeStyles DateTimeStyles { get => _dateTimeStyles; set => _dateTimeStyles = value; } public string? DateTimeFormat { get => _dateTimeFormat ?? string.Empty; set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; } public CultureInfo Culture { get => _culture ?? CultureInfo.CurrentCulture; set => _culture = value; } public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) { string text; if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal) { value = value.ToUniversalTime(); } text = value.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); writer.WriteStringValue(text); } public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { string? dateText = reader.GetString(); if (string.IsNullOrEmpty(dateText) == false) { if (!string.IsNullOrEmpty(_dateTimeFormat)) { return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); } else { return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles); } } else { return default(DateTimeOffset); } } public static readonly IsoDateTimeOffsetConverter Singleton = new IsoDateTimeOffsetConverter(); } } #pragma warning restore CS8618 #pragma warning restore CS8601 #pragma warning restore CS8602 #pragma warning restore CS8603