Browse Source

Used a UUID in HDHomeRun config to allow multiple instances on a same network (#1810)

* Used a UUID in HDHomeRun config to allow multiple instances on a same network

* tweak some async calls

* try to fix line endings

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
pull/1820/head
Sylvain 9 months ago committed by GitHub
parent
commit
8488fe5d3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      .gitattributes
  2. 3
      ErsatzTV.Application/HDHR/Queries/GetHDHRUUID.cs
  3. 24
      ErsatzTV.Application/HDHR/Queries/GetHDHRUUIDHandler.cs
  4. 3
      ErsatzTV.Core/Domain/ConfigElementKey.cs
  5. 6
      ErsatzTV.Core/Hdhr/DeviceXml.cs
  6. 10
      ErsatzTV.Core/Hdhr/Discover.cs
  7. 7
      ErsatzTV.Infrastructure/Data/Repositories/ConfigElementRepository.cs
  8. 24
      ErsatzTV/Controllers/HdhrController.cs
  9. 73
      ErsatzTV/Pages/Settings.razor

8
.gitattributes vendored

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
# Auto detect text files and perform LF normalization
* text=auto
*.cs text diff=csharp
*.cshtml text diff=html
*.csx text diff=csharp
*.sln text eol=crlf
*.csproj text eol=crlf

3
ErsatzTV.Application/HDHR/Queries/GetHDHRUUID.cs

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
namespace ErsatzTV.Application.HDHR;
public record GetHDHRUUID : IRequest<Guid>;

24
ErsatzTV.Application/HDHR/Queries/GetHDHRUUIDHandler.cs

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
namespace ErsatzTV.Application.HDHR;
public class GetHDHRUUIDHandler : IRequestHandler<GetHDHRUUID, Guid>
{
private readonly IConfigElementRepository _configElementRepository;
public GetHDHRUUIDHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public async Task<Guid> Handle(GetHDHRUUID request, CancellationToken cancellationToken)
{
Option<Guid> maybeGuid = await _configElementRepository.GetValue<Guid>(ConfigElementKey.HDHRUUID);
return await maybeGuid.IfNoneAsync(
async () =>
{
Guid guid = Guid.NewGuid();
await _configElementRepository.Upsert(ConfigElementKey.HDHRUUID, guid);
return guid;
});
}
}

3
ErsatzTV.Core/Domain/ConfigElementKey.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
namespace ErsatzTV.Core.Domain;
namespace ErsatzTV.Core.Domain;
public class ConfigElementKey
{
@ -27,6 +27,7 @@ public class ConfigElementKey @@ -27,6 +27,7 @@ public class ConfigElementKey
public static ConfigElementKey FFmpegHlsDirectOutputFormat => new("ffmpeg.hls_direct.output_format");
public static ConfigElementKey SearchIndexVersion => new("search_index.version");
public static ConfigElementKey HDHRTunerCount => new("hdhr.tuner_count");
public static ConfigElementKey HDHRUUID => new("hdhr.uuid");
public static ConfigElementKey ChannelsPageSize => new("pages.channels.page_size");
public static ConfigElementKey CollectionsPageSize => new("pages.collections.page_size");
public static ConfigElementKey MultiCollectionsPageSize => new("pages.multi_collections.page_size");

6
ErsatzTV.Core/Hdhr/DeviceXml.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
namespace ErsatzTV.Core.Hdhr;
public record DeviceXml(string Scheme, string Host)
public record DeviceXml(string Scheme, string Host, Guid uuid)
{
public string ToXml() =>
@$"<root xmlns=""urn:schemas-upnp-org:device-1-0"">
@ -15,8 +15,8 @@ public record DeviceXml(string Scheme, string Host) @@ -15,8 +15,8 @@ public record DeviceXml(string Scheme, string Host)
<manufacturer>Silicondust</manufacturer>
<modelName>HDTC-2US</modelName>
<modelNumber>HDTC-2US</modelNumber>
<serialNumber/>
<UDN>uuid:2020-03-S3LA-BG3LIA:2</UDN>
<serialNumber>{uuid}</serialNumber>
<UDN>uuid:{uuid}</UDN>
</device>
</root>";
}

10
ErsatzTV.Core/Hdhr/Discover.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
namespace ErsatzTV.Core.Hdhr;
@ -8,21 +8,23 @@ public class Discover @@ -8,21 +8,23 @@ public class Discover
{
private readonly string _host;
private readonly string _scheme;
private readonly Guid _UUID;
public Discover(string scheme, string host, int tunerCount)
public Discover(string scheme, string host, int tunerCount, Guid uuid)
{
_scheme = scheme;
_host = host;
TunerCount = tunerCount;
_UUID = uuid;
}
public string DeviceAuth => "";
public string DeviceID => "ErsatzTV";
public string DeviceID => _UUID.ToString();
public string FirmwareName => "hdhomeruntc_atsc";
public string FirmwareVersion => "20190621";
public string FriendlyName => "ErsatzTV";
public string LineupURL => $"{_scheme}://{_host}/lineup.json";
public string Manufacturer => "ErsatzTV - Silicondust";
public string Manufacturer => "ErsatzTV";
public string ManufacturerURL => "https://github.com/ErsatzTV/ErsatzTV";
public string ModelNumber => "HDTC-2US";
public int TunerCount { get; }

7
ErsatzTV.Infrastructure/Data/Repositories/ConfigElementRepository.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
using System.Globalization;
using System.Globalization;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Extensions;
@ -54,6 +54,11 @@ public class ConfigElementRepository : IConfigElementRepository @@ -54,6 +54,11 @@ public class ConfigElementRepository : IConfigElementRepository
GetConfigElement(key).MapT(
ce =>
{
if (typeof(T).Name == "Guid")
{
return (T)Convert.ChangeType(Guid.Parse(ce.Value), typeof(T), CultureInfo.InvariantCulture);
}
if (typeof(T).IsEnum)
{
return (T)Enum.Parse(typeof(T), ce.Value);

24
ErsatzTV/Controllers/HdhrController.cs

@ -9,21 +9,23 @@ namespace ErsatzTV.Controllers; @@ -9,21 +9,23 @@ namespace ErsatzTV.Controllers;
[ApiController]
[ApiExplorerSettings(IgnoreApi = true)]
public class HdhrController : ControllerBase
public class HdhrController(IMediator mediator) : ControllerBase
{
private readonly IMediator _mediator;
public HdhrController(IMediator mediator) => _mediator = mediator;
[HttpGet("device.xml")]
public IActionResult DeviceXml() =>
new OkObjectResult(new DeviceXml(Request.Scheme, Request.Host.ToString()));
public async Task<IActionResult> DeviceXml()
{
Guid uuid = await mediator.Send(new GetHDHRUUID());
return new OkObjectResult(new DeviceXml(Request.Scheme, Request.Host.ToString(), uuid));
}
[HttpGet("discover.json")]
[ResponseCache(NoStore = true)]
public Task<IActionResult> Discover() =>
_mediator.Send(new GetHDHRTunerCount()).Map<int, IActionResult>(
tunerCount => new OkObjectResult(new Discover(Request.Scheme, Request.Host.ToString(), tunerCount)));
public async Task<IActionResult> Discover()
{
Guid uuid = await mediator.Send(new GetHDHRUUID());
int tunerCount = await mediator.Send(new GetHDHRTunerCount());
return new OkObjectResult(new Discover(Request.Scheme, Request.Host.ToString(), tunerCount, uuid));
}
[HttpGet("lineup_status.json")]
public IActionResult LineupStatus() =>
@ -31,5 +33,5 @@ public class HdhrController : ControllerBase @@ -31,5 +33,5 @@ public class HdhrController : ControllerBase
[HttpGet("lineup.json")]
public Task<IActionResult> Lineup() =>
_mediator.Send(new GetChannelLineup(Request.Scheme, Request.Host.ToString())).ToActionResult();
mediator.Send(new GetChannelLineup(Request.Scheme, Request.Host.ToString())).ToActionResult();
}

73
ErsatzTV/Pages/Settings.razor

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
@page "/settings"
@page "/settings"
@using ErsatzTV.Application.Configuration
@using ErsatzTV.Application.FFmpegProfiles
@using ErsatzTV.Application.Filler
@ -191,7 +191,10 @@ @@ -191,7 +191,10 @@
<CardHeaderContent>
<MudText Typo="Typo.h6">HDHomeRun Settings</MudText>
</CardHeaderContent>
</MudCardHeader>
</MudCardHeader>
<MudCardContent>
<MudTextField T="Guid" Label="UUID" @bind-Value="_uuid" ReadOnly="true" Disabled="true" />
</MudCardContent>
<MudCardContent>
<MudForm @bind-IsValid="@_hdhrSuccess">
<MudTextField T="int" Label="Tuner Count" @bind-Value="_tunerCount" Validation="@(new Func<int, string>(ValidateTunerCount))" Required="true" RequiredError="Tuner count is required!"/>
@ -325,42 +328,44 @@ @@ -325,42 +328,44 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private readonly CancellationTokenSource _cts = new();
private bool _success;
private bool _hdhrSuccess;
private bool _scannerSuccess;
private bool _playoutSuccess;
private List<FFmpegProfileViewModel> _ffmpegProfiles = new();
private FFmpegSettingsViewModel _ffmpegSettings = new();
private List<LanguageCodeViewModel> _availableCultures = new();
private List<WatermarkViewModel> _watermarks = new();
private List<FillerPresetViewModel> _fillerPresets = new();
private List<ResolutionViewModel> _customResolutions = new();
private int _tunerCount;
private int _libraryRefreshInterval;
private PlayoutSettingsViewModel _playoutSettings = new();
private GeneralSettingsViewModel _generalSettings = new();
private XmltvSettingsViewModel _xmltvSettings = new();
private bool _success;
private bool _hdhrSuccess;
private bool _scannerSuccess;
private bool _playoutSuccess;
private List<FFmpegProfileViewModel> _ffmpegProfiles = new();
private FFmpegSettingsViewModel _ffmpegSettings = new();
private List<LanguageCodeViewModel> _availableCultures = new();
private List<WatermarkViewModel> _watermarks = new();
private List<FillerPresetViewModel> _fillerPresets = new();
private List<ResolutionViewModel> _customResolutions = new();
private int _tunerCount;
private int _libraryRefreshInterval;
private PlayoutSettingsViewModel _playoutSettings = new();
private GeneralSettingsViewModel _generalSettings = new();
private XmltvSettingsViewModel _xmltvSettings = new();
private Guid _uuid;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
await LoadFFmpegProfilesAsync();
protected override async Task OnParametersSetAsync()
{
await LoadFFmpegProfilesAsync();
_ffmpegSettings = await Mediator.Send(new GetFFmpegSettings(), _cts.Token);
_success = File.Exists(_ffmpegSettings.FFmpegPath) && File.Exists(_ffmpegSettings.FFprobePath);
_availableCultures = await Mediator.Send(new GetAllLanguageCodes(), _cts.Token);
_watermarks = await Mediator.Send(new GetAllWatermarks(), _cts.Token);
_fillerPresets = await Mediator.Send(new GetAllFillerPresets(), _cts.Token)
.Map(list => list.Filter(fp => fp.FillerKind == FillerKind.Fallback).ToList());
_tunerCount = await Mediator.Send(new GetHDHRTunerCount(), _cts.Token);
_hdhrSuccess = string.IsNullOrWhiteSpace(ValidateTunerCount(_tunerCount));
_ffmpegSettings = await Mediator.Send(new GetFFmpegSettings(), _cts.Token);
_success = File.Exists(_ffmpegSettings.FFmpegPath) && File.Exists(_ffmpegSettings.FFprobePath);
_availableCultures = await Mediator.Send(new GetAllLanguageCodes(), _cts.Token);
_watermarks = await Mediator.Send(new GetAllWatermarks(), _cts.Token);
_fillerPresets = await Mediator.Send(new GetAllFillerPresets(), _cts.Token)
.Map(list => list.Filter(fp => fp.FillerKind == FillerKind.Fallback).ToList());
_tunerCount = await Mediator.Send(new GetHDHRTunerCount(), _cts.Token);
_uuid = await Mediator.Send(new GetHDHRUUID(), _cts.Token);
_hdhrSuccess = string.IsNullOrWhiteSpace(ValidateTunerCount(_tunerCount));
_libraryRefreshInterval = await Mediator.Send(new GetLibraryRefreshInterval(), _cts.Token);
_scannerSuccess = _libraryRefreshInterval is >= 0 and < 1_000_000;
_playoutSettings = await Mediator.Send(new GetPlayoutSettings(), _cts.Token);

Loading…
Cancel
Save