Clean up HttpClientManager, LiveTvManager and InstallationManager

This commit is contained in:
Bond_009 2018-12-26 01:16:02 +01:00
parent 0cafd7dfef
commit a1b96a3135
6 changed files with 227 additions and 383 deletions

View file

@ -640,15 +640,14 @@ namespace Emby.Server.Implementations
/// Gets the exports. /// Gets the exports.
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param> /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
/// <returns>IEnumerable{``0}.</returns> /// <returns>IEnumerable{``0}.</returns>
public IEnumerable<T> GetExports<T>(bool manageLifetime = true) public IEnumerable<T> GetExports<T>(bool manageLifetime = true)
{ {
var parts = GetExportTypes<T>() var parts = GetExportTypes<T>()
.Select(CreateInstanceSafe) .Select(CreateInstanceSafe)
.Where(i => i != null) .Where(i => i != null)
.Cast<T>() .Cast<T>();
.ToList();
if (manageLifetime) if (manageLifetime)
{ {
@ -703,7 +702,7 @@ namespace Emby.Server.Implementations
/// <summary> /// <summary>
/// Runs the startup tasks. /// Runs the startup tasks.
/// </summary> /// </summary>
public async Task RunStartupTasks() public Task RunStartupTasks()
{ {
Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false)); Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
@ -736,6 +735,8 @@ namespace Emby.Server.Implementations
Logger.LogInformation("All entry points have started"); Logger.LogInformation("All entry points have started");
//LoggerFactory.RemoveConsoleOutput(); //LoggerFactory.RemoveConsoleOutput();
return Task.CompletedTask;
} }
private void RunEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup) private void RunEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)

View file

