|
|
|
@ -8,6 +8,8 @@ using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Net.Mime;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using MediaBrowser.Common;
|
|
|
|
@ -26,7 +28,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
{
|
|
|
|
|
private readonly ILogger<SchedulesDirect> _logger;
|
|
|
|
|
private readonly IJsonSerializer _jsonSerializer;
|
|
|
|
|
private readonly IHttpClient _httpClient;
|
|
|
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
|
|
|
private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
|
|
|
|
|
private readonly IApplicationHost _appHost;
|
|
|
|
|
|
|
|
|
@ -35,12 +37,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
public SchedulesDirect(
|
|
|
|
|
ILogger<SchedulesDirect> logger,
|
|
|
|
|
IJsonSerializer jsonSerializer,
|
|
|
|
|
IHttpClient httpClient,
|
|
|
|
|
IHttpClientFactory httpClientFactory,
|
|
|
|
|
IApplicationHost appHost)
|
|
|
|
|
{
|
|
|
|
|
_logger = logger;
|
|
|
|
|
_jsonSerializer = jsonSerializer;
|
|
|
|
|
_httpClient = httpClient;
|
|
|
|
|
_httpClientFactory = httpClientFactory;
|
|
|
|
|
_appHost = appHost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -102,95 +104,78 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
var requestString = _jsonSerializer.SerializeToString(requestList);
|
|
|
|
|
_logger.LogDebug("Request string for schedules is: {RequestString}", requestString);
|
|
|
|
|
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/schedules",
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true,
|
|
|
|
|
RequestContent = requestString
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
httpOptions.RequestHeaders["token"] = token;
|
|
|
|
|
using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules");
|
|
|
|
|
options.Content = new StringContent(requestString, Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
|
|
|
options.Headers.TryAddWithoutValidation("token", token);
|
|
|
|
|
using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(responseStream).ConfigureAwait(false);
|
|
|
|
|
_logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
|
|
|
|
|
|
|
|
|
|
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
|
|
|
|
|
{
|
|
|
|
|
var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false);
|
|
|
|
|
_logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
|
|
|
|
|
|
|
|
|
|
httpOptions = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/programs",
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true
|
|
|
|
|
};
|
|
|
|
|
using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs");
|
|
|
|
|
programRequestOptions.Headers.TryAddWithoutValidation("token", token);
|
|
|
|
|
|
|
|
|
|
httpOptions.RequestHeaders["token"] = token;
|
|
|
|
|
var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
|
|
|
|
|
programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
|
|
|
|
|
|
|
|
var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
|
|
|
|
|
httpOptions.RequestContent = "[\"" + string.Join("\", \"", programsID) + "\"]";
|
|
|
|
|
using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponseStream).ConfigureAwait(false);
|
|
|
|
|
var programDict = programDetails.ToDictionary(p => p.programID, y => y);
|
|
|
|
|
|
|
|
|
|
using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false))
|
|
|
|
|
{
|
|
|
|
|
var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false);
|
|
|
|
|
var programDict = programDetails.ToDictionary(p => p.programID, y => y);
|
|
|
|
|
var programIdsWithImages =
|
|
|
|
|
programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
var programIdsWithImages =
|
|
|
|
|
programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
|
|
|
|
|
.ToList();
|
|
|
|
|
var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
var 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 " +
|
|
|
|
|
// schedule.programID + " which says it has images? " +
|
|
|
|
|
// programDict[schedule.programID].hasImageArtwork);
|
|
|
|
|
|
|
|
|
|
var programsInfo = new List<ProgramInfo>();
|
|
|
|
|
foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
|
|
|
|
|
if (images != null)
|
|
|
|
|
{
|
|
|
|
|
var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
|
|
|
|
|
if (imageIndex > -1)
|
|
|
|
|
{
|
|
|
|
|
// _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
|
|
|
|
|
// " which corresponds to channel " + channelNumber + " and program id " +
|
|
|
|
|
// schedule.programID + " which says it has images? " +
|
|
|
|
|
// programDict[schedule.programID].hasImageArtwork);
|
|
|
|
|
|
|
|
|
|
if (images != null)
|
|
|
|
|
{
|
|
|
|
|
var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
|
|
|
|
|
if (imageIndex > -1)
|
|
|
|
|
{
|
|
|
|
|
var programEntry = programDict[schedule.programID];
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
const double DesiredAspect = 2.0 / 3;
|
|
|
|
|
var programEntry = programDict[schedule.programID];
|
|
|
|
|
|
|
|
|
|
programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ??
|
|
|
|
|
GetProgramImage(ApiUrl, allImages, true, DesiredAspect);
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
const double WideAspect = 16.0 / 9;
|
|
|
|
|
const double DesiredAspect = 2.0 / 3;
|
|
|
|
|
|
|
|
|
|
programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect);
|
|
|
|
|
programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ??
|
|
|
|
|
GetProgramImage(ApiUrl, allImages, true, DesiredAspect);
|
|
|
|
|
|
|
|
|
|
// Don't supply the same image twice
|
|
|
|
|
if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
programEntry.thumbImage = null;
|
|
|
|
|
}
|
|
|
|
|
const double WideAspect = 16.0 / 9;
|
|
|
|
|
|
|
|
|
|
programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
|
|
|
|
|
programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect);
|
|
|
|
|
|
|
|
|
|
// programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
|
|
|
|
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
|
|
|
|
|
// GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
|
|
|
|
|
// GetProgramImage(ApiUrl, data, "Banner-LOT", false);
|
|
|
|
|
}
|
|
|
|
|
// Don't supply the same image twice
|
|
|
|
|
if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
programEntry.thumbImage = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
|
|
|
|
|
}
|
|
|
|
|
programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
|
|
|
|
|
|
|
|
|
|
return programsInfo;
|
|
|
|
|
// programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
|
|
|
|
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
|
|
|
|
|
// GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
|
|
|
|
|
// GetProgramImage(ApiUrl, data, "Banner-LOT", false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return programsInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int GetSizeOrder(ScheduleDirect.ImageData image)
|
|
|
|
@ -482,22 +467,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
|
|
|
|
imageIdString = imageIdString.TrimEnd(',') + "]";
|
|
|
|
|
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/metadata/programs",
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
RequestContent = imageIdString,
|
|
|
|
|
LogErrorResponseBody = true,
|
|
|
|
|
};
|
|
|
|
|
using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs");
|
|
|
|
|
message.Content = new StringContent(imageIdString, Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false))
|
|
|
|
|
{
|
|
|
|
|
return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
|
|
|
|
|
innerResponse2.Content).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var response = await innerResponse2.Content.ReadAsStreamAsync();
|
|
|
|
|
return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
|
|
|
|
|
response).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
@ -518,41 +496,33 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
return lineups;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var options = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location,
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
options.RequestHeaders["token"] = token;
|
|
|
|
|
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/headends?country=" + country + "&postalcode=" + location);
|
|
|
|
|
options.Headers.TryAddWithoutValidation("token", token);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var httpResponse = await Get(options, false, info).ConfigureAwait(false))
|
|
|
|
|
using (Stream responce = httpResponse.Content)
|
|
|
|
|
{
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(responce).ConfigureAwait(false);
|
|
|
|
|
using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var response = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(response).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
if (root != null)
|
|
|
|
|
if (root != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (ScheduleDirect.Headends headend in root)
|
|
|
|
|
{
|
|
|
|
|
foreach (ScheduleDirect.Headends headend in root)
|
|
|
|
|
foreach (ScheduleDirect.Lineup lineup in headend.lineups)
|
|
|
|
|
{
|
|
|
|
|
foreach (ScheduleDirect.Lineup lineup in headend.lineups)
|
|
|
|
|
lineups.Add(new NameIdPair
|
|
|
|
|
{
|
|
|
|
|
lineups.Add(new NameIdPair
|
|
|
|
|
{
|
|
|
|
|
Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
|
|
|
|
|
Id = lineup.uri.Substring(18)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
|
|
|
|
|
Id = lineup.uri.Substring(18)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation("No lineups available");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation("No lineups available");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
@ -633,46 +603,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
|
|
|
|
|
bool enableRetry,
|
|
|
|
|
ListingsProviderInfo providerInfo)
|
|
|
|
|
{
|
|
|
|
|
// Schedules direct requires that the client support compression and will return a 400 response without it
|
|
|
|
|
options.DecompressionMethod = CompressionMethods.Deflate;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _httpClient.Post(options).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (HttpException ex)
|
|
|
|
|
{
|
|
|
|
|
_tokens.Clear();
|
|
|
|
|
|
|
|
|
|
if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
|
|
|
|
|
{
|
|
|
|
|
enableRetry = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!enableRetry)
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
|
|
|
|
|
return await Post(options, false, providerInfo).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<HttpResponseInfo> Get(HttpRequestOptions options,
|
|
|
|
|
private async Task<HttpResponseMessage> Send(
|
|
|
|
|
HttpRequestMessage options,
|
|
|
|
|
bool enableRetry,
|
|
|
|
|
ListingsProviderInfo providerInfo)
|
|
|
|
|
ListingsProviderInfo providerInfo,
|
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
// Schedules direct requires that the client support compression and will return a 400 response without it
|
|
|
|
|
options.DecompressionMethod = CompressionMethods.Deflate;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
|
|
|
|
|
return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
catch (HttpException ex)
|
|
|
|
|
{
|
|
|
|
@ -689,35 +628,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
|
|
|
|
|
return await Get(options, false, providerInfo).ConfigureAwait(false);
|
|
|
|
|
options.Headers.TryAddWithoutValidation("token", await GetToken(providerInfo, cancellationToken).ConfigureAwait(false));
|
|
|
|
|
return await Send(options, false, providerInfo, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<string> GetTokenInternal(string username, string password,
|
|
|
|
|
private async Task<string> GetTokenInternal(
|
|
|
|
|
string username,
|
|
|
|
|
string password,
|
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/token",
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}",
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true
|
|
|
|
|
};
|
|
|
|
|
// _logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
|
|
|
|
|
// httpOptions.RequestContent);
|
|
|
|
|
using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token");
|
|
|
|
|
options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
|
|
|
|
|
|
|
|
using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
|
|
|
|
|
using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(stream).ConfigureAwait(false);
|
|
|
|
|
if (root.message == "OK")
|
|
|
|
|
{
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(response.Content).ConfigureAwait(false);
|
|
|
|
|
if (root.message == "OK")
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
|
|
|
|
|
return root.token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
|
|
|
|
|
_logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
|
|
|
|
|
return root.token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
|
|
|
|
@ -736,20 +668,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("Adding new LineUp ");
|
|
|
|
|
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/lineups/" + info.ListingsId,
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true,
|
|
|
|
|
BufferContent = false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
httpOptions.RequestHeaders["token"] = token;
|
|
|
|
|
|
|
|
|
|
using (await _httpClient.SendAsync(httpOptions, HttpMethod.Put).ConfigureAwait(false))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
using var options = new HttpRequestMessage(HttpMethod.Put, ApiUrl + "/lineups/" + info.ListingsId);
|
|
|
|
|
options.Headers.TryAddWithoutValidation("token", token);
|
|
|
|
|
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)
|
|
|
|
@ -768,25 +689,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("Headends on account ");
|
|
|
|
|
|
|
|
|
|
var options = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/lineups",
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
options.RequestHeaders["token"] = token;
|
|
|
|
|
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups");
|
|
|
|
|
options.Headers.TryAddWithoutValidation("token", token);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var httpResponse = await Get(options, false, null).ConfigureAwait(false))
|
|
|
|
|
using (var response = httpResponse.Content)
|
|
|
|
|
{
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false);
|
|
|
|
|
using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
using var response = httpResponse.Content;
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(stream).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)
|
|
|
|
|
{
|
|
|
|
@ -851,55 +764,37 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|
|
|
|
throw new Exception("token required");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var httpOptions = new HttpRequestOptions()
|
|
|
|
|
{
|
|
|
|
|
Url = ApiUrl + "/lineups/" + listingsId,
|
|
|
|
|
UserAgent = UserAgent,
|
|
|
|
|
CancellationToken = cancellationToken,
|
|
|
|
|
LogErrorResponseBody = true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
httpOptions.RequestHeaders["token"] = token;
|
|
|
|
|
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);
|
|
|
|
|
options.Headers.TryAddWithoutValidation("token", token);
|
|
|
|
|
|
|
|
|
|
var list = new List<ChannelInfo>();
|
|
|
|
|
|
|
|
|
|
using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false))
|
|
|
|
|
using (var response = httpResponse.Content)
|
|
|
|
|
{
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
|
|
var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
|
|
|
|
|
using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(stream).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
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
foreach (ScheduleDirect.Map map in root.map)
|
|
|
|
|
{
|
|
|
|
|
var channelNumber = GetChannelNumber(map);
|
|
|
|
|
|
|
|
|
|
var channelInfo = new ChannelInfo
|
|
|
|
|
{
|
|
|
|
|
Id = station.stationID,
|
|
|
|
|
CallSign = station.callsign,
|
|
|
|
|
Number = channelNumber,
|
|
|
|
|
Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name
|
|
|
|
|
};
|
|
|
|
|
var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
if (station == null)
|
|
|
|
|
{
|
|
|
|
|
station = new ScheduleDirect.Station {stationID = map.stationID};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|