|
@@ -15,6 +15,7 @@ using System.IO;
|
|
|
using System.Linq;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
+using MediaBrowser.Model.Extensions;
|
|
|
|
|
|
namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
{
|
|
@@ -60,8 +61,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
return dates;
|
|
|
}
|
|
|
|
|
|
- public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
|
|
|
+ public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
|
|
|
{
|
|
|
+ if (string.IsNullOrWhiteSpace(channelId))
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("channelId");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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);
|
|
@@ -80,15 +89,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
|
|
|
|
|
|
- ScheduleDirect.Station station = GetStation(info.ListingsId, channelNumber, channelName);
|
|
|
-
|
|
|
- if (station == null)
|
|
|
- {
|
|
|
- _logger.Info("No Schedules Direct Station found for channel {0} with name {1}", channelNumber, channelName);
|
|
|
- return programsInfo;
|
|
|
- }
|
|
|
-
|
|
|
- string stationID = station.stationID;
|
|
|
+ string stationID = channelId;
|
|
|
|
|
|
_logger.Info("Channel Station ID is: " + stationID);
|
|
|
List<ScheduleDirect.RequestScheduleForChannel> requestList =
|
|
@@ -122,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
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 " + stationID + " ScheduleDirect");
|
|
|
|
|
|
httpOptions = new HttpRequestOptions()
|
|
|
{
|
|
@@ -180,7 +181,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- programsInfo.Add(GetProgram(channelNumber, schedule, programDict[schedule.programID]));
|
|
|
+ programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -202,183 +203,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- private readonly object _channelCacheLock = new object();
|
|
|
- private ScheduleDirect.Station GetStation(string listingsId, string channelNumber, string channelName)
|
|
|
+ private string GetChannelNumber(ScheduleDirect.Map map)
|
|
|
{
|
|
|
- lock (_channelCacheLock)
|
|
|
- {
|
|
|
- Dictionary<string, ScheduleDirect.Station> channelPair;
|
|
|
- if (_channelPairingCache.TryGetValue(listingsId, out channelPair))
|
|
|
- {
|
|
|
- ScheduleDirect.Station station;
|
|
|
-
|
|
|
- if (!string.IsNullOrWhiteSpace(channelNumber) && channelPair.TryGetValue(channelNumber, out station))
|
|
|
- {
|
|
|
- return station;
|
|
|
- }
|
|
|
-
|
|
|
- if (!string.IsNullOrWhiteSpace(channelName))
|
|
|
- {
|
|
|
- channelName = NormalizeName(channelName);
|
|
|
-
|
|
|
- var result = channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
|
|
|
-
|
|
|
- if (result != null)
|
|
|
- {
|
|
|
- return result;
|
|
|
- }
|
|
|
- }
|
|
|
+ var channelNumber = map.logicalChannelNumber;
|
|
|
|
|
|
- if (!string.IsNullOrWhiteSpace(channelNumber))
|
|
|
- {
|
|
|
- return channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, 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)
|
|
|
+ if (string.IsNullOrWhiteSpace(channelNumber))
|
|
|
{
|
|
|
- Dictionary<string, ScheduleDirect.Station> cache;
|
|
|
- if (_channelPairingCache.TryGetValue(listingsId, out cache))
|
|
|
- {
|
|
|
- cache.Clear();
|
|
|
- }
|
|
|
+ channelNumber = map.channel;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- private int GetChannelPairCacheCount(string listingsId)
|
|
|
- {
|
|
|
- lock (_channelCacheLock)
|
|
|
+ if (string.IsNullOrWhiteSpace(channelNumber))
|
|
|
{
|
|
|
- Dictionary<string, ScheduleDirect.Station> cache;
|
|
|
- if (_channelPairingCache.TryGetValue(listingsId, out cache))
|
|
|
- {
|
|
|
- return cache.Count;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ channelNumber = map.atscMajor + "." + map.atscMinor;
|
|
|
}
|
|
|
- }
|
|
|
+ channelNumber = channelNumber.TrimStart('0');
|
|
|
|
|
|
- private string NormalizeName(string value)
|
|
|
- {
|
|
|
- return value.Replace(" ", string.Empty).Replace("-", string.Empty);
|
|
|
+ return channelNumber;
|
|
|
}
|
|
|
|
|
|
- public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels,
|
|
|
- CancellationToken cancellationToken)
|
|
|
- {
|
|
|
- var listingsId = info.ListingsId;
|
|
|
- if (string.IsNullOrWhiteSpace(listingsId))
|
|
|
- {
|
|
|
- throw new Exception("ListingsId required");
|
|
|
- }
|
|
|
-
|
|
|
- var token = await GetToken(info, cancellationToken);
|
|
|
-
|
|
|
- if (string.IsNullOrWhiteSpace(token))
|
|
|
- {
|
|
|
- throw new Exception("token required");
|
|
|
- }
|
|
|
-
|
|
|
- ClearPairCache(listingsId);
|
|
|
-
|
|
|
- var httpOptions = new HttpRequestOptions()
|
|
|
- {
|
|
|
- Url = ApiUrl + "/lineups/" + listingsId,
|
|
|
- UserAgent = UserAgent,
|
|
|
- CancellationToken = cancellationToken,
|
|
|
- LogErrorResponseBody = true,
|
|
|
- // The data can be large so give it some extra time
|
|
|
- TimeoutMs = 60000
|
|
|
- };
|
|
|
-
|
|
|
- httpOptions.RequestHeaders["token"] = token;
|
|
|
-
|
|
|
- using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
|
|
|
- {
|
|
|
- var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
|
|
|
-
|
|
|
- foreach (ScheduleDirect.Map map in root.map)
|
|
|
- {
|
|
|
- var channelNumber = map.logicalChannelNumber;
|
|
|
-
|
|
|
- if (string.IsNullOrWhiteSpace(channelNumber))
|
|
|
- {
|
|
|
- channelNumber = map.channel;
|
|
|
- }
|
|
|
- if (string.IsNullOrWhiteSpace(channelNumber))
|
|
|
- {
|
|
|
- channelNumber = map.atscMajor + "." + map.atscMinor;
|
|
|
- }
|
|
|
- channelNumber = channelNumber.TrimStart('0');
|
|
|
-
|
|
|
- _logger.Debug("Found channel: " + channelNumber + " in Schedules Direct");
|
|
|
-
|
|
|
- var schChannel = (root.stations ?? new List<ScheduleDirect.Station>()).FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
|
|
|
- if (schChannel != null)
|
|
|
- {
|
|
|
- AddToChannelPairCache(listingsId, channelNumber, schChannel);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- AddToChannelPairCache(listingsId, channelNumber, new ScheduleDirect.Station
|
|
|
- {
|
|
|
- stationID = map.stationID
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- foreach (ChannelInfo channel in channels)
|
|
|
- {
|
|
|
- var station = GetStation(listingsId, channel.Number, channel.Name);
|
|
|
-
|
|
|
- if (station != null)
|
|
|
- {
|
|
|
- if (station.logo != null)
|
|
|
- {
|
|
|
- channel.ImageUrl = station.logo.URL;
|
|
|
- channel.HasImage = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (!string.IsNullOrWhiteSpace(station.name))
|
|
|
- {
|
|
|
- channel.Name = station.name;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + channel.Name);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo,
|
|
|
- ScheduleDirect.ProgramDetails details)
|
|
|
+ private ProgramInfo GetProgram(string channelId, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details)
|
|
|
{
|
|
|
//_logger.Debug("Show type is: " + (details.showType ?? "No ShowType"));
|
|
|
DateTime startAt = GetDate(programInfo.airDateTime);
|
|
@@ -386,7 +228,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
ProgramAudio audioType = ProgramAudio.Stereo;
|
|
|
|
|
|
bool repeat = programInfo.@new == null;
|
|
|
- string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channel;
|
|
|
+ string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channelId;
|
|
|
|
|
|
if (programInfo.audioProperties != null)
|
|
|
{
|
|
@@ -422,7 +264,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
var info = new ProgramInfo
|
|
|
{
|
|
|
- ChannelId = channel,
|
|
|
+ ChannelId = channelId,
|
|
|
Id = newID,
|
|
|
StartDate = startAt,
|
|
|
EndDate = endAt,
|
|
@@ -969,8 +811,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
throw new Exception("ListingsId required");
|
|
|
}
|
|
|
|
|
|
- await AddMetadata(info, new List<ChannelInfo>(), cancellationToken).ConfigureAwait(false);
|
|
|
-
|
|
|
var token = await GetToken(info, cancellationToken);
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(token))
|
|
@@ -997,39 +837,81 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
|
|
|
_logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
|
|
|
_logger.Info("Mapping Stations to Channel");
|
|
|
+
|
|
|
+ var allStations = root.stations ?? new List<ScheduleDirect.Station>();
|
|
|
+
|
|
|
foreach (ScheduleDirect.Map map in root.map)
|
|
|
{
|
|
|
- var channelNumber = map.logicalChannelNumber;
|
|
|
-
|
|
|
- if (string.IsNullOrWhiteSpace(channelNumber))
|
|
|
+ var channelNumber = GetChannelNumber(map);
|
|
|
+
|
|
|
+ var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
|
|
|
+ if (station == null)
|
|
|
{
|
|
|
- channelNumber = map.channel;
|
|
|
- }
|
|
|
- if (string.IsNullOrWhiteSpace(channelNumber))
|
|
|
- {
|
|
|
- channelNumber = map.atscMajor + "." + map.atscMinor;
|
|
|
+ station = new ScheduleDirect.Station
|
|
|
+ {
|
|
|
+ stationID = map.stationID
|
|
|
+ };
|
|
|
}
|
|
|
- channelNumber = channelNumber.TrimStart('0');
|
|
|
|
|
|
var name = channelNumber;
|
|
|
- var station = GetStation(listingsId, channelNumber, null);
|
|
|
|
|
|
- if (station != null && !string.IsNullOrWhiteSpace(station.name))
|
|
|
- {
|
|
|
- name = station.name;
|
|
|
- }
|
|
|
-
|
|
|
- list.Add(new ChannelInfo
|
|
|
+ var channelInfo = new ChannelInfo
|
|
|
{
|
|
|
Number = channelNumber,
|
|
|
Name = name
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ 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;
|
|
|
+ channelInfo.HasImage = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ list.Add(channelInfo);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
}
|
|
|
|
|
|
+ private ScheduleDirect.Station GetStation(List<ScheduleDirect.Station> allStations, string channelNumber, string channelName)
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrWhiteSpace(channelName))
|
|
|
+ {
|
|
|
+ channelName = NormalizeName(channelName);
|
|
|
+
|
|
|
+ var result = allStations.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
|
|
|
+
|
|
|
+ if (result != null)
|
|
|
+ {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!string.IsNullOrWhiteSpace(channelNumber))
|
|
|
+ {
|
|
|
+ return allStations.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, StringComparison.OrdinalIgnoreCase));
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string NormalizeName(string value)
|
|
|
+ {
|
|
|
+ return value.Replace(" ", string.Empty).Replace("-", string.Empty);
|
|
|
+ }
|
|
|
+
|
|
|
public class ScheduleDirect
|
|
|
{
|
|
|
public class Token
|