@ -5,18 +5,15 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations.IO;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Controller.IO;
namespace Emby.Server.Implementations.HttpClientManager namespace Emby.Server.Implementations.HttpClientManager
{ {
@ -136,9 +133,8 @@ namespace Emby.Server.Implementations.HttpClientManager
} }
var request = CreateWebRequest(url); var request = CreateWebRequest(url);
var httpWebRequest = request as HttpWebRequest;
if (httpWebRequest != null) if (request is HttpWebRequest httpWebRequest)
{ {
AddRequestHeaders(httpWebRequest, options); AddRequestHeaders(httpWebRequest, options);
@ -159,25 +155,12 @@ namespace Emby.Server.Implementations.HttpClientManager
{ {
httpWebRequest.AutomaticDecompression = DecompressionMethods.None; httpWebRequest.AutomaticDecompression = DecompressionMethods.None;
} }
}
request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
if (httpWebRequest != null)
{
if (options.EnableKeepAlive) if (options.EnableKeepAlive)
{ {
httpWebRequest.KeepAlive = true; httpWebRequest.KeepAlive = true;
} }
}
request.Method = method;
request.Timeout = options.TimeoutMs;
if (httpWebRequest != null)
{
if (!string.IsNullOrEmpty(options.Host)) if (!string.IsNullOrEmpty(options.Host))
{ {
httpWebRequest.Host = options.Host; httpWebRequest.Host = options.Host;
@ -189,6 +172,11 @@ namespace Emby.Server.Implementations.HttpClientManager
} }
} }
request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
request.Method = method;
request.Timeout = options.TimeoutMs;
if (!string.IsNullOrWhiteSpace(userInfo)) if (!string.IsNullOrWhiteSpace(userInfo))
{ {
var parts = userInfo.Split(':'); var parts = userInfo.Split(':');
@ -215,7 +203,7 @@ namespace Emby.Server.Implementations.HttpClientManager
{ {
var hasUserAgent = false; var hasUserAgent = false;
foreach (var header in options.RequestHeaders.ToList()) foreach (var header in options.RequestHeaders)
{ {
if (string.Equals(header.Key, "Accept", StringComparison.OrdinalIgnoreCase)) if (string.Equals(header.Key, "Accept", StringComparison.OrdinalIgnoreCase))
{ {
@ -340,8 +328,8 @@ namespace Emby.Server.Implementations.HttpClientManager
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(responseCachePath)); _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(responseCachePath));
using (var responseStream = response.Content) using (var responseStream = response.Content)
using (var memoryStream = new MemoryStream())
{ {
var memoryStream = new MemoryStream();
await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false); await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0; memoryStream.Position = 0;
@ -379,10 +367,7 @@ namespace Emby.Server.Implementations.HttpClientManager
{ {
try try
{ {
// TODO: We can always put this in the options object if needed var bytes = options.RequestContentBytes ?? Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
var requestEncoding = Encoding.UTF8;
var bytes = options.RequestContentBytes ?? requestEncoding.GetBytes(options.RequestContent ?? string.Empty);
var contentType = options.RequestContentType ?? "application/x-www-form-urlencoded"; var contentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
@ -392,7 +377,6 @@ namespace Emby.Server.Implementations.HttpClientManager
} }
httpWebRequest.ContentType = contentType; httpWebRequest.ContentType = contentType;
httpWebRequest.ContentLength = bytes.Length; httpWebRequest.ContentLength = bytes.Length;
(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length); (await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length);
} }
@ -409,10 +393,7 @@ namespace Emby.Server.Implementations.HttpClientManager
if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds) if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
{ {
if (options.ResourcePool != null) options.ResourcePool?.Release();
{
options.ResourcePool.Release();
}
throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true };
} }
@ -455,9 +436,8 @@ namespace Emby.Server.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested(); options.CancellationToken.ThrowIfCancellationRequested();
using (var stream = httpResponse.GetResponseStream()) using (var stream = httpResponse.GetResponseStream())
using (var memoryStream = new MemoryStream())
{ {
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream).ConfigureAwait(false); await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0; memoryStream.Position = 0;
@ -476,10 +456,7 @@ namespace Emby.Server.Implementations.HttpClientManager
} }
finally finally
{ {
if (options.ResourcePool != null) options.ResourcePool?.Release();
{
options.ResourcePool.Release();
}
} }
} }
@ -488,13 +465,9 @@ namespace Emby.Server.Implementations.HttpClientManager
var responseInfo = new HttpResponseInfo(disposable) var responseInfo = new HttpResponseInfo(disposable)
{ {
Content = content, Content = content,
StatusCode = httpResponse.StatusCode, StatusCode = httpResponse.StatusCode,
ContentType = httpResponse.ContentType, ContentType = httpResponse.ContentType,
ContentLength = contentLength, ContentLength = contentLength,
ResponseUrl = httpResponse.ResponseUri.ToString() ResponseUrl = httpResponse.ResponseUri.ToString()
}; };
@ -511,11 +484,8 @@ namespace Emby.Server.Implementations.HttpClientManager
var responseInfo = new HttpResponseInfo var responseInfo = new HttpResponseInfo
{ {
TempFilePath = tempFile, TempFilePath = tempFile,
StatusCode = httpResponse.StatusCode, StatusCode = httpResponse.StatusCode,
ContentType = httpResponse.ContentType, ContentType = httpResponse.ContentType,
ContentLength = contentLength ContentLength = contentLength
}; };
@ -619,24 +589,22 @@ namespace Emby.Server.Implementations.HttpClientManager
var contentLength = GetContentLength(httpResponse); var contentLength = GetContentLength(httpResponse);
if (!contentLength.HasValue) if (contentLength.HasValue)
{
// We're not able to track progress
using (var stream = httpResponse.GetResponseStream())
{
using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
{
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
}
}
}
else
{ {
using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
{ {
await httpResponse.GetResponseStream().CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); await httpResponse.GetResponseStream().CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
} }
} }
else
{
// We're not able to track progress
using (var stream = httpResponse.GetResponseStream())
using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
{
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
}
}
options.Progress.Report(100); options.Progress.Report(100);
@ -650,10 +618,7 @@ namespace Emby.Server.Implementations.HttpClientManager
} }
finally finally
{ {
if (options.ResourcePool != null) options.ResourcePool?.Release();
{
options.ResourcePool.Release();
}
} }
} }
@ -810,8 +775,11 @@ namespace Emby.Server.Implementations.HttpClientManager
var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299; var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299;
if (!isSuccessful) if (isSuccessful)
{ {
return;
}
if (options.LogErrorResponseBody) if (options.LogErrorResponseBody)
{ {
try try
@ -834,12 +802,12 @@ namespace Emby.Server.Implementations.HttpClientManager
} }
} }
throw new HttpException(response.StatusDescription) throw new HttpException(response.StatusDescription)
{ {
StatusCode = response.StatusCode StatusCode = response.StatusCode
}; };
} }
}
private Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout) private Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout)
{ {
@ -859,15 +827,12 @@ namespace Emby.Server.Implementations.HttpClientManager
private static void TimeoutCallback(object state, bool timedOut) private static void TimeoutCallback(object state, bool timedOut)
{ {
if (timedOut) if (timedOut && state != null)
{ {
WebRequest request = (WebRequest)state; WebRequest request = (WebRequest)state;
if (state != null)
{
request.Abort(); request.Abort();
} }
} }
}
private class TaskCallback private class TaskCallback
{ {
@ -880,13 +845,13 @@ namespace Emby.Server.Implementations.HttpClientManager
public void OnError(Task<WebResponse> task) public void OnError(Task<WebResponse> task)
{ {
if (task.Exception != null) if (task.Exception == null)
{ {
taskCompletion.TrySetException(task.Exception); taskCompletion.TrySetException(Enumerable.Empty<Exception>());
} }
else else
{ {
taskCompletion.TrySetException(new List<Exception>()); taskCompletion.TrySetException(task.Exception);
} }
} }
} }

View file

@ -16,8 +16,6 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.LiveTv.Listings namespace Emby.Server.Implementations.LiveTv.Listings
@ -32,9 +30,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private const string ApiUrl = "https://json.schedulesdirect.org/20141201"; private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
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)
{ {
_logger = logger; _logger = logger;
@ -74,33 +69,29 @@ namespace Emby.Server.Implementations.LiveTv.Listings
// Normalize incoming input // Normalize incoming input
channelId = channelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I'); 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); var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(token)) if (string.IsNullOrEmpty(token))
{ {
_logger.LogWarning("SchedulesDirect token is empty, returning empty program list"); _logger.LogWarning("SchedulesDirect token is empty, returning empty program list");
return programsInfo;
return Enumerable.Empty<ProgramInfo>();
} }
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc); var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
string stationID = channelId; _logger.LogInformation("Channel Station ID is: {ChannelID}", channelId);
var requestList = new List<ScheduleDirect.RequestScheduleForChannel>()
_logger.LogInformation("Channel Station ID is: " + stationID);
List<ScheduleDirect.RequestScheduleForChannel> requestList =
new List<ScheduleDirect.RequestScheduleForChannel>()
{ {
new ScheduleDirect.RequestScheduleForChannel() new ScheduleDirect.RequestScheduleForChannel()
{ {
stationID = stationID, stationID = channelId,
date = dates date = dates
} }
}; };
var requestString = _jsonSerializer.SerializeToString(requestList); var requestString = _jsonSerializer.SerializeToString(requestList);
_logger.LogDebug("Request string for schedules is: " + requestString); _logger.LogDebug("Request string for schedules is: {RequestString}", requestString);
var httpOptions = new HttpRequestOptions() var httpOptions = new HttpRequestOptions()
{ {
@ -109,16 +100,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
// The data can be large so give it some extra time // The data can be large so give it some extra time
TimeoutMs = 60000, TimeoutMs = 60000,
LogErrorResponseBody = true LogErrorResponseBody = true,
RequestContent = requestString
}; };
httpOptions.RequestHeaders["token"] = token; httpOptions.RequestHeaders["token"] = token;
httpOptions.RequestContent = requestString;
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false)) using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
using (StreamReader reader = new StreamReader(response.Content))
{ {
var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false); var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false);
_logger.LogDebug("Found {ScheduleCount} programs on {StationID} ScheduleDirect", dailySchedules.Count, stationID); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
httpOptions = new HttpRequestOptions() httpOptions = new HttpRequestOptions()
{ {
@ -132,14 +124,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
httpOptions.RequestHeaders["token"] = token; httpOptions.RequestHeaders["token"] = token;
List<string> programsID = new List<string>(); var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct().ToList(); httpOptions.RequestContent = "[\"" + string.Join("\", \"", programsID) + "\"]";
var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]";
httpOptions.RequestContent = requestBody;
double wideAspect = 1.77777778;
using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false)) using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false))
using (StreamReader innerReader = new StreamReader(innerResponse.Content))
{ {
var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false); var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false);
var programDict = programDetails.ToDictionary(p => p.programID, y => y); var programDict = programDetails.ToDictionary(p => p.programID, y => y);
@ -150,8 +139,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false); var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
var schedules = dailySchedules.SelectMany(d => d.programs); List<ProgramInfo> programsInfo = new List<ProgramInfo>();
foreach (ScheduleDirect.Program schedule in schedules) foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
{ {
//_logger.LogDebug("Proccesing Schedule for statio ID " + stationID + //_logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
// " which corresponds to channel " + channelNumber + " and program id " + // " which corresponds to channel " + channelNumber + " and program id " +
@ -165,15 +154,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
var programEntry = programDict[schedule.programID]; var programEntry = programDict[schedule.programID];
var allImages = (images[imageIndex].data ?? new List<ScheduleDirect.ImageData>()).ToList(); var allImages = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)).ToList(); var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase));
var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase)).ToList(); var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase));
double desiredAspect = 0.666666667; const double desiredAspect = 0.666666667;
programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, desiredAspect) ?? programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, desiredAspect) ??
GetProgramImage(ApiUrl, allImages, true, desiredAspect); GetProgramImage(ApiUrl, allImages, true, desiredAspect);
const double wideAspect = 1.77777778;
programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, wideAspect); programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, wideAspect);
// Don't supply the same image twice // Don't supply the same image twice
@ -193,18 +184,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID])); programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
} }
}
}
return programsInfo; return programsInfo;
} }
}
}
private int GetSizeOrder(ScheduleDirect.ImageData image) private int GetSizeOrder(ScheduleDirect.ImageData image)
{ {
if (!string.IsNullOrWhiteSpace(image.height)) if (!string.IsNullOrWhiteSpace(image.height))
{ {
int value; if (int.TryParse(image.height, out int value))
if (int.TryParse(image.height, out value))
{ {
return value; return value;
} }
@ -225,9 +214,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
channelNumber = map.atscMajor + "." + map.atscMinor; channelNumber = map.atscMajor + "." + map.atscMinor;
} }
channelNumber = channelNumber.TrimStart('0');
return channelNumber; return channelNumber.TrimStart('0');
} }
private bool IsMovie(ScheduleDirect.ProgramDetails programInfo) private bool IsMovie(ScheduleDirect.ProgramDetails programInfo)
@ -382,8 +370,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (details.movie != null) if (details.movie != null)
{ {
int year; if (!string.IsNullOrEmpty(details.movie.year) && int.TryParse(details.movie.year, out int year))
if (!string.IsNullOrEmpty(details.movie.year) && int.TryParse(details.movie.year, out year))
{ {
info.ProductionYear = year; info.ProductionYear = year;
} }
@ -414,18 +401,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return date; return date;
} }
private string GetProgramImage(string apiUrl, List<ScheduleDirect.ImageData> images, bool returnDefaultImage, double desiredAspect) private string GetProgramImage(string apiUrl, IEnumerable<ScheduleDirect.ImageData> images, bool returnDefaultImage, double desiredAspect)
{ {
string url = null; var match = images
.OrderBy(i => Math.Abs(desiredAspect - GetAspectRatio(i)))
var matches = images;
matches = matches
.OrderBy(i => Math.Abs(desiredAspect - GetApsectRatio(i)))
.ThenByDescending(GetSizeOrder) .ThenByDescending(GetSizeOrder)
.ToList(); .FirstOrDefault();
var match = matches.FirstOrDefault();
if (match == null) if (match == null)
{ {
@ -434,22 +415,21 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var uri = match.uri; var uri = match.uri;
if (!string.IsNullOrWhiteSpace(uri)) if (string.IsNullOrWhiteSpace(uri))
{ {
if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1) return null;
}
else if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
{ {
url = uri; return uri;
} }
else else
{ {
url = apiUrl + "/image/" + uri; return apiUrl + "/image/" + uri;
} }
} }
//_logger.LogDebug("URL for image is : " + url);
return url;
}
private double GetApsectRatio(ScheduleDirect.ImageData i) private double GetAspectRatio(ScheduleDirect.ImageData i)
{ {
int width = 0; int width = 0;
int height = 0; int height = 0;
@ -614,8 +594,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (!string.IsNullOrEmpty(savedToken.Name) && !string.IsNullOrEmpty(savedToken.Value)) if (!string.IsNullOrEmpty(savedToken.Name) && !string.IsNullOrEmpty(savedToken.Value))
{ {
long ticks; if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out long ticks))
if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
{ {
// If it's under 24 hours old we can still use it // If it's under 24 hours old we can still use it
if (DateTime.UtcNow.Ticks - ticks < TimeSpan.FromHours(20).Ticks) if (DateTime.UtcNow.Ticks - ticks < TimeSpan.FromHours(20).Ticks)
@ -685,8 +664,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
} }
} }
var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false); options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);;
options.RequestHeaders["token"] = newToken;
return await Post(options, false, providerInfo).ConfigureAwait(false); return await Post(options, false, providerInfo).ConfigureAwait(false);
} }
@ -724,8 +702,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
} }
} }
var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false); options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
options.RequestHeaders["token"] = newToken;
return await Get(options, false, providerInfo).ConfigureAwait(false); return await Get(options, false, providerInfo).ConfigureAwait(false);
} }
@ -743,9 +720,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
//_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " + //_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent); // httpOptions.RequestContent);
using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false)) using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
{ {
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(responce.Content).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(response.Content).ConfigureAwait(false);
if (root.message == "OK") if (root.message == "OK")
{ {
_logger.LogInformation("Authenticated with Schedules Direct token: " + root.token); _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
@ -828,7 +805,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
try try
{ {
using (var httpResponse = await Get(options, false, null).ConfigureAwait(false)) using (var httpResponse = await Get(options, false, null).ConfigureAwait(false))
{
using (var response = httpResponse.Content) using (var response = httpResponse.Content)
{ {
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false);
@ -836,7 +812,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
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) catch (HttpException ex)
{ {
// Apparently we're supposed to swallow this // Apparently we're supposed to swallow this
@ -913,14 +888,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var list = new List<ChannelInfo>(); var list = new List<ChannelInfo>();
using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false)) using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false))
{
using (var response = httpResponse.Content) using (var response = httpResponse.Content)
{ {
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(response).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(response).ConfigureAwait(false);
_logger.LogInformation("Found " + root.map.Count + " channels on the lineup on ScheduleDirect"); _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
_logger.LogInformation("Mapping Stations to Channel"); _logger.LogInformation("Mapping Stations to Channel");
var allStations = root.stations ?? new List<ScheduleDirect.Station>(); var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
foreach (ScheduleDirect.Map map in root.map) foreach (ScheduleDirect.Map map in root.map)
{ {
@ -935,34 +909,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}; };
} }
var name = channelNumber;
var channelInfo = new ChannelInfo var channelInfo = new ChannelInfo
{ {
Id = station.stationID,
CallSign = station.callsign,
Number = channelNumber, Number = channelNumber,
Name = name Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.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) if (station.logo != null)
{ {
channelInfo.ImageUrl = station.logo.URL; channelInfo.ImageUrl = station.logo.URL;
} }
}
list.Add(channelInfo); list.Add(channelInfo);
} }
} }
}
return list; return list;
} }

