more cleanup

This commit is contained in:
Cody Robibero 2024-06-14 07:30:05 -06:00
parent 7a08a85e7f
commit eab72a5530
12 changed files with 115 additions and 128 deletions

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Jellyfin.Plugin.NextPVR.Entities; using Jellyfin.Plugin.NextPVR.Entities;
@ -23,20 +23,22 @@ public class PluginConfiguration : BasePluginConfiguration
PollInterval = 20; PollInterval = 20;
BackendVersion = 0; BackendVersion = 0;
// Initialise this // Initialise this
GenreMappings = new SerializableDictionary<string, List<string>>(); GenreMappings = new SerializableDictionary<string, List<string>>
GenreMappings["GENRESPORT"] = new List<string>()
{ {
"Sports", ["GENRESPORT"] =
"Football", [
"Baseball", "Sports",
"Basketball", "Football",
"Hockey", "Baseball",
"Soccer" "Basketball",
"Hockey",
"Soccer"
],
["GENRENEWS"] = ["News"],
["GENREKIDS"] = ["Kids", "Children"],
["GENREMOVIE"] = ["Movie", "Film"],
["GENRELIVE"] = ["Awards"]
}; };
GenreMappings["GENRENEWS"] = new List<string>() { "News" };
GenreMappings["GENREKIDS"] = new List<string>() { "Kids", "Children" };
GenreMappings["GENREMOVIE"] = new List<string>() { "Movie", "Film" };
GenreMappings["GENRELIVE"] = new List<string>() { "Awards" };
} }
public string WebServiceUrl { get; set; } public string WebServiceUrl { get; set; }

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
@ -32,7 +31,6 @@ public class LiveTvService : ILiveTvService
private readonly bool _enableIPv6; private readonly bool _enableIPv6;
private readonly ILogger<LiveTvService> _logger; private readonly ILogger<LiveTvService> _logger;
private int _liveStreams; private int _liveStreams;
private DateTimeOffset _lastRecordingChange = DateTimeOffset.MinValue;
private string _baseUrl; private string _baseUrl;
@ -51,7 +49,7 @@ public class LiveTvService : ILiveTvService
public static LiveTvService Instance { get; private set; } public static LiveTvService Instance { get; private set; }
public bool IsActive => Sid != null; public bool IsActive => Sid is not null;
public bool FlagRecordingChange { get; set; } public bool FlagRecordingChange { get; set; }
@ -76,13 +74,13 @@ public class LiveTvService : ILiveTvService
{ {
if (!Uri.IsWellFormedUriString(config.WebServiceUrl, UriKind.Absolute)) if (!Uri.IsWellFormedUriString(config.WebServiceUrl, UriKind.Absolute))
{ {
_logger.LogError("[NextPVR] Web service URL must be configured"); _logger.LogError("Web service URL must be configured");
throw new InvalidOperationException("NextPVR web service URL must be configured."); throw new InvalidOperationException("NextPVR web service URL must be configured.");
} }
if (string.IsNullOrEmpty(config.Pin)) if (string.IsNullOrEmpty(config.Pin))
{ {
_logger.LogError("[NextPVR] PIN must be configured"); _logger.LogError("PIN must be configured");
throw new InvalidOperationException("NextPVR PIN must be configured."); throw new InvalidOperationException("NextPVR PIN must be configured.");
} }
@ -114,7 +112,7 @@ public class LiveTvService : ILiveTvService
/// </summary> /// </summary>
private async Task InitiateSession(CancellationToken cancellationToken) private async Task InitiateSession(CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start InitiateSession"); _logger.LogInformation("Start InitiateSession");
_baseUrl = Plugin.Instance.Configuration.CurrentWebServiceURL; _baseUrl = Plugin.Instance.Configuration.CurrentWebServiceURL;
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
httpClient.Timeout = TimeSpan.FromSeconds(5); httpClient.Timeout = TimeSpan.FromSeconds(5);
@ -141,19 +139,19 @@ public class LiveTvService : ILiveTvService
{ {
Uri uri = new Uri(Plugin.Instance.Configuration.WebServiceUrl); Uri uri = new Uri(Plugin.Instance.Configuration.WebServiceUrl);
var hosts = await Dns.GetHostEntryAsync(uri.Host, System.Net.Sockets.AddressFamily.InterNetwork, cancellationToken); var hosts = await Dns.GetHostEntryAsync(uri.Host, System.Net.Sockets.AddressFamily.InterNetwork, cancellationToken);
if (hosts != null) if (hosts is not null)
{ {
var host = hosts.AddressList.FirstOrDefault()?.ToString(); var host = hosts.AddressList.FirstOrDefault()?.ToString();
if (builder.Host != host) if (builder.Host != host && host is not null)
{ {
_logger.LogInformation("[NextPVR] Changed host from {0} to {1}", builder.Host, host); _logger.LogInformation("Changed host from {OldHost} to {NewHost}", builder.Host, host);
builder.Host = host; builder.Host = host;
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Could not resolve {0}", Plugin.Instance.Configuration.WebServiceUrl); _logger.LogError(ex, "Could not resolve {WebServiceUrl}", Plugin.Instance.Configuration.WebServiceUrl);
} }
} }
@ -171,8 +169,8 @@ public class LiveTvService : ILiveTvService
{ {
LastUpdatedSidDateTime = DateTimeOffset.UtcNow; LastUpdatedSidDateTime = DateTimeOffset.UtcNow;
Sid = Plugin.Instance.Configuration.StoredSid; Sid = Plugin.Instance.Configuration.StoredSid;
_logger.LogInformation("[NextPVR] Session initiated"); _logger.LogInformation("Session initiated");
_logger.LogInformation("[NextPVR] Sid: {0}", Sid); _logger.LogInformation("Sid: {Sid}", Sid);
if (updateConfiguration) if (updateConfiguration)
{ {
Plugin.Instance.Configuration.CurrentWebServiceURL = _baseUrl; Plugin.Instance.Configuration.CurrentWebServiceURL = _baseUrl;
@ -188,16 +186,16 @@ public class LiveTvService : ILiveTvService
else else
{ {
Sid = null; Sid = null;
_logger.LogError("[NextPVR] PIN not accepted"); _logger.LogError("PIN not accepted");
throw new UnauthorizedAccessException("NextPVR PIN not accepted"); throw new UnauthorizedAccessException("NextPVR PIN not accepted");
} }
} }
private async Task<bool> Login(string sid, string salt, CancellationToken cancellationToken) private async Task<bool> Login(string sid, string salt, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start Login procedure for Sid: {0} & Salt: {1}", sid, salt); _logger.LogInformation("Start Login procedure for Sid: {Sid} & Salt: {Salt}", sid, salt);
var pin = Plugin.Instance.Configuration.Pin; var pin = Plugin.Instance.Configuration.Pin;
_logger.LogInformation("[NextPVR] PIN: {0}", pin == "0000" ? pin : "Not default"); _logger.LogInformation("PIN: {Pin}", pin == "0000" ? pin : "Not default");
var strb = new StringBuilder(); var strb = new StringBuilder();
var md5Result = GetMd5Hash(strb.Append(':').Append(GetMd5Hash(pin)).Append(':').Append(salt).ToString()); var md5Result = GetMd5Hash(strb.Append(':').Append(GetMd5Hash(pin)).Append(':').Append(salt).ToString());
@ -225,7 +223,7 @@ public class LiveTvService : ILiveTvService
/// <returns>Task{IEnumerable{ChannelInfo}}.</returns> /// <returns>Task{IEnumerable{ChannelInfo}}.</returns>
public async Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken) public async Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start GetChannels Async, retrieve all channels"); _logger.LogInformation("Start GetChannels Async, retrieve all channels");
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
@ -239,9 +237,9 @@ public class LiveTvService : ILiveTvService
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RecordingInfo}}.</returns> /// <returns>Task{IEnumerable{RecordingInfo}}.</returns>
public async Task<IEnumerable<MyRecordingInfo>> GetAllRecordingsAsync(CancellationToken cancellationToken) public async Task<IReadOnlyList<MyRecordingInfo>> GetAllRecordingsAsync(CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start GetRecordings Async, retrieve all 'Pending', 'Inprogress' and 'Completed' recordings "); _logger.LogInformation("Start GetRecordings Async, retrieve all 'Pending', 'Inprogress' and 'Completed' recordings ");
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=recording.list&filter=ready&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=recording.list&filter=ready&sid={Sid}", cancellationToken);
@ -256,17 +254,16 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken) public async Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start Delete Recording Async for recordingId: {RecordingId}", recordingId); _logger.LogInformation("Start Delete Recording Async for recordingId: {RecordingId}", recordingId);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=recording.delete&recording_id={recordingId}&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=recording.delete&recording_id={recordingId}&sid={Sid}", cancellationToken);
_lastRecordingChange = DateTimeOffset.UtcNow;
bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false); bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false);
if (error == null || error == true) if (error is null or true)
{ {
_logger.LogError("[NextPVR] Failed to delete the recording for recordingId: {RecordingId}", recordingId); _logger.LogError("Failed to delete the recording for recordingId: {RecordingId}", recordingId);
throw new JsonException($"Failed to delete the recording for recordingId: {recordingId}"); throw new JsonException($"Failed to delete the recording for recordingId: {recordingId}");
} }
else else
@ -274,7 +271,7 @@ public class LiveTvService : ILiveTvService
FlagRecordingChange = true; FlagRecordingChange = true;
} }
_logger.LogInformation("[NextPVR] Deleted Recording with recordingId: {RecordingId}", recordingId); _logger.LogInformation("Deleted Recording with recordingId: {RecordingId}", recordingId);
} }
/// <summary> /// <summary>
@ -285,17 +282,16 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task CancelTimerAsync(string timerId, CancellationToken cancellationToken) public async Task CancelTimerAsync(string timerId, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start Cancel Recording Async for recordingId: {TimerId}", timerId); _logger.LogInformation("Start Cancel Recording Async for recordingId: {TimerId}", timerId);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=recording.delete&recording_id={timerId}&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=recording.delete&recording_id={timerId}&sid={Sid}", cancellationToken);
_lastRecordingChange = DateTimeOffset.UtcNow;
bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false); bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false);
if (error == null || error == true) if (error is null or true)
{ {
_logger.LogError("[NextPVR] Failed to cancel the recording for recordingId: {TimerId}", timerId); _logger.LogError("Failed to cancel the recording for recordingId: {TimerId}", timerId);
throw new JsonException($"Failed to cancel the recording for recordingId: {timerId}"); throw new JsonException($"Failed to cancel the recording for recordingId: {timerId}");
} }
else else
@ -303,7 +299,7 @@ public class LiveTvService : ILiveTvService
FlagRecordingChange = true; FlagRecordingChange = true;
} }
_logger.LogInformation("[NextPVR] Cancelled Recording for recordingId: {TimerId}", timerId); _logger.LogInformation("Cancelled Recording for recordingId: {TimerId}", timerId);
} }
/// <summary> /// <summary>
@ -314,9 +310,9 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken) public async Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start CreateTimer Async for ChannelId: {ChannelId} & Name: {Name}", info.ChannelId, info.Name); _logger.LogInformation("Start CreateTimer Async for ChannelId: {ChannelId} & Name: {Name}", info.ChannelId, info.Name);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
UtilsHelper.DebugInformation(_logger, $"[NextPVR] TimerSettings CreateTimer: {info.ProgramId} for ChannelId: {info.ChannelId} & Name: {info.Name}"); UtilsHelper.DebugInformation(_logger, $"TimerSettings CreateTimer: {info.ProgramId} for ChannelId: {info.ChannelId} & Name: {info.Name}");
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync( .GetStreamAsync(
string.Format( string.Format(
@ -330,9 +326,9 @@ public class LiveTvService : ILiveTvService
cancellationToken); cancellationToken);
bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false); bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false);
if (error == null || error == true) if (error is null or true)
{ {
_logger.LogError("[NextPVR] Failed to create the timer with programId: {ProgramId}", info.ProgramId); _logger.LogError("Failed to create the timer with programId: {ProgramId}", info.ProgramId);
throw new JsonException($"Failed to create the timer with programId: {info.ProgramId}"); throw new JsonException($"Failed to create the timer with programId: {info.ProgramId}");
} }
else if (info.StartDate <= DateTime.UtcNow) else if (info.StartDate <= DateTime.UtcNow)
@ -340,7 +336,7 @@ public class LiveTvService : ILiveTvService
FlagRecordingChange = true; FlagRecordingChange = true;
} }
_logger.LogError("[NextPVR] CreateTimer async for programId: {ProgramId}", info.ProgramId); _logger.LogError("CreateTimer async for programId: {ProgramId}", info.ProgramId);
} }
/// <summary> /// <summary>
@ -350,7 +346,7 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken) public async Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start GetTimer Async, retrieve the 'Pending' recordings"); _logger.LogInformation("Start GetTimer Async, retrieve the 'Pending' recordings");
if (await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false)) if (await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false))
{ {
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
@ -369,7 +365,7 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken) public async Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start GetSeriesTimer Async, retrieve the recurring recordings"); _logger.LogInformation("Start GetSeriesTimer Async, retrieve the recurring recordings");
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=recording.recurring.list&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=recording.recurring.list&sid={Sid}", cancellationToken);
@ -385,7 +381,7 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) public async Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start CreateSeriesTimer Async for ChannelId: {ChannelId} & Name: {Name}", info.ChannelId, info.Name); _logger.LogInformation("Start CreateSeriesTimer Async for ChannelId: {ChannelId} & Name: {Name}", info.ChannelId, info.Name);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
var url = $"{_baseUrl}/service?method=recording.recurring.save&sid={Sid}&pre_padding={info.PrePaddingSeconds / 60}&post_padding={info.PostPaddingSeconds / 60}&keep={info.KeepUpTo}"; var url = $"{_baseUrl}/service?method=recording.recurring.save&sid={Sid}&pre_padding={info.PrePaddingSeconds / 60}&post_padding={info.PostPaddingSeconds / 60}&keep={info.KeepUpTo}";
@ -405,7 +401,7 @@ public class LiveTvService : ILiveTvService
url += "&only_new=true"; url += "&only_new=true";
} }
if (recurringType == 3 || recurringType == 4) if (recurringType is 3 or 4)
{ {
url += "&timeslot=true"; url += "&timeslot=true";
} }
@ -413,27 +409,20 @@ public class LiveTvService : ILiveTvService
await CreateUpdateSeriesTimerAsync(info, url, cancellationToken); await CreateUpdateSeriesTimerAsync(info, url, cancellationToken);
} }
/// <summary> private async Task CreateUpdateSeriesTimerAsync(SeriesTimerInfo info, string url, CancellationToken cancellationToken)
/// Update the series Timer.
/// </summary>
/// <param name="info">The series program info.</param>
/// <param name="url">The url.</param>
/// <param name="cancellationToken">The CancellationToken.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task CreateUpdateSeriesTimerAsync(SeriesTimerInfo info, string url, CancellationToken cancellationToken)
{ {
UtilsHelper.DebugInformation(_logger, $"[NextPVR] TimerSettings CreateSeriesTimerAsync: {info.ProgramId} for ChannelId: {info.ChannelId} & Name: {info.Name}"); UtilsHelper.DebugInformation(_logger, $"TimerSettings CreateSeriesTimerAsync: {info.ProgramId} for ChannelId: {info.ChannelId} & Name: {info.Name}");
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync(url, cancellationToken); .GetStreamAsync(url, cancellationToken);
bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false); bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false);
if (error == null || error == true) if (error is null or true)
{ {
_logger.LogError("[NextPVR] Failed to create or update the timer with Recurring ID: {0}", info.Id); _logger.LogError("Failed to create or update the timer with Recurring ID: {TimerInfoId}", info.Id);
throw new JsonException($"Failed to create or update the timer with Recurring ID: {info.Id}"); throw new JsonException($"Failed to create or update the timer with Recurring ID: {info.Id}");
} }
_logger.LogInformation("[NextPVR] CreateUpdateSeriesTimer async for Program ID: {0} Recurring ID {1}", info.ProgramId, info.Id); _logger.LogInformation("CreateUpdateSeriesTimer async for Program ID: {ProgramId} Recurring ID {TimerInfoId}", info.ProgramId, info.Id);
} }
/// <summary> /// <summary>
@ -444,7 +433,7 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start UpdateSeriesTimer Async for ChannelId: {ChannelId} & Name: {Name}", info.ChannelId, info.Name); _logger.LogInformation("Start UpdateSeriesTimer Async for ChannelId: {ChannelId} & Name: {Name}", info.ChannelId, info.Name);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
var url = $"{_baseUrl}/service?method=recording.recurring.save&sid={Sid}&pre_padding={info.PrePaddingSeconds / 60}&post_padding={info.PostPaddingSeconds / 60}&keep={info.KeepUpTo}&recurring_id={info.Id}"; var url = $"{_baseUrl}/service?method=recording.recurring.save&sid={Sid}&pre_padding={info.PrePaddingSeconds / 60}&post_padding={info.PostPaddingSeconds / 60}&keep={info.KeepUpTo}&recurring_id={info.Id}";
@ -466,14 +455,7 @@ public class LiveTvService : ILiveTvService
} }
else else
{ {
if (info.Days.Count == 7) recurringType = info.Days.Count == 7 ? 4 : 3;
{
recurringType = 4;
}
else
{
recurringType = 3;
}
} }
url += $"&recurring_type={recurringType}"; url += $"&recurring_type={recurringType}";
@ -495,19 +477,19 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken) public async Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start UpdateTimer Async for ChannelId: {ChannelId} & Name: {Name}", updatedTimer.ChannelId, updatedTimer.Name); _logger.LogInformation("Start UpdateTimer Async for ChannelId: {ChannelId} & Name: {Name}", updatedTimer.ChannelId, updatedTimer.Name);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=recording.save&sid={Sid}&pre_padding={updatedTimer.PrePaddingSeconds / 60}&post_padding={updatedTimer.PostPaddingSeconds / 60}&recording_id={updatedTimer.Id}&event_id={updatedTimer.ProgramId}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=recording.save&sid={Sid}&pre_padding={updatedTimer.PrePaddingSeconds / 60}&post_padding={updatedTimer.PostPaddingSeconds / 60}&recording_id={updatedTimer.Id}&event_id={updatedTimer.ProgramId}", cancellationToken);
bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false); bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false);
if (error == null || error == true) if (error is null or true)
{ {
_logger.LogError("[NextPVR] Failed to update the timer with ID: {Id}", updatedTimer.Id); _logger.LogError("Failed to update the timer with ID: {Id}", updatedTimer.Id);
throw new JsonException($"Failed to update the timer with ID: {updatedTimer.Id}"); throw new JsonException($"Failed to update the timer with ID: {updatedTimer.Id}");
} }
_logger.LogInformation("[NextPVR] UpdateTimer async for Program ID: {ProgramId} ID {Id}", updatedTimer.ProgramId, updatedTimer.Id); _logger.LogInformation("UpdateTimer async for Program ID: {ProgramId} ID {Id}", updatedTimer.ProgramId, updatedTimer.Id);
} }
/// <summary> /// <summary>
@ -518,31 +500,31 @@ public class LiveTvService : ILiveTvService
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) public async Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start Cancel SeriesRecording Async for recordingId: {TimerId}", timerId); _logger.LogInformation("Start Cancel SeriesRecording Async for recordingId: {TimerId}", timerId);
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=recording.recurring.delete&recurring_id={timerId}&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=recording.recurring.delete&recurring_id={timerId}&sid={Sid}", cancellationToken);
bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false); bool? error = await new CancelDeleteRecordingResponse().RecordingError(stream, _logger).ConfigureAwait(false);
if (error == null || error == true) if (error is null or true)
{ {
_logger.LogError("[NextPVR] Failed to cancel the recording with recordingId: {TimerId}", timerId); _logger.LogError("Failed to cancel the recording with recordingId: {TimerId}", timerId);
throw new JsonException($"Failed to cancel the recording with recordingId: {timerId}"); throw new JsonException($"Failed to cancel the recording with recordingId: {timerId}");
} }
_logger.LogInformation("[NextPVR] Cancelled Recording for recordingId: {TimerId}", timerId); _logger.LogInformation("Cancelled Recording for recordingId: {TimerId}", timerId);
} }
public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
{ {
var source = await GetChannelStream(channelId, string.Empty, cancellationToken); var source = await GetChannelStream(channelId, string.Empty, cancellationToken);
return new List<MediaSourceInfo>() { source }; return [source];
} }
public Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) public Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start ChannelStream"); _logger.LogInformation("Start ChannelStream");
EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
_liveStreams++; _liveStreams++;
@ -553,7 +535,7 @@ public class LiveTvService : ILiveTvService
} }
string streamUrl = $"{_baseUrl}/live?channeloid={channelId}&client=jellyfin.{_liveStreams.ToString(CultureInfo.InvariantCulture)}{sidParameter}"; string streamUrl = $"{_baseUrl}/live?channeloid={channelId}&client=jellyfin.{_liveStreams.ToString(CultureInfo.InvariantCulture)}{sidParameter}";
_logger.LogInformation("[NextPVR] Streaming {Url}", streamUrl); _logger.LogInformation("Streaming {Url}", streamUrl);
var mediaSourceInfo = new MediaSourceInfo var mediaSourceInfo = new MediaSourceInfo
{ {
Id = _liveStreams.ToString(CultureInfo.InvariantCulture), Id = _liveStreams.ToString(CultureInfo.InvariantCulture),
@ -585,7 +567,7 @@ public class LiveTvService : ILiveTvService
public Task CloseLiveStream(string id, CancellationToken cancellationToken) public Task CloseLiveStream(string id, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Closing {Id}", id); _logger.LogInformation("Closing {Id}", id);
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -599,18 +581,18 @@ public class LiveTvService : ILiveTvService
return Task.FromResult(defaultSettings); return Task.FromResult(defaultSettings);
} }
private async Task<bool> GetDefaultSettingsAsync(CancellationToken cancellationToken) private async Task GetDefaultSettingsAsync(CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start GetDefaultSettings Async"); _logger.LogInformation("Start GetDefaultSettings Async");
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=setting.list&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=setting.list&sid={Sid}", cancellationToken);
return await new SettingResponse().GetDefaultSettings(stream, _logger).ConfigureAwait(false); await new SettingResponse().GetDefaultSettings(stream, _logger).ConfigureAwait(false);
} }
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] Start GetPrograms Async, retrieve all Programs"); _logger.LogInformation("Start GetPrograms Async, retrieve all Programs");
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=channel.listings&sid={Sid}&start={((DateTimeOffset)startDateUtc).ToUnixTimeSeconds()}&end={((DateTimeOffset)endDateUtc).ToUnixTimeSeconds()}&channel_id={channelId}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=channel.listings&sid={Sid}&start={((DateTimeOffset)startDateUtc).ToUnixTimeSeconds()}&end={((DateTimeOffset)endDateUtc).ToUnixTimeSeconds()}&channel_id={channelId}", cancellationToken);
@ -619,7 +601,7 @@ public class LiveTvService : ILiveTvService
public async Task<DateTimeOffset> GetLastUpdate(CancellationToken cancellationToken) public async Task<DateTimeOffset> GetLastUpdate(CancellationToken cancellationToken)
{ {
_logger.LogDebug("[NextPVR] GetLastUpdateTime"); _logger.LogDebug("GetLastUpdateTime");
DateTimeOffset retTime = DateTimeOffset.FromUnixTimeSeconds(0); DateTimeOffset retTime = DateTimeOffset.FromUnixTimeSeconds(0);
try try
@ -637,7 +619,7 @@ public class LiveTvService : ILiveTvService
LastUpdatedSidDateTime = DateTimeOffset.UtcNow; LastUpdatedSidDateTime = DateTimeOffset.UtcNow;
} }
UtilsHelper.DebugInformation(_logger, $"[NextPVR] GetLastUpdateTime {retTime.ToUnixTimeSeconds()}"); UtilsHelper.DebugInformation(_logger, $"GetLastUpdateTime {retTime.ToUnixTimeSeconds()}");
} }
catch (HttpRequestException) catch (HttpRequestException)
{ {
@ -649,9 +631,9 @@ public class LiveTvService : ILiveTvService
return retTime; return retTime;
} }
public async Task<string> GetBackendSettingAsync(string key, CancellationToken cancellationToken) private async Task<string> GetBackendSettingAsync(string key, CancellationToken cancellationToken)
{ {
_logger.LogInformation("[NextPVR] GetBackendSetting"); _logger.LogInformation("GetBackendSetting");
await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false); await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default) await using var stream = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetStreamAsync($"{_baseUrl}/service?method=setting.get&key={key}&sid={Sid}", cancellationToken); .GetStreamAsync($"{_baseUrl}/service?method=setting.get&key={key}&sid={Sid}", cancellationToken);

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -37,7 +37,7 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
private IEnumerable<MyRecordingInfo> _allRecordings; private IEnumerable<MyRecordingInfo> _allRecordings;
private bool _useCachedRecordings = false; private bool _useCachedRecordings = false;
private DateTime _cachedRecordingModificationTime; private DateTime _cachedRecordingModificationTime;
private string _cachekeyBase; private string _cacheKeyBase;
private int _pollInterval = -1; private int _pollInterval = -1;
public RecordingsChannel(IApplicationPaths applicationPaths, ILibraryManager libraryManager, IFileSystem fileSystem, ILogger<RecordingsChannel> logger) public RecordingsChannel(IApplicationPaths applicationPaths, ILibraryManager libraryManager, IFileSystem fileSystem, ILogger<RecordingsChannel> logger)
@ -45,7 +45,7 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
_fileSystem = fileSystem; _fileSystem = fileSystem;
_logger = logger; _logger = logger;
string channelId = libraryManager.GetNewItemId($"Channel {Name}", typeof(Channel)).ToString("N", CultureInfo.InvariantCulture); string channelId = libraryManager.GetNewItemId($"Channel {Name}", typeof(Channel)).ToString("N", CultureInfo.InvariantCulture);
string version = BaseExtensions.GetMD5($"{DataVersion}2").ToString("N", CultureInfo.InvariantCulture); string version = $"{DataVersion}2".GetMD5().ToString("N", CultureInfo.InvariantCulture);
_recordingCacheDirectory = Path.Join(applicationPaths.CachePath, "channels", channelId, version); _recordingCacheDirectory = Path.Join(applicationPaths.CachePath, "channels", channelId, version);
CleanCache(true); CleanCache(true);
_cancellationToken = new CancellationTokenSource(); _cancellationToken = new CancellationTokenSource();
@ -57,7 +57,7 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
public string Description => "NextPVR Recordings"; public string Description => "NextPVR Recordings";
#pragma warning disable CA1819 #pragma warning disable CA1819
public string[] Attributes => new[] { "Recordings" }; public string[] Attributes => ["Recordings"];
#pragma warning restore CA1819 #pragma warning restore CA1819
public string DataVersion => "1"; public string DataVersion => "1";
@ -86,7 +86,7 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
public string GetCacheKey(string userId) public string GetCacheKey(string userId)
{ {
DateTimeOffset dto = LiveTvService.Instance.RecordingModificationTime; DateTimeOffset dto = LiveTvService.Instance.RecordingModificationTime;
return $"{dto.ToUnixTimeSeconds()}-{_cachekeyBase}"; return $"{dto.ToUnixTimeSeconds()}-{_cacheKeyBase}";
} }
private void CleanCache(bool cleanAll = false) private void CleanCache(bool cleanAll = false)
@ -94,22 +94,25 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
if (!string.IsNullOrEmpty(_recordingCacheDirectory) && Directory.Exists(_recordingCacheDirectory)) if (!string.IsNullOrEmpty(_recordingCacheDirectory) && Directory.Exists(_recordingCacheDirectory))
{ {
string[] cachedJson = Directory.GetFiles(_recordingCacheDirectory, "*.json"); string[] cachedJson = Directory.GetFiles(_recordingCacheDirectory, "*.json");
_logger.LogInformation("Cleaning JSON cache {0} {1}", _recordingCacheDirectory, cachedJson.Length); _logger.LogInformation("Cleaning JSON cache {CacheDirectory} {FileCount}", _recordingCacheDirectory, cachedJson.Length);
foreach (string fileName in cachedJson) foreach (string fileName in cachedJson)
{ {
if (cleanAll == true || _fileSystem.GetLastWriteTimeUtc(fileName).Add(TimeSpan.FromHours(3)) <= DateTimeOffset.UtcNow) if (cleanAll || _fileSystem.GetLastWriteTimeUtc(fileName).Add(TimeSpan.FromHours(3)) <= DateTimeOffset.UtcNow)
{ {
_fileSystem.DeleteFile(fileName); _fileSystem.DeleteFile(fileName);
} }
} }
} }
return;
} }
public InternalChannelFeatures GetChannelFeatures() public InternalChannelFeatures GetChannelFeatures()
{ {
return new InternalChannelFeatures { ContentTypes = new List<ChannelMediaContentType> { ChannelMediaContentType.Movie, ChannelMediaContentType.Episode, ChannelMediaContentType.Clip }, MediaTypes = new List<ChannelMediaType> { ChannelMediaType.Audio, ChannelMediaType.Video }, SupportsContentDownloading = true }; return new InternalChannelFeatures
{
ContentTypes = [ChannelMediaContentType.Movie, ChannelMediaContentType.Episode, ChannelMediaContentType.Clip],
MediaTypes = [ChannelMediaType.Audio, ChannelMediaType.Video],
SupportsContentDownloading = true
};
} }
public Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken) public Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken)
@ -315,15 +318,15 @@ public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISuppo
_logger.LogDebug("{0} Reload cache", name); _logger.LogDebug("{0} Reload cache", name);
_allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false); _allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false);
int maxId = _allRecordings.Max(r => int.Parse(r.Id, CultureInfo.InvariantCulture)); int maxId = _allRecordings.Max(r => int.Parse(r.Id, CultureInfo.InvariantCulture));
int inProcessCount = _allRecordings.Where(r => r.Status == RecordingStatus.InProgress).Count(); int inProcessCount = _allRecordings.Count(r => r.Status == RecordingStatus.InProgress);
string keyBase = $"{maxId}-{inProcessCount}-{_allRecordings.Count()}"; string keyBase = $"{maxId}-{inProcessCount}-{_allRecordings.Count()}";
if (keyBase != _cachekeyBase && !service.FlagRecordingChange) if (keyBase != _cacheKeyBase && !service.FlagRecordingChange)
{ {
_logger.LogDebug("External recording list change {0}", keyBase); _logger.LogDebug("External recording list change {0}", keyBase);
CleanCache(true); CleanCache(true);
} }
_cachekeyBase = keyBase; _cacheKeyBase = keyBase;
_lastUpdate = DateTimeOffset.UtcNow; _lastUpdate = DateTimeOffset.UtcNow;
service.FlagRecordingChange = false; service.FlagRecordingChange = false;
_useCachedRecordings = true; _useCachedRecordings = true;

