|
@@ -28,8 +28,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
|
|
private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
|
|
|
|
|
|
- private readonly ConcurrentDictionary<string, ScheduleDirect.Station> _channelPair =
|
|
|
|
- new ConcurrentDictionary<string, ScheduleDirect.Station>();
|
|
|
|
|
|
+ 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)
|
|
public SchedulesDirect(ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IApplicationHost appHost)
|
|
{
|
|
{
|
|
@@ -68,29 +68,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(token))
|
|
if (string.IsNullOrWhiteSpace(token))
|
|
{
|
|
{
|
|
|
|
+ _logger.Warn("SchedulesDirect token is empty, returning empty program list");
|
|
return programsInfo;
|
|
return programsInfo;
|
|
}
|
|
}
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(info.ListingsId))
|
|
if (string.IsNullOrWhiteSpace(info.ListingsId))
|
|
{
|
|
{
|
|
|
|
+ _logger.Warn("ListingsId is null, returning empty program list");
|
|
return programsInfo;
|
|
return programsInfo;
|
|
}
|
|
}
|
|
|
|
|
|
- var httpOptions = new HttpRequestOptions()
|
|
|
|
- {
|
|
|
|
- Url = ApiUrl + "/schedules",
|
|
|
|
- UserAgent = UserAgent,
|
|
|
|
- CancellationToken = cancellationToken,
|
|
|
|
- // The data can be large so give it some extra time
|
|
|
|
- TimeoutMs = 60000,
|
|
|
|
- LogErrorResponseBody = true
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- httpOptions.RequestHeaders["token"] = token;
|
|
|
|
-
|
|
|
|
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
|
|
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
|
|
|
|
|
|
- ScheduleDirect.Station station = GetStation(channelNumber, channelName);
|
|
|
|
|
|
+ ScheduleDirect.Station station = GetStation(info.ListingsId, channelNumber, channelName);
|
|
|
|
|
|
if (station == null)
|
|
if (station == null)
|
|
{
|
|
{
|
|
@@ -113,13 +103,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
var requestString = _jsonSerializer.SerializeToString(requestList);
|
|
var requestString = _jsonSerializer.SerializeToString(requestList);
|
|
_logger.Debug("Request string for schedules is: " + requestString);
|
|
_logger.Debug("Request string for schedules is: " + requestString);
|
|
|
|
+
|
|
|
|
+ var httpOptions = new HttpRequestOptions()
|
|
|
|
+ {
|
|
|
|
+ Url = ApiUrl + "/schedules",
|
|
|
|
+ UserAgent = UserAgent,
|
|
|
|
+ CancellationToken = cancellationToken,
|
|
|
|
+ // The data can be large so give it some extra time
|
|
|
|
+ TimeoutMs = 60000,
|
|
|
|
+ LogErrorResponseBody = true
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ httpOptions.RequestHeaders["token"] = token;
|
|
|
|
+
|
|
httpOptions.RequestContent = requestString;
|
|
httpOptions.RequestContent = requestString;
|
|
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
|
|
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
|
|
{
|
|
{
|
|
StreamReader reader = new StreamReader(response.Content);
|
|
StreamReader reader = new StreamReader(response.Content);
|
|
string responseString = reader.ReadToEnd();
|
|
string responseString = reader.ReadToEnd();
|
|
var dailySchedules = _jsonSerializer.DeserializeFromString<List<ScheduleDirect.Day>>(responseString);
|
|
var dailySchedules = _jsonSerializer.DeserializeFromString<List<ScheduleDirect.Day>>(responseString);
|
|
- _logger.Debug("Found " + dailySchedules.Count() + " programs on " + channelNumber + " ScheduleDirect");
|
|
|
|
|
|
+ _logger.Debug("Found " + dailySchedules.Count + " programs on " + channelNumber + " ScheduleDirect");
|
|
|
|
|
|
httpOptions = new HttpRequestOptions()
|
|
httpOptions = new HttpRequestOptions()
|
|
{
|
|
{
|
|
@@ -176,23 +179,77 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
return programsInfo;
|
|
return programsInfo;
|
|
}
|
|
}
|
|
|
|
|
|
- private ScheduleDirect.Station GetStation(string channelNumber, string channelName)
|
|
|
|
|
|
+ private readonly object _channelCacheLock = new object();
|
|
|
|
+ private ScheduleDirect.Station GetStation(string listingsId, string channelNumber, string channelName)
|
|
{
|
|
{
|
|
- ScheduleDirect.Station station;
|
|
|
|
|
|
+ lock (_channelCacheLock)
|
|
|
|
+ {
|
|
|
|
+ Dictionary<string, ScheduleDirect.Station> channelPair;
|
|
|
|
+ if (_channelPairingCache.TryGetValue(listingsId, out channelPair))
|
|
|
|
+ {
|
|
|
|
+ ScheduleDirect.Station station;
|
|
|
|
+
|
|
|
|
+ if (channelPair.TryGetValue(channelNumber, out station))
|
|
|
|
+ {
|
|
|
|
+ return station;
|
|
|
|
+ }
|
|
|
|
|
|
- if (_channelPair.TryGetValue(channelNumber, out station))
|
|
|
|
|
|
+ if (string.IsNullOrWhiteSpace(channelName))
|
|
|
|
+ {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ channelName = NormalizeName(channelName);
|
|
|
|
+
|
|
|
|
+ return channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void AddToChannelPairCache(string listingsId, string channelNumber, ScheduleDirect.Station schChannel)
|
|
|
|
+ {
|
|
|
|
+ lock (_channelCacheLock)
|
|
{
|
|
{
|
|
- return station;
|
|
|
|
|
|
+ Dictionary<string, ScheduleDirect.Station> cache;
|
|
|
|
+ if (_channelPairingCache.TryGetValue(listingsId, out cache))
|
|
|
|
+ {
|
|
|
|
+ cache[channelNumber] = schChannel;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ cache = new Dictionary<string, ScheduleDirect.Station>();
|
|
|
|
+ cache[channelNumber] = schChannel;
|
|
|
|
+ _channelPairingCache[listingsId] = cache;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- if (string.IsNullOrWhiteSpace(channelName))
|
|
|
|
|
|
+ private void ClearPairCache(string listingsId)
|
|
|
|
+ {
|
|
|
|
+ lock (_channelCacheLock)
|
|
{
|
|
{
|
|
- return null;
|
|
|
|
|
|
+ Dictionary<string, ScheduleDirect.Station> cache;
|
|
|
|
+ if (_channelPairingCache.TryGetValue(listingsId, out cache))
|
|
|
|
+ {
|
|
|
|
+ cache.Clear();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- channelName = NormalizeName(channelName);
|
|
|
|
|
|
+ private int GetChannelPairCacheCount(string listingsId)
|
|
|
|
+ {
|
|
|
|
+ lock (_channelCacheLock)
|
|
|
|
+ {
|
|
|
|
+ Dictionary<string, ScheduleDirect.Station> cache;
|
|
|
|
+ if (_channelPairingCache.TryGetValue(listingsId, out cache))
|
|
|
|
+ {
|
|
|
|
+ return cache.Count;
|
|
|
|
+ }
|
|
|
|
|
|
- return _channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
private string NormalizeName(string value)
|
|
private string NormalizeName(string value)
|
|
@@ -203,7 +260,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels,
|
|
public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels,
|
|
CancellationToken cancellationToken)
|
|
CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
- if (string.IsNullOrWhiteSpace(info.ListingsId))
|
|
|
|
|
|
+ var listingsId = info.ListingsId;
|
|
|
|
+ if (string.IsNullOrWhiteSpace(listingsId))
|
|
{
|
|
{
|
|
throw new Exception("ListingsId required");
|
|
throw new Exception("ListingsId required");
|
|
}
|
|
}
|
|
@@ -215,11 +273,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
throw new Exception("token required");
|
|
throw new Exception("token required");
|
|
}
|
|
}
|
|
|
|
|
|
- _channelPair.Clear();
|
|
|
|
|
|
+ ClearPairCache(listingsId);
|
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
var httpOptions = new HttpRequestOptions()
|
|
{
|
|
{
|
|
- Url = ApiUrl + "/lineups/" + info.ListingsId,
|
|
|
|
|
|
+ Url = ApiUrl + "/lineups/" + listingsId,
|
|
UserAgent = UserAgent,
|
|
UserAgent = UserAgent,
|
|
CancellationToken = cancellationToken,
|
|
CancellationToken = cancellationToken,
|
|
LogErrorResponseBody = true,
|
|
LogErrorResponseBody = true,
|
|
@@ -232,7 +290,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
|
|
using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
|
|
{
|
|
{
|
|
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
|
|
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
|
|
- _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect");
|
|
|
|
|
|
+ _logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
|
|
_logger.Info("Mapping Stations to Channel");
|
|
_logger.Info("Mapping Stations to Channel");
|
|
foreach (ScheduleDirect.Map map in root.map)
|
|
foreach (ScheduleDirect.Map map in root.map)
|
|
{
|
|
{
|
|
@@ -251,13 +309,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|
_logger.Debug("Found channel: " + channelNumber + " in Schedules Direct");
|
|
_logger.Debug("Found channel: " + channelNumber + " in Schedules Direct");
|
|
var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID);
|
|
var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID);
|
|
|
|
|
|
- _channelPair.TryAdd(channelNumber, schChannel);
|
|
|
|
|
|
+ AddToChannelPairCache(listingsId, channelNumber, schChannel);
|
|
}
|
|
}
|
|
- _logger.Info("Added " + _channelPair.Count + " channels to the dictionary");
|
|
|
|
|
|
+ _logger.Info("Added " + GetChannelPairCacheCount(listingsId) + " channels to the dictionary");
|
|
|
|
|
|
foreach (ChannelInfo channel in channels)
|
|
foreach (ChannelInfo channel in channels)
|
|
{
|
|
{
|
|
- var station = GetStation(channel.Number, channel.Name);
|
|
|
|
|
|
+ var station = GetStation(listingsId, channel.Number, channel.Name);
|
|
|
|
|
|
if (station != null)
|
|
if (station != null)
|
|
{
|
|
{
|