update multi-tuner support

pull/702/head
Luke Pulverenti 9 years ago
parent 14b9f94e0a
commit 623fd6ff92

@ -588,6 +588,10 @@ namespace MediaBrowser.Dlna.Ssdp
{ {
} }
catch (Exception)
{
// If called while shutting down, seeing a NullReferenceException inside EndReceive
}
} }
} }

@ -232,7 +232,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
} }
} }
_channelCache = list; _channelCache = list.ToList();
return list; return list;
} }
@ -520,9 +520,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{ {
if (!IsListingProviderEnabledForTuner(provider.Item2, channel.TunerHostId)) if (!IsListingProviderEnabledForTuner(provider.Item2, channel.TunerHostId))
{ {
_logger.Debug("Skipping getting programs for channel {0}-{1} from {2}-{3}, because it's not enabled for this tuner.", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
continue; continue;
} }
_logger.Debug("Getting programs for channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken) var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);

@ -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 = private readonly Dictionary<string, Dictionary<string, ScheduleDirect.Station>> _channelPairingCache =
new ConcurrentDictionary<string, ScheduleDirect.Station>(); 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,11 +179,17 @@ 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)
{
lock (_channelCacheLock)
{
Dictionary<string, ScheduleDirect.Station> channelPair;
if (_channelPairingCache.TryGetValue(listingsId, out channelPair))
{ {
ScheduleDirect.Station station; ScheduleDirect.Station station;
if (_channelPair.TryGetValue(channelNumber, out station)) if (channelPair.TryGetValue(channelNumber, out station))
{ {
return station; return station;
} }
@ -192,7 +201,55 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
channelName = NormalizeName(channelName); channelName = NormalizeName(channelName);
return _channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase)); 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)
{
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;
}
}
}
private void ClearPairCache(string listingsId)
{
lock (_channelCacheLock)
{
Dictionary<string, ScheduleDirect.Station> cache;
if (_channelPairingCache.TryGetValue(listingsId, out cache))
{
cache.Clear();
}
}
}
private int GetChannelPairCacheCount(string listingsId)
{
lock (_channelCacheLock)
{
Dictionary<string, ScheduleDirect.Station> cache;
if (_channelPairingCache.TryGetValue(listingsId, out cache))
{
return cache.Count;
}
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)
{ {

Loading…
Cancel
Save