|
@@ -16,8 +16,6 @@ using System.Linq;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
using MediaBrowser.Model.Extensions;
|
|
|
-using MediaBrowser.Controller.Entities.TV;
|
|
|
-using MediaBrowser.Controller.Providers;
|
|
|
using MediaBrowser.Model.Entities;
|
|
|
|
|
|
namespace Emby.Server.Implementations.LiveTv.Listings
|
|
@@ -32,9 +30,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
|
|
|
|
|
|
- private readonly Dictionary<string, Dictionary<string, ScheduleDirect.Station>> _channelPairingCache =
|
|
|
- new Dictionary<string, Dictionary<string, ScheduleDirect.Station>>(StringComparer.OrdinalIgnoreCase);
|
|
|
-
|
|
|
public SchedulesDirect(ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IApplicationHost appHost)
|
|
|
{
|
|
|
_logger = logger;
|
|
@@ -74,33 +69,29 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
// Normalize incoming input
|
|
|
channelId = channelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
|
|
|
|
|
|
- List<ProgramInfo> programsInfo = new List<ProgramInfo>();
|
|
|
-
|
|
|
var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
if (string.IsNullOrEmpty(token))
|
|
|
{
|
|
|
_logger.LogWarning("SchedulesDirect token is empty, returning empty program list");
|
|
|
- return programsInfo;
|
|
|
+
|
|
|
+ return Enumerable.Empty<ProgramInfo>();
|
|
|
}
|
|
|
|
|
|
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
|
|
|
|
|
|
- string stationID = channelId;
|
|
|
-
|
|
|
- _logger.LogInformation("Channel Station ID is: " + stationID);
|
|
|
- List<ScheduleDirect.RequestScheduleForChannel> requestList =
|
|
|
- new List<ScheduleDirect.RequestScheduleForChannel>()
|
|
|
+ _logger.LogInformation("Channel Station ID is: {ChannelID}", channelId);
|
|
|
+ var requestList = new List<ScheduleDirect.RequestScheduleForChannel>()
|
|
|
+ {
|
|
|
+ new ScheduleDirect.RequestScheduleForChannel()
|
|
|
{
|
|
|
- new ScheduleDirect.RequestScheduleForChannel()
|
|
|
- {
|
|
|
- stationID = stationID,
|
|
|
- date = dates
|
|
|
- }
|
|
|
- };
|
|
|
+ stationID = channelId,
|
|
|
+ date = dates
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
var requestString = _jsonSerializer.SerializeToString(requestList);
|
|
|
- _logger.LogDebug("Request string for schedules is: " + requestString);
|
|
|
+ _logger.LogDebug("Request string for schedules is: {RequestString}", requestString);
|
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
|
{
|
|
@@ -109,16 +100,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
CancellationToken = cancellationToken,
|
|
|
// The data can be large so give it some extra time
|
|
|
TimeoutMs = 60000,
|
|
|
- LogErrorResponseBody = true
|
|
|
+ LogErrorResponseBody = true,
|
|
|
+ RequestContent = requestString
|
|
|
};
|
|
|
|
|
|
httpOptions.RequestHeaders["token"] = token;
|
|
|
|
|
|
- httpOptions.RequestContent = requestString;
|
|
|
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
|
|
|
+ using (StreamReader reader = new StreamReader(response.Content))
|
|
|
{
|
|
|
var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false);
|
|
|
- _logger.LogDebug("Found {ScheduleCount} programs on {StationID} ScheduleDirect", dailySchedules.Count, stationID);
|
|
|
+ _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
|
|
|
|
|
|
httpOptions = new HttpRequestOptions()
|
|
|
{
|
|
@@ -132,14 +124,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
httpOptions.RequestHeaders["token"] = token;
|
|
|
|
|
|
- List<string> programsID = new List<string>();
|
|
|
- programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct().ToList();
|
|
|
- var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]";
|
|
|
- httpOptions.RequestContent = requestBody;
|
|
|
-
|
|
|
- double wideAspect = 1.77777778;
|
|
|
+ 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))
|
|
|
+ using (StreamReader innerReader = new StreamReader(innerResponse.Content))
|
|
|
{
|
|
|
var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false);
|
|
|
var programDict = programDetails.ToDictionary(p => p.programID, y => y);
|
|
@@ -150,8 +139,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
- var schedules = dailySchedules.SelectMany(d => d.programs);
|
|
|
- foreach (ScheduleDirect.Program schedule in schedules)
|
|
|
+ List<ProgramInfo> 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 " +
|
|
@@ -165,15 +154,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
{
|
|
|
var programEntry = programDict[schedule.programID];
|
|
|
|
|
|
- var allImages = (images[imageIndex].data ?? new List<ScheduleDirect.ImageData>()).ToList();
|
|
|
- var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)).ToList();
|
|
|
- var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase)).ToList();
|
|
|
+ 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));
|
|
|
|
|
|
- double desiredAspect = 0.666666667;
|
|
|
+ const double desiredAspect = 0.666666667;
|
|
|
|
|
|
programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, desiredAspect) ??
|
|
|
GetProgramImage(ApiUrl, allImages, true, desiredAspect);
|
|
|
|
|
|
+ const double wideAspect = 1.77777778;
|
|
|
+
|
|
|
programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, wideAspect);
|
|
|
|
|
|
// Don't supply the same image twice
|
|
@@ -193,18 +184,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
|
|
|
}
|
|
|
+ return programsInfo;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return programsInfo;
|
|
|
}
|
|
|
|
|
|
private int GetSizeOrder(ScheduleDirect.ImageData image)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(image.height))
|
|
|
{
|
|
|
- int value;
|
|
|
- if (int.TryParse(image.height, out value))
|
|
|
+ if (int.TryParse(image.height, out int value))
|
|
|
{
|
|
|
return value;
|
|
|
}
|
|
@@ -225,9 +214,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
{
|
|
|
channelNumber = map.atscMajor + "." + map.atscMinor;
|
|
|
}
|
|
|
- channelNumber = channelNumber.TrimStart('0');
|
|
|
|
|
|
- return channelNumber;
|
|
|
+ return channelNumber.TrimStart('0');
|
|
|
}
|
|
|
|
|
|
private bool IsMovie(ScheduleDirect.ProgramDetails programInfo)
|
|
@@ -382,8 +370,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
if (details.movie != null)
|
|
|
{
|
|
|
- int year;
|
|
|
- if (!string.IsNullOrEmpty(details.movie.year) && int.TryParse(details.movie.year, out year))
|
|
|
+ if (!string.IsNullOrEmpty(details.movie.year) && int.TryParse(details.movie.year, out int year))
|
|
|
{
|
|
|
info.ProductionYear = year;
|
|
|
}
|
|
@@ -414,18 +401,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
return date;
|
|
|
}
|
|
|
|
|
|
- private string GetProgramImage(string apiUrl, List<ScheduleDirect.ImageData> images, bool returnDefaultImage, double desiredAspect)
|
|
|
+ private string GetProgramImage(string apiUrl, IEnumerable<ScheduleDirect.ImageData> images, bool returnDefaultImage, double desiredAspect)
|
|
|
{
|
|
|
- string url = null;
|
|
|
-
|
|
|
- var matches = images;
|
|
|
-
|
|
|
- matches = matches
|
|
|
- .OrderBy(i => Math.Abs(desiredAspect - GetApsectRatio(i)))
|
|
|
+ var match = images
|
|
|
+ .OrderBy(i => Math.Abs(desiredAspect - GetAspectRatio(i)))
|
|
|
.ThenByDescending(GetSizeOrder)
|
|
|
- .ToList();
|
|
|
-
|
|
|
- var match = matches.FirstOrDefault();
|
|
|
+ .FirstOrDefault();
|
|
|
|
|
|
if (match == null)
|
|
|
{
|
|
@@ -434,22 +415,21 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
var uri = match.uri;
|
|
|
|
|
|
- if (!string.IsNullOrWhiteSpace(uri))
|
|
|
+ if (string.IsNullOrWhiteSpace(uri))
|
|
|
{
|
|
|
- if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
|
|
|
- {
|
|
|
- url = uri;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- url = apiUrl + "/image/" + uri;
|
|
|
- }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ else if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
|
|
|
+ {
|
|
|
+ return uri;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return apiUrl + "/image/" + uri;
|
|
|
}
|
|
|
- //_logger.LogDebug("URL for image is : " + url);
|
|
|
- return url;
|
|
|
}
|
|
|
|
|
|
- private double GetApsectRatio(ScheduleDirect.ImageData i)
|
|
|
+ private double GetAspectRatio(ScheduleDirect.ImageData i)
|
|
|
{
|
|
|
int width = 0;
|
|
|
int height = 0;
|
|
@@ -614,8 +594,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
if (!string.IsNullOrEmpty(savedToken.Name) && !string.IsNullOrEmpty(savedToken.Value))
|
|
|
{
|
|
|
- long ticks;
|
|
|
- if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
|
|
|
+ if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out long ticks))
|
|
|
{
|
|
|
// If it's under 24 hours old we can still use it
|
|
|
if (DateTime.UtcNow.Ticks - ticks < TimeSpan.FromHours(20).Ticks)
|
|
@@ -685,8 +664,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
|
|
|
- options.RequestHeaders["token"] = newToken;
|
|
|
+ options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);;
|
|
|
return await Post(options, false, providerInfo).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
@@ -724,8 +702,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
|
|
|
- options.RequestHeaders["token"] = newToken;
|
|
|
+ options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
|
|
|
return await Get(options, false, providerInfo).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
@@ -743,9 +720,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
//_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
|
|
|
// httpOptions.RequestContent);
|
|
|
|
|
|
- using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false))
|
|
|
+ using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
|
|
|
{
|
|
|
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(responce.Content).ConfigureAwait(false);
|
|
|
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(response.Content).ConfigureAwait(false);
|
|
|
if (root.message == "OK")
|
|
|
{
|
|
|
_logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
|
|
@@ -828,13 +805,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
try
|
|
|
{
|
|
|
using (var httpResponse = await Get(options, false, null).ConfigureAwait(false))
|
|
|
+ using (var response = httpResponse.Content)
|
|
|
{
|
|
|
- using (var response = httpResponse.Content)
|
|
|
- {
|
|
|
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false);
|
|
|
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).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)
|
|
@@ -913,54 +888,41 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
var list = new List<ChannelInfo>();
|
|
|
|
|
|
using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false))
|
|
|
+ using (var response = httpResponse.Content)
|
|
|
{
|
|
|
- using (var response = httpResponse.Content)
|
|
|
- {
|
|
|
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(response).ConfigureAwait(false);
|
|
|
- _logger.LogInformation("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
|
|
|
- _logger.LogInformation("Mapping Stations to Channel");
|
|
|
-
|
|
|
- var allStations = root.stations ?? new List<ScheduleDirect.Station>();
|
|
|
+ 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");
|
|
|
|
|
|
- foreach (ScheduleDirect.Map map in root.map)
|
|
|
- {
|
|
|
- var channelNumber = GetChannelNumber(map);
|
|
|
+ var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
|
|
|
|
|
|
- var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
|
|
|
- if (station == null)
|
|
|
- {
|
|
|
- station = new ScheduleDirect.Station
|
|
|
- {
|
|
|
- stationID = map.stationID
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- var name = channelNumber;
|
|
|
+ foreach (ScheduleDirect.Map map in root.map)
|
|
|
+ {
|
|
|
+ var channelNumber = GetChannelNumber(map);
|
|
|
|
|
|
- var channelInfo = new ChannelInfo
|
|
|
+ var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
|
|
|
+ if (station == null)
|
|
|
+ {
|
|
|
+ station = new ScheduleDirect.Station
|
|
|
{
|
|
|
- Number = channelNumber,
|
|
|
- Name = name
|
|
|
+ stationID = map.stationID
|
|
|
};
|
|
|
+ }
|
|
|
|
|
|
- if (station != null)
|
|
|
- {
|
|
|
- if (!string.IsNullOrWhiteSpace(station.name))
|
|
|
- {
|
|
|
- channelInfo.Name = station.name;
|
|
|
- }
|
|
|
-
|
|
|
- channelInfo.Id = station.stationID;
|
|
|
- channelInfo.CallSign = station.callsign;
|
|
|
-
|
|
|
- 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);
|
|
|
}
|
|
|
}
|
|
|
|