View file

@ -132,9 +132,7 @@ namespace Emby.Server.Implementations.LiveTv
{ {
service.DataSourceChanged += service_DataSourceChanged; service.DataSourceChanged += service_DataSourceChanged;
var embyTv = service as EmbyTV.EmbyTV; if (service is EmbyTV.EmbyTV embyTv)
if (embyTv != null)
{ {
embyTv.TimerCreated += EmbyTv_TimerCreated; embyTv.TimerCreated += EmbyTv_TimerCreated;
embyTv.TimerCancelled += EmbyTv_TimerCancelled; embyTv.TimerCancelled += EmbyTv_TimerCancelled;
@ -251,18 +249,15 @@ namespace Emby.Server.Implementations.LiveTv
mediaSourceId = null; mediaSourceId = null;
} }
MediaSourceInfo info;
bool isVideo;
ILiveTvService service;
ILiveStream liveStream;
var channel = (LiveTvChannel)_libraryManager.GetItemById(id); var channel = (LiveTvChannel)_libraryManager.GetItemById(id);
isVideo = channel.ChannelType == ChannelType.TV;
service = GetService(channel); bool isVideo = channel.ChannelType == ChannelType.TV;
ILiveTvService service = GetService(channel);
_logger.LogInformation("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId); _logger.LogInformation("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId);
var supportsManagedStream = service as ISupportsDirectStreamProvider; MediaSourceInfo info;
if (supportsManagedStream != null) ILiveStream liveStream;
if (service is ISupportsDirectStreamProvider supportsManagedStream)
{ {
liveStream = await supportsManagedStream.GetChannelStreamWithDirectStreamProvider(channel.ExternalId, mediaSourceId, currentLiveStreams, cancellationToken).ConfigureAwait(false); liveStream = await supportsManagedStream.GetChannelStreamWithDirectStreamProvider(channel.ExternalId, mediaSourceId, currentLiveStreams, cancellationToken).ConfigureAwait(false);
info = liveStream.MediaSource; info = liveStream.MediaSource;
@ -303,14 +298,12 @@ namespace Emby.Server.Implementations.LiveTv
throw new NotImplementedException(); throw new NotImplementedException();
} }
var list = sources.ToList(); foreach (var source in sources)
foreach (var source in list)
{ {
Normalize(source, service, baseItem.ChannelType == ChannelType.TV); Normalize(source, service, baseItem.ChannelType == ChannelType.TV);
} }
return list; return sources;
} }
private ILiveTvService GetService(LiveTvChannel item) private ILiveTvService GetService(LiveTvChannel item)
@ -542,13 +535,11 @@ namespace Emby.Server.Implementations.LiveTv
{ {
var id = _tvDtoService.GetInternalProgramId(info.Id); var id = _tvDtoService.GetInternalProgramId(info.Id);
LiveTvProgram item = null;
allExistingPrograms.TryGetValue(id, out item);
var isNew = false; var isNew = false;
var forceUpdate = false; var forceUpdate = false;
if (item == null) LiveTvProgram item;
if (!allExistingPrograms.TryGetValue(id, out item))
{ {
isNew = true; isNew = true;
item = new LiveTvProgram item = new LiveTvProgram
@ -783,11 +774,9 @@ namespace Emby.Server.Implementations.LiveTv
var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user); var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user);
var list = new List<Tuple<BaseItemDto, string, string>>(); var list = new List<Tuple<BaseItemDto, string, string>>() {
new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, program.ExternalSeriesId)
var externalSeriesId = program.ExternalSeriesId; };
list.Add(new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, externalSeriesId));
await AddRecordingInfo(list, cancellationToken).ConfigureAwait(false); await AddRecordingInfo(list, cancellationToken).ConfigureAwait(false);
@ -928,13 +917,11 @@ namespace Emby.Server.Implementations.LiveTv
programs = programs.Take(query.Limit.Value); programs = programs.Take(query.Limit.Value);
} }
var result = new QueryResult<BaseItem> return new QueryResult<BaseItem>
{ {
Items = programs.ToArray(), Items = programs.ToArray(),
TotalRecordCount = totalCount TotalRecordCount = totalCount
}; };
return result;
} }
public QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken) public QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken)
@ -948,17 +935,11 @@ namespace Emby.Server.Implementations.LiveTv
var internalResult = GetRecommendedProgramsInternal(query, options, cancellationToken); var internalResult = GetRecommendedProgramsInternal(query, options, cancellationToken);
var user = query.User; return new QueryResult<BaseItemDto>
var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user);
var result = new QueryResult<BaseItemDto>
{ {
Items = returnArray, Items = _dtoService.GetBaseItemDtos(internalResult.Items, options, query.User),
TotalRecordCount = internalResult.TotalRecordCount TotalRecordCount = internalResult.TotalRecordCount
}; };
return result;
} }
private int GetRecommendationScore(LiveTvProgram program, User user, bool factorChannelWatchCount) private int GetRecommendationScore(LiveTvProgram program, User user, bool factorChannelWatchCount)
@ -977,17 +958,16 @@ namespace Emby.Server.Implementations.LiveTv
var channel = _libraryManager.GetItemById(program.ChannelId); var channel = _libraryManager.GetItemById(program.ChannelId);
if (channel != null) if (channel == null)
{ {
return score;
}
var channelUserdata = _userDataManager.GetUserData(user, channel); var channelUserdata = _userDataManager.GetUserData(user, channel);
if (channelUserdata.Likes ?? false) if (channelUserdata.Likes.HasValue)
{ {
score += 2; score += channelUserdata.Likes.Value ? 2 : -2;
}
else if (!(channelUserdata.Likes ?? true))
{
score -= 2;
} }
if (channelUserdata.IsFavorite) if (channelUserdata.IsFavorite)
@ -999,7 +979,6 @@ namespace Emby.Server.Implementations.LiveTv
{ {
score += channelUserdata.PlayCount; score += channelUserdata.PlayCount;
} }
}
return score; return score;
} }
@ -1153,7 +1132,6 @@ namespace Emby.Server.Implementations.LiveTv
var numComplete = 0; var numComplete = 0;
var parentFolder = GetInternalLiveTvFolder(cancellationToken); var parentFolder = GetInternalLiveTvFolder(cancellationToken);
var parentFolderId = parentFolder.Id;
foreach (var channelInfo in allChannelsList) foreach (var channelInfo in allChannelsList)
{ {
@ -1239,30 +1217,11 @@ namespace Emby.Server.Implementations.LiveTv
programs.Add(programItem.Id); programs.Add(programItem.Id);
if (program.IsMovie) isMovie |= program.IsMovie;
{ iSSeries |= program.IsSeries;
isMovie = true; isSports |= program.IsSports;
} isNews |= program.IsNews;
isKids |= program.IsKids;
if (program.IsSeries)
{
iSSeries = true;
}
if (program.IsSports)
{
isSports = true;
}
if (program.IsNews)
{
isNews = true;
}
if (program.IsKids)
{
isKids = true;
}
} }
_logger.LogDebug("Channel {0} has {1} new programs and {2} updated programs", currentChannel.Name, newPrograms.Count, updatedPrograms.Count); _logger.LogDebug("Channel {0} has {1} new programs and {2} updated programs", currentChannel.Name, newPrograms.Count, updatedPrograms.Count);
@ -1304,8 +1263,7 @@ namespace Emby.Server.Implementations.LiveTv
} }
numComplete++; numComplete++;
double percent = numComplete; double percent = numComplete / allChannelsList.Count;
percent /= allChannelsList.Count;
progress.Report(85 * percent + 15); progress.Report(85 * percent + 15);
} }
@ -1320,7 +1278,6 @@ namespace Emby.Server.Implementations.LiveTv
{ {
IncludeItemTypes = validTypes, IncludeItemTypes = validTypes,
DtoOptions = new DtoOptions(false) DtoOptions = new DtoOptions(false)
}); });
var numComplete = 0; var numComplete = 0;
@ -1351,8 +1308,7 @@ namespace Emby.Server.Implementations.LiveTv
} }
numComplete++; numComplete++;
double percent = numComplete; double percent = numComplete / list.Count;
percent /= list.Count;
progress.Report(100 * percent); progress.Report(100 * percent);
} }
@ -1414,28 +1370,22 @@ namespace Emby.Server.Implementations.LiveTv
excludeItemTypes.Add(typeof(Episode).Name); excludeItemTypes.Add(typeof(Episode).Name);
} }
} }
if (query.IsSports.HasValue) if (query.IsSports ?? false)
{
if (query.IsSports.Value)
{ {
genres.Add("Sports"); genres.Add("Sports");
} }
} if (query.IsKids ?? false)
if (query.IsKids.HasValue)
{
if (query.IsKids.Value)
{ {
genres.Add("Kids"); genres.Add("Kids");
genres.Add("Children"); genres.Add("Children");
genres.Add("Family"); genres.Add("Family");
} }
}
var limit = query.Limit; var limit = query.Limit;
if ((query.IsInProgress ?? false)) if (query.IsInProgress ?? false)
{ {
limit = (query.Limit ?? 10) * 2; // limit = (query.Limit ?? 10) * 2;
limit = null; limit = null;
//var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray(); //var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
@ -1467,7 +1417,7 @@ namespace Emby.Server.Implementations.LiveTv
DtoOptions = dtoOptions DtoOptions = dtoOptions
}); });
if ((query.IsInProgress ?? false)) if (query.IsInProgress ?? false)
{ {
result.Items = result result.Items = result
.Items .Items
@ -1494,60 +1444,33 @@ namespace Emby.Server.Implementations.LiveTv
dto.StartDate = program.StartDate; dto.StartDate = program.StartDate;
dto.EpisodeTitle = program.EpisodeTitle; dto.EpisodeTitle = program.EpisodeTitle;
dto.IsRepeat |= program.IsRepeat;
if (program.IsRepeat) dto.IsMovie |= program.IsMovie;
{ dto.IsSeries |= program.IsSeries;
dto.IsRepeat = program.IsRepeat; dto.IsSports |= program.IsSports;
} dto.IsLive |= program.IsLive;
if (program.IsMovie) dto.IsNews |= program.IsNews;
{ dto.IsKids |= program.IsKids;
dto.IsMovie = program.IsMovie; dto.IsPremiere |= program.IsPremiere;
}
if (program.IsSeries)
{
dto.IsSeries = program.IsSeries;
}
if (program.IsSports)
{
dto.IsSports = program.IsSports;
}
if (program.IsLive)
{
dto.IsLive = program.IsLive;
}
if (program.IsNews)
{
dto.IsNews = program.IsNews;
}
if (program.IsKids)
{
dto.IsKids = program.IsKids;
}
if (program.IsPremiere)
{
dto.IsPremiere = program.IsPremiere;
}
if (hasChannelInfo || hasChannelImage) if (hasChannelInfo || hasChannelImage)
{ {
var channel = _libraryManager.GetItemById(program.ChannelId) as LiveTvChannel; var channel = _libraryManager.GetItemById(program.ChannelId);
if (channel != null) if (channel is LiveTvChannel liveChannel)
{ {
dto.ChannelName = channel.Name; dto.ChannelName = liveChannel.Name;
dto.MediaType = channel.MediaType; dto.MediaType = liveChannel.MediaType;
dto.ChannelNumber = channel.Number; dto.ChannelNumber = liveChannel.Number;
if (hasChannelImage && channel.HasImage(ImageType.Primary)) if (hasChannelImage && liveChannel.HasImage(ImageType.Primary))
{ {
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel); dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(liveChannel);
} }
} }
} }
var externalSeriesId = program.ExternalSeriesId; programTuples.Add(new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, program.ExternalSeriesId));
programTuples.Add(new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, externalSeriesId));
} }
return AddRecordingInfo(programTuples, CancellationToken.None); return AddRecordingInfo(programTuples, CancellationToken.None);
@ -2037,19 +1960,13 @@ namespace Emby.Server.Implementations.LiveTv
private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null) private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
{ {
var service = program != null ? ILiveTvService service = null;
GetService(program) :
null;
if (service == null)
{
service = _services.First();
}
ProgramInfo programInfo = null; ProgramInfo programInfo = null;
if (program != null) if(program != null)
{ {
service = GetService(program);
var channel = _libraryManager.GetItemById(program.ChannelId); var channel = _libraryManager.GetItemById(program.ChannelId);
programInfo = new ProgramInfo programInfo = new ProgramInfo
@ -2079,6 +1996,11 @@ namespace Emby.Server.Implementations.LiveTv
}; };
} }
if (service == null)
{
service = _services.First();
}
var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false); var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
info.RecordAnyTime = true; info.RecordAnyTime = true;
@ -2147,8 +2069,7 @@ namespace Emby.Server.Implementations.LiveTv
info.Priority = defaultValues.Priority; info.Priority = defaultValues.Priority;
string newTimerId = null; string newTimerId = null;
var supportsNewTimerIds = service as ISupportsNewTimerIds; if (service is ISupportsNewTimerIds supportsNewTimerIds)
if (supportsNewTimerIds != null)
{ {
newTimerId = await supportsNewTimerIds.CreateTimer(info, cancellationToken).ConfigureAwait(false); newTimerId = await supportsNewTimerIds.CreateTimer(info, cancellationToken).ConfigureAwait(false);
newTimerId = _tvDtoService.GetInternalTimerId(newTimerId); newTimerId = _tvDtoService.GetInternalTimerId(newTimerId);
@ -2192,8 +2113,7 @@ namespace Emby.Server.Implementations.LiveTv
info.Priority = defaultValues.Priority; info.Priority = defaultValues.Priority;
string newTimerId = null; string newTimerId = null;
var supportsNewTimerIds = service as ISupportsNewTimerIds; if (service is ISupportsNewTimerIds supportsNewTimerIds)
if (supportsNewTimerIds != null)
{ {
newTimerId = await supportsNewTimerIds.CreateSeriesTimer(info, cancellationToken).ConfigureAwait(false); newTimerId = await supportsNewTimerIds.CreateSeriesTimer(info, cancellationToken).ConfigureAwait(false);
newTimerId = _tvDtoService.GetInternalSeriesTimerId(newTimerId).ToString("N"); newTimerId = _tvDtoService.GetInternalSeriesTimerId(newTimerId).ToString("N");
@ -2354,8 +2274,7 @@ namespace Emby.Server.Implementations.LiveTv
throw new ResourceNotFoundException(); throw new ResourceNotFoundException();
} }
var configurable = provider as IConfigurableTunerHost; if (provider is IConfigurableTunerHost configurable)
if (configurable != null)
{ {
await configurable.Validate(info).ConfigureAwait(false); await configurable.Validate(info).ConfigureAwait(false);
} }

View file

@ -549,13 +549,13 @@ namespace Emby.Server.Implementations.Updates
// Do plugin-specific processing // Do plugin-specific processing
if (isPlugin) if (isPlugin)
{ {
if (plugin != null) if (plugin == null)
{ {
OnPluginUpdated(plugin, package); OnPluginInstalled(package);
} }
else else
{ {
OnPluginInstalled(package); OnPluginUpdated(plugin, package);
} }
} }
} }

View file

@ -1,7 +1,4 @@
using System; using System.IO;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MediaBrowser.Common.Net namespace MediaBrowser.Common.Net