aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs')
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs530
1 files changed, 272 insertions, 258 deletions
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 89b81fd96..28aabc159 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -8,6 +8,8 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Mime;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
@@ -24,23 +26,23 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
public class SchedulesDirect : IListingsProvider
{
- private readonly ILogger _logger;
+ private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
+
+ private readonly ILogger<SchedulesDirect> _logger;
private readonly IJsonSerializer _jsonSerializer;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
private readonly IApplicationHost _appHost;
- private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
-
public SchedulesDirect(
ILogger<SchedulesDirect> logger,
IJsonSerializer jsonSerializer,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IApplicationHost appHost)
{
_logger = logger;
_jsonSerializer = jsonSerializer;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
}
@@ -61,7 +63,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
while (start <= end)
{
- dates.Add(start.ToString("yyyy-MM-dd"));
+ dates.Add(start.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
start = start.AddDays(1);
}
@@ -102,95 +104,78 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var requestString = _jsonSerializer.SerializeToString(requestList);
_logger.LogDebug("Request string for schedules is: {RequestString}", requestString);
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/schedules",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- RequestContent = requestString
- };
+ using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules");
+ options.Content = new StringContent(requestString, Encoding.UTF8, MediaTypeNames.Application.Json);
+ options.Headers.TryAddWithoutValidation("token", token);
+ using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
+ await using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(responseStream).ConfigureAwait(false);
+ _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
- httpOptions.RequestHeaders["token"] = token;
+ using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs");
+ programRequestOptions.Headers.TryAddWithoutValidation("token", token);
- using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
- {
- var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false);
- _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
+ var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
+ programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json);
- httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/programs",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
-
- httpOptions.RequestHeaders["token"] = token;
+ using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
+ await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponseStream).ConfigureAwait(false);
+ var programDict = programDetails.ToDictionary(p => p.programID, y => y);
- var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
- httpOptions.RequestContent = "[\"" + string.Join("\", \"", programsID) + "\"]";
-
- using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false))
- {
- var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false);
- var programDict = programDetails.ToDictionary(p => p.programID, y => y);
+ var programIdsWithImages =
+ programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
+ .ToList();
- var programIdsWithImages =
- programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
- .ToList();
+ var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
- var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
+ var programsInfo = new List<ProgramInfo>();
+ foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
+ {
+ // _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
+ // " which corresponds to channel " + channelNumber + " and program id " +
+ // schedule.programID + " which says it has images? " +
+ // programDict[schedule.programID].hasImageArtwork);
- var programsInfo = new List<ProgramInfo>();
- foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
+ if (images != null)
+ {
+ var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
+ if (imageIndex > -1)
{
- //_logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
- // " which corresponds to channel " + channelNumber + " and program id " +
- // schedule.programID + " which says it has images? " +
- // programDict[schedule.programID].hasImageArtwork);
+ var programEntry = programDict[schedule.programID];
- if (images != null)
- {
- var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
- if (imageIndex > -1)
- {
- var programEntry = programDict[schedule.programID];
-
- var allImages = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
- var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase));
- var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase));
-
- const double DesiredAspect = 2.0 / 3;
-
- programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ??
- GetProgramImage(ApiUrl, allImages, true, DesiredAspect);
+ var allImages = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
+ var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase));
+ var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase));
- const double WideAspect = 16.0 / 9;
+ const double DesiredAspect = 2.0 / 3;
- programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect);
+ programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ??
+ GetProgramImage(ApiUrl, allImages, true, DesiredAspect);
- // Don't supply the same image twice
- if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal))
- {
- programEntry.thumbImage = null;
- }
+ const double WideAspect = 16.0 / 9;
- programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
+ programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect);
- //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
- // GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
- // GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
- // GetProgramImage(ApiUrl, data, "Banner-LOT", false);
- }
+ // Don't supply the same image twice
+ if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal))
+ {
+ programEntry.thumbImage = null;
}
- programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
- }
+ programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
- return programsInfo;
+ // programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
+ // GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
+ // GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
+ // GetProgramImage(ApiUrl, data, "Banner-LOT", false);
+ }
}
+
+ programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
}
+
+ return programsInfo;
}
private static int GetSizeOrder(ScheduleDirect.ImageData image)
@@ -212,6 +197,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
channelNumber = map.channel;
}
+
if (string.IsNullOrWhiteSpace(channelNumber))
{
channelNumber = map.atscMajor + "." + map.atscMinor;
@@ -276,7 +262,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
CommunityRating = null,
EpisodeTitle = episodeTitle,
Audio = audioType,
- //IsNew = programInfo.@new ?? false,
+ // IsNew = programInfo.@new ?? false,
IsRepeat = programInfo.@new == null,
IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase),
ImageUrl = details.primaryImage,
@@ -342,7 +328,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
info.SeriesId = programId.Substring(0, 10);
- info.SeriesProviderIds[MetadataProviders.Zap2It.ToString()] = info.SeriesId;
+ info.SeriesProviderIds[MetadataProvider.Zap2It.ToString()] = info.SeriesId;
if (details.metadata != null)
{
@@ -366,13 +352,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (!string.IsNullOrWhiteSpace(details.originalAirDate))
{
- info.OriginalAirDate = DateTime.Parse(details.originalAirDate);
+ info.OriginalAirDate = DateTime.Parse(details.originalAirDate, CultureInfo.InvariantCulture);
info.ProductionYear = info.OriginalAirDate.Value.Year;
}
if (details.movie != null)
{
- if (!string.IsNullOrEmpty(details.movie.year) && int.TryParse(details.movie.year, out int year))
+ if (!string.IsNullOrEmpty(details.movie.year)
+ && int.TryParse(details.movie.year, out int year))
{
info.ProductionYear = year;
}
@@ -400,6 +387,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
}
+
return date;
}
@@ -459,7 +447,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
ListingsProviderInfo info,
List<string> programIds,
- CancellationToken cancellationToken)
+ CancellationToken cancellationToken)
{
if (programIds.Count == 0)
{
@@ -472,7 +460,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var imageId = i.Substring(0, 10);
- if (!imageIdString.Contains(imageId))
+ if (!imageIdString.Contains(imageId, StringComparison.Ordinal))
{
imageIdString += "\"" + imageId + "\",";
}
@@ -480,22 +468,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
imageIdString = imageIdString.TrimEnd(',') + "]";
- var httpOptions = new HttpRequestOptions()
+ using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs")
{
- Url = ApiUrl + "/metadata/programs",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- RequestContent = imageIdString,
- LogErrorResponseBody = true,
+ Content = new StringContent(imageIdString, Encoding.UTF8, MediaTypeNames.Application.Json)
};
try
{
- using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false))
- {
- return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
- innerResponse2.Content).ConfigureAwait(false);
- }
+ using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
+ await using var response = await innerResponse2.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
+ response).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -516,41 +499,33 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return lineups;
}
- var options = new HttpRequestOptions()
- {
- Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
-
- options.RequestHeaders["token"] = token;
+ using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/headends?country=" + country + "&postalcode=" + location);
+ options.Headers.TryAddWithoutValidation("token", token);
try
{
- using (var httpResponse = await Get(options, false, info).ConfigureAwait(false))
- using (Stream responce = httpResponse.Content)
- {
- var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(responce).ConfigureAwait(false);
+ using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
+ await using var response = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(response).ConfigureAwait(false);
- if (root != null)
+ if (root != null)
+ {
+ foreach (ScheduleDirect.Headends headend in root)
{
- foreach (ScheduleDirect.Headends headend in root)
+ foreach (ScheduleDirect.Lineup lineup in headend.lineups)
{
- foreach (ScheduleDirect.Lineup lineup in headend.lineups)
+ lineups.Add(new NameIdPair
{
- lineups.Add(new NameIdPair
- {
- Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
- Id = lineup.uri.Substring(18)
- });
- }
+ Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
+ Id = lineup.uri.Substring(18)
+ });
}
}
- else
- {
- _logger.LogInformation("No lineups available");
- }
+ }
+ else
+ {
+ _logger.LogInformation("No lineups available");
}
}
catch (Exception ex)
@@ -585,7 +560,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return null;
}
- NameValuePair savedToken = null;
+ NameValuePair savedToken;
if (!_tokens.TryGetValue(username, out savedToken))
{
savedToken = new NameValuePair();
@@ -622,6 +597,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_lastErrorResponse = DateTime.UtcNow;
}
}
+
throw;
}
finally
@@ -630,46 +606,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
- bool enableRetry,
- ListingsProviderInfo providerInfo)
- {
- // Schedules direct requires that the client support compression and will return a 400 response without it
- options.DecompressionMethod = CompressionMethods.Deflate;
-
- try
- {
- return await _httpClient.Post(options).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- _tokens.Clear();
-
- if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
- {
- enableRetry = false;
- }
-
- if (!enableRetry)
- {
- throw;
- }
- }
-
- options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
- return await Post(options, false, providerInfo).ConfigureAwait(false);
- }
-
- private async Task<HttpResponseInfo> Get(HttpRequestOptions options,
+ private async Task<HttpResponseMessage> Send(
+ HttpRequestMessage options,
bool enableRetry,
- ListingsProviderInfo providerInfo)
+ ListingsProviderInfo providerInfo,
+ CancellationToken cancellationToken,
+ HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
{
- // Schedules direct requires that the client support compression and will return a 400 response without it
- options.DecompressionMethod = CompressionMethods.Deflate;
-
try
{
- return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
+ return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, completionOption, cancellationToken).ConfigureAwait(false);
}
catch (HttpException ex)
{
@@ -686,35 +632,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
- return await Get(options, false, providerInfo).ConfigureAwait(false);
+ options.Headers.TryAddWithoutValidation("token", await GetToken(providerInfo, cancellationToken).ConfigureAwait(false));
+ return await Send(options, false, providerInfo, cancellationToken).ConfigureAwait(false);
}
- private async Task<string> GetTokenInternal(string username, string password,
+ private async Task<string> GetTokenInternal(
+ string username,
+ string password,
CancellationToken cancellationToken)
{
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/token",
- UserAgent = UserAgent,
- RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}",
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
- //_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
- // httpOptions.RequestContent);
+ using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token");
+ options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json);
- using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
+ using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(stream).ConfigureAwait(false);
+ if (root.message == "OK")
{
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(response.Content).ConfigureAwait(false);
- if (root.message == "OK")
- {
- _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
- return root.token;
- }
-
- throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
+ _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
+ return root.token;
}
+
+ throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
}
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
@@ -733,20 +672,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("Adding new LineUp ");
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups/" + info.ListingsId,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- BufferContent = false
- };
-
- httpOptions.RequestHeaders["token"] = token;
-
- using (await _httpClient.SendAsync(httpOptions, HttpMethod.Put).ConfigureAwait(false))
- {
- }
+ using var options = new HttpRequestMessage(HttpMethod.Put, ApiUrl + "/lineups/" + info.ListingsId);
+ options.Headers.TryAddWithoutValidation("token", token);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
}
private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)
@@ -765,25 +693,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("Headends on account ");
- var options = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
-
- options.RequestHeaders["token"] = token;
+ using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups");
+ options.Headers.TryAddWithoutValidation("token", token);
try
{
- using (var httpResponse = await Get(options, false, null).ConfigureAwait(false))
- using (var response = httpResponse.Content)
- {
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false);
+ using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
+ await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var response = httpResponse.Content;
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(stream).ConfigureAwait(false);
- return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase));
- }
+ return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase));
}
catch (HttpException ex)
{
@@ -805,11 +725,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
throw new ArgumentException("Username is required");
}
+
if (string.IsNullOrEmpty(info.Password))
{
throw new ArgumentException("Password is required");
}
}
+
if (validateListings)
{
if (string.IsNullOrEmpty(info.ListingsId))
@@ -846,55 +768,43 @@ namespace Emby.Server.Implementations.LiveTv.Listings
throw new Exception("token required");
}
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups/" + listingsId,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- };
-
- httpOptions.RequestHeaders["token"] = token;
+ using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);
+ options.Headers.TryAddWithoutValidation("token", token);
var list = new List<ChannelInfo>();
- using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false))
- using (var response = httpResponse.Content)
- {
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(response).ConfigureAwait(false);
- _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
- _logger.LogInformation("Mapping Stations to Channel");
+ using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
+ await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(stream).ConfigureAwait(false);
+ _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
+ _logger.LogInformation("Mapping Stations to Channel");
- var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
+ var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
- foreach (ScheduleDirect.Map map in root.map)
- {
- var channelNumber = GetChannelNumber(map);
-
- var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
- if (station == null)
- {
- station = new ScheduleDirect.Station
- {
- stationID = map.stationID
- };
- }
+ foreach (ScheduleDirect.Map map in root.map)
+ {
+ var channelNumber = GetChannelNumber(map);
- var channelInfo = new ChannelInfo
- {
- Id = station.stationID,
- CallSign = station.callsign,
- Number = channelNumber,
- Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name
- };
+ var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
+ if (station == null)
+ {
+ station = new ScheduleDirect.Station { stationID = map.stationID };
+ }
- if (station.logo != null)
- {
- channelInfo.ImageUrl = station.logo.URL;
- }
+ var channelInfo = new ChannelInfo
+ {
+ Id = station.stationID,
+ CallSign = station.callsign,
+ Number = channelNumber,
+ Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name
+ };
- list.Add(channelInfo);
+ if (station.logo != null)
+ {
+ channelInfo.ImageUrl = station.logo.URL;
}
+
+ list.Add(channelInfo);
}
return list;
@@ -924,7 +834,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private static string NormalizeName(string value)
{
- return value.Replace(" ", string.Empty).Replace("-", string.Empty);
+ return value.Replace(" ", string.Empty, StringComparison.Ordinal).Replace("-", string.Empty, StringComparison.Ordinal);
}
public class ScheduleDirect
@@ -932,144 +842,194 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Token
{
public int code { get; set; }
+
public string message { get; set; }
+
public string serverID { get; set; }
+
public string token { get; set; }
}
+
public class Lineup
{
public string lineup { get; set; }
+
public string name { get; set; }
+
public string transport { get; set; }
+
public string location { get; set; }
+
public string uri { get; set; }
}
public class Lineups
{
public int code { get; set; }
+
public string serverID { get; set; }
+
public string datetime { get; set; }
+
public List<Lineup> lineups { get; set; }
}
-
public class Headends
{
public string headend { get; set; }
+
public string transport { get; set; }
+
public string location { get; set; }
+
public List<Lineup> lineups { get; set; }
}
-
-
public class Map
{
public string stationID { get; set; }
+
public string channel { get; set; }
+
public string logicalChannelNumber { get; set; }
+
public int uhfVhf { get; set; }
+
public int atscMajor { get; set; }
+
public int atscMinor { get; set; }
}
public class Broadcaster
{
public string city { get; set; }
+
public string state { get; set; }
+
public string postalcode { get; set; }
+
public string country { get; set; }
}
public class Logo
{
public string URL { get; set; }
+
public int height { get; set; }
+
public int width { get; set; }
+
public string md5 { get; set; }
}
public class Station
{
public string stationID { get; set; }
+
public string name { get; set; }
+
public string callsign { get; set; }
+
public List<string> broadcastLanguage { get; set; }
+
public List<string> descriptionLanguage { get; set; }
+
public Broadcaster broadcaster { get; set; }
+
public string affiliate { get; set; }
+
public Logo logo { get; set; }
+
public bool? isCommercialFree { get; set; }
}
public class Metadata
{
public string lineup { get; set; }
+
public string modified { get; set; }
+
public string transport { get; set; }
}
public class Channel
{
public List<Map> map { get; set; }
+
public List<Station> stations { get; set; }
+
public Metadata metadata { get; set; }
}
public class RequestScheduleForChannel
{
public string stationID { get; set; }
+
public List<string> date { get; set; }
}
-
-
-
public class Rating
{
public string body { get; set; }
+
public string code { get; set; }
}
public class Multipart
{
public int partNumber { get; set; }
+
public int totalParts { get; set; }
}
public class Program
{
public string programID { get; set; }
+
public string airDateTime { get; set; }
+
public int duration { get; set; }
+
public string md5 { get; set; }
+
public List<string> audioProperties { get; set; }
+
public List<string> videoProperties { get; set; }
+
public List<Rating> ratings { get; set; }
+
public bool? @new { get; set; }
+
public Multipart multipart { get; set; }
+
public string liveTapeDelay { get; set; }
+
public bool premiere { get; set; }
+
public bool repeat { get; set; }
+
public string isPremiereOrFinale { get; set; }
}
-
-
public class MetadataSchedule
{
public string modified { get; set; }
+
public string md5 { get; set; }
+
public string startDate { get; set; }
+
public string endDate { get; set; }
+
public int days { get; set; }
}
public class Day
{
public string stationID { get; set; }
+
public List<Program> programs { get; set; }
+
public MetadataSchedule metadata { get; set; }
public Day()
@@ -1092,24 +1052,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Description100
{
public string descriptionLanguage { get; set; }
+
public string description { get; set; }
}
public class Description1000
{
public string descriptionLanguage { get; set; }
+
public string description { get; set; }
}
public class DescriptionsProgram
{
public List<Description100> description100 { get; set; }
+
public List<Description1000> description1000 { get; set; }
}
public class Gracenote
{
public int season { get; set; }
+
public int episode { get; set; }
}
@@ -1121,104 +1085,154 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class ContentRating
{
public string body { get; set; }
+
public string code { get; set; }
}
public class Cast
{
public string billingOrder { get; set; }
+
public string role { get; set; }
+
public string nameId { get; set; }
+
public string personId { get; set; }
+
public string name { get; set; }
+
public string characterName { get; set; }
}
public class Crew
{
public string billingOrder { get; set; }
+
public string role { get; set; }
+
public string nameId { get; set; }
+
public string personId { get; set; }
+
public string name { get; set; }
}
public class QualityRating
{
public string ratingsBody { get; set; }
+
public string rating { get; set; }
+
public string minRating { get; set; }
+
public string maxRating { get; set; }
+
public string increment { get; set; }
}
public class Movie
{
public string year { get; set; }
+
public int duration { get; set; }
+
public List<QualityRating> qualityRating { get; set; }
}
public class Recommendation
{
public string programID { get; set; }
+
public string title120 { get; set; }
}
public class ProgramDetails
{
public string audience { get; set; }
+
public string programID { get; set; }
+
public List<Title> titles { get; set; }
+
public EventDetails eventDetails { get; set; }
+
public DescriptionsProgram descriptions { get; set; }
+
public string originalAirDate { get; set; }
+
public List<string> genres { get; set; }
+
public string episodeTitle150 { get; set; }
+
public List<MetadataPrograms> metadata { get; set; }
+
public List<ContentRating> contentRating { get; set; }
+
public List<Cast> cast { get; set; }
+
public List<Crew> crew { get; set; }
+
public string entityType { get; set; }
+
public string showType { get; set; }
+
public bool hasImageArtwork { get; set; }
+
public string primaryImage { get; set; }
+
public string thumbImage { get; set; }
+
public string backdropImage { get; set; }
+
public string bannerImage { get; set; }
+
public string imageID { get; set; }
+
public string md5 { get; set; }
+
public List<string> contentAdvisory { get; set; }
+
public Movie movie { get; set; }
+
public List<Recommendation> recommendations { get; set; }
}
public class Caption
{
public string content { get; set; }
+
public string lang { get; set; }
}
public class ImageData
{
public string width { get; set; }
+
public string height { get; set; }
+
public string uri { get; set; }
+
public string size { get; set; }
+
public string aspect { get; set; }
+
public string category { get; set; }
+
public string text { get; set; }
+
public string primary { get; set; }
+
public string tier { get; set; }
+
public Caption caption { get; set; }
}
public class ShowImages
{
public string programID { get; set; }
+
public List<ImageData> data { get; set; }
}
-
}
}
}