View File

@ -17,7 +17,7 @@ public class CancelDeleteRecordingResponse
if (root.Stat != "ok") if (root.Stat != "ok")
{ {
UtilsHelper.DebugInformation(logger, $"[NextPVR] RecordingError Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"RecordingError Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
return true; return true;
} }

View File

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -33,7 +33,7 @@ public class ChannelResponse
if (root.Channels != null) if (root.Channels != null)
{ {
UtilsHelper.DebugInformation(logger, $"[NextPVR] ChannelResponse: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"ChannelResponse: {JsonSerializer.Serialize(root, _jsonOptions)}");
return root.Channels.Select(i => new ChannelInfo return root.Channels.Select(i => new ChannelInfo
{ {
Name = i.ChannelName, Name = i.ChannelName,

View File

@ -1,4 +1,4 @@
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json;
@ -17,11 +17,11 @@ public class InitializeResponse
if (!string.IsNullOrEmpty(root.Stat)) if (!string.IsNullOrEmpty(root.Stat))
{ {
UtilsHelper.DebugInformation(logger, $"[NextPVR] Connection validation: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"Connection validation: {JsonSerializer.Serialize(root, _jsonOptions)}");
return root.Stat == "ok"; return root.Stat == "ok";
} }
logger.LogError("[NextPVR] Failed to validate your connection with NextPVR"); logger.LogError("Failed to validate your connection with NextPVR");
throw new JsonException("Failed to validate your connection with NextPVR."); throw new JsonException("Failed to validate your connection with NextPVR.");
} }

View File

@ -21,11 +21,11 @@ public class InstantiateResponse
if (root.Sid != null && root.Salt != null) if (root.Sid != null && root.Salt != null)
{ {
UtilsHelper.DebugInformation(logger, $"[NextPVR] ClientKeys: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"ClientKeys: {JsonSerializer.Serialize(root, _jsonOptions)}");
return root; return root;
} }
logger.LogError("[NextPVR] Failed to validate the ClientKeys from NextPVR"); logger.LogError("Failed to validate the ClientKeys from NextPVR");
throw new JsonException("Failed to load the ClientKeys from NextPVR."); throw new JsonException("Failed to load the ClientKeys from NextPVR.");
} }
catch catch

View File

@ -16,7 +16,7 @@ public class LastUpdateResponse
public async Task<DateTimeOffset> GetUpdateTime(Stream stream, ILogger<LiveTvService> logger) public async Task<DateTimeOffset> GetUpdateTime(Stream stream, ILogger<LiveTvService> logger)
{ {
var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(logger, $"[NextPVR] LastUpdate Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"LastUpdate Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
return DateTimeOffset.FromUnixTimeSeconds(root.LastUpdate); return DateTimeOffset.FromUnixTimeSeconds(root.LastUpdate);
} }

View File

@ -26,7 +26,7 @@ public class ListingsResponse
public async Task<IEnumerable<ProgramInfo>> GetPrograms(Stream stream, string channelId, ILogger<LiveTvService> logger) public async Task<IEnumerable<ProgramInfo>> GetPrograms(Stream stream, string channelId, ILogger<LiveTvService> logger)
{ {
var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(logger, $"[NextPVR] GetPrograms Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"GetPrograms Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
_channelId = channelId; _channelId = channelId;
return root.Listings return root.Listings
.Select(i => i) .Select(i => i)

View File

@ -26,16 +26,16 @@ public class RecordingResponse
_logger = logger; _logger = logger;
} }
public async Task<IEnumerable<MyRecordingInfo>> GetRecordings(Stream stream) public async Task<IReadOnlyList<MyRecordingInfo>> GetRecordings(Stream stream)
{ {
if (stream == null) if (stream == null)
{ {
_logger.LogError("[NextPVR] GetRecording stream == null"); _logger.LogError("GetRecording stream == null");
throw new ArgumentNullException(nameof(stream)); throw new ArgumentNullException(nameof(stream));
} }
var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(_logger, $"[NextPVR] GetRecordings Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(_logger, $"GetRecordings Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
IEnumerable<MyRecordingInfo> recordings; IEnumerable<MyRecordingInfo> recordings;
try try
@ -47,23 +47,23 @@ public class RecordingResponse
} }
catch (Exception err) catch (Exception err)
{ {
_logger.LogWarning(err, "[NextPVR] Get recordings"); _logger.LogWarning(err, "Get recordings");
throw; throw;
} }
return recordings; return recordings.ToList();
} }
public async Task<IEnumerable<TimerInfo>> GetTimers(Stream stream) public async Task<IEnumerable<TimerInfo>> GetTimers(Stream stream)
{ {
if (stream == null) if (stream == null)
{ {
_logger.LogError("[NextPVR] GetTimers stream == null"); _logger.LogError("GetTimers stream == null");
throw new ArgumentNullException(nameof(stream)); throw new ArgumentNullException(nameof(stream));
} }
var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(_logger, $"[NextPVR] GetTimers Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(_logger, $"GetTimers Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
IEnumerable<TimerInfo> timers; IEnumerable<TimerInfo> timers;
try try
{ {
@ -73,7 +73,7 @@ public class RecordingResponse
} }
catch (Exception err) catch (Exception err)
{ {
_logger.LogWarning(err, "[NextPVR] Get timers"); _logger.LogWarning(err, "Get timers");
throw; throw;
} }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -26,12 +26,12 @@ internal sealed class RecurringResponse
{ {
if (stream == null) if (stream == null)
{ {
_logger.LogError("[NextPVR] GetSeriesTimers stream == null"); _logger.LogError("GetSeriesTimers stream == null");
throw new ArgumentNullException(nameof(stream)); throw new ArgumentNullException(nameof(stream));
} }
var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<RootObject>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(_logger, $"[NextPVR] GetSeriesTimers Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(_logger, $"GetSeriesTimers Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
return root.Recurrings return root.Recurrings
.Select(i => i) .Select(i => i)
.Select(GetSeriesTimerInfo); .Select(GetSeriesTimerInfo);

View File

@ -1,4 +1,4 @@
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -15,7 +15,7 @@ public class SettingResponse
public async Task<bool> GetDefaultSettings(Stream stream, ILogger<LiveTvService> logger) public async Task<bool> GetDefaultSettings(Stream stream, ILogger<LiveTvService> logger)
{ {
var root = await JsonSerializer.DeserializeAsync<ScheduleSettings>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<ScheduleSettings>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(logger, $"[NextPVR] GetDefaultTimerInfo Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"GetDefaultTimerInfo Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
Plugin.Instance.Configuration.PostPaddingSeconds = root.PostPadding; Plugin.Instance.Configuration.PostPaddingSeconds = root.PostPadding;
Plugin.Instance.Configuration.PrePaddingSeconds = root.PrePadding; Plugin.Instance.Configuration.PrePaddingSeconds = root.PrePadding;
Plugin.Instance.Configuration.ShowRepeat = root.ShowNewInGuide; Plugin.Instance.Configuration.ShowRepeat = root.ShowNewInGuide;
@ -26,7 +26,7 @@ public class SettingResponse
public async Task<string> GetSetting(Stream stream, ILogger<LiveTvService> logger) public async Task<string> GetSetting(Stream stream, ILogger<LiveTvService> logger)
{ {
var root = await JsonSerializer.DeserializeAsync<SettingValue>(stream, _jsonOptions).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync<SettingValue>(stream, _jsonOptions).ConfigureAwait(false);
UtilsHelper.DebugInformation(logger, $"[NextPVR] GetSetting Response: {JsonSerializer.Serialize(root, _jsonOptions)}"); UtilsHelper.DebugInformation(logger, $"GetSetting Response: {JsonSerializer.Serialize(root, _jsonOptions)}");
return root.Value; return root.Value;
} }