@ -28,8 +28,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
private const string ApiUrl = "https://json.schedulesdirect.org/20141201" ;
private readonly Concurrent Dictionary< string , ScheduleDirect . Station > _channelPair =
new Concurrent Dictionary< string , ScheduleDirect . Station > () ;
private readonly Dictionary< string , Dictionary< string , ScheduleDirect . Station > > _channelPair ingCache =
new Dictionary< string , Dictionary< string , ScheduleDirect . Station > > (StringComparer . OrdinalIgnoreCase ) ;
public SchedulesDirect ( ILogger logger , IJsonSerializer jsonSerializer , IHttpClient httpClient , IApplicationHost appHost )
{
@ -68,29 +68,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
if ( string . IsNullOrWhiteSpace ( token ) )
{
_logger . Warn ( "SchedulesDirect token is empty, returning empty program list" ) ;
return programsInfo ;
}
if ( string . IsNullOrWhiteSpace ( info . ListingsId ) )
{
_logger . Warn ( "ListingsId is null, returning empty program list" ) ;
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 ) ;
ScheduleDirect . Station station = GetStation ( channelNumber, channelName ) ;
ScheduleDirect . Station station = GetStation ( info . ListingsId , channelNumber , channelName ) ;
if ( station = = null )
{
@ -113,13 +103,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
var requestString = _jsonSerializer . SerializeToString ( requestList ) ;
_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 ;
using ( var response = await Post ( httpOptions , true , info ) . ConfigureAwait ( false ) )
{
StreamReader reader = new StreamReader ( response . Content ) ;
string responseString = reader . ReadToEnd ( ) ;
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 ( )
{
@ -176,11 +179,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
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 ;
if ( _channelPair . TryGetValue ( channelNumber , out station ) )
if ( channelPair. TryGetValue ( channelNumber , out station ) )
{
return station ;
}
@ -192,7 +201,55 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
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 )
@ -203,7 +260,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
public async Task AddMetadata ( ListingsProviderInfo info , List < ChannelInfo > channels ,
CancellationToken cancellationToken )
{
if ( string . IsNullOrWhiteSpace ( info . ListingsId ) )
var listingsId = info . ListingsId ;
if ( string . IsNullOrWhiteSpace ( listingsId ) )
{
throw new Exception ( "ListingsId required" ) ;
}
@ -215,11 +273,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
throw new Exception ( "token required" ) ;
}
_channelPair. Clear ( ) ;
ClearPairCache( listingsId ) ;
var httpOptions = new HttpRequestOptions ( )
{
Url = ApiUrl + "/lineups/" + info. L istingsId,
Url = ApiUrl + "/lineups/" + l istingsId,
UserAgent = UserAgent ,
CancellationToken = cancellationToken ,
LogErrorResponseBody = true ,
@ -232,7 +290,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
using ( var response = await Get ( httpOptions , true , info ) . ConfigureAwait ( false ) )
{
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" ) ;
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" ) ;
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 )
{
var station = GetStation ( channel. Number , channel . Name ) ;
var station = GetStation ( listingsId, channel. Number , channel . Name ) ;
if ( station ! = null )
{