mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-23 10:34:43 +01:00
Merge remote-tracking branch 'upstream/master' into register-services-correctly
This commit is contained in:
@@ -132,7 +132,6 @@ namespace Emby.Server.Implementations
|
||||
private ISessionManager _sessionManager;
|
||||
private IHttpServer _httpServer;
|
||||
private IHttpClient _httpClient;
|
||||
private IInstallationManager _installationManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance can self restart.
|
||||
@@ -725,8 +724,6 @@ namespace Emby.Server.Implementations
|
||||
var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
|
||||
((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
|
||||
|
||||
Resolve<IInstallationManager>().PluginInstalled += PluginInstalled;
|
||||
|
||||
FindParts();
|
||||
}
|
||||
|
||||
@@ -823,41 +820,6 @@ namespace Emby.Server.Implementations
|
||||
AuthenticatedAttribute.AuthService = Resolve<IAuthService>();
|
||||
}
|
||||
|
||||
private async void PluginInstalled(object sender, GenericEventArgs<PackageVersionInfo> args)
|
||||
{
|
||||
string dir = Path.Combine(ApplicationPaths.PluginsPath, args.Argument.name);
|
||||
var types = Directory.EnumerateFiles(dir, "*.dll", SearchOption.AllDirectories)
|
||||
.Select(Assembly.LoadFrom)
|
||||
.SelectMany(x => x.ExportedTypes)
|
||||
.Where(x => x.IsClass && !x.IsAbstract && !x.IsInterface && !x.IsGenericType)
|
||||
.ToArray();
|
||||
|
||||
int oldLen = _allConcreteTypes.Length;
|
||||
Array.Resize(ref _allConcreteTypes, oldLen + types.Length);
|
||||
types.CopyTo(_allConcreteTypes, oldLen);
|
||||
|
||||
var plugins = types.Where(x => x.IsAssignableFrom(typeof(IPlugin)))
|
||||
.Select(CreateInstanceSafe)
|
||||
.Where(x => x != null)
|
||||
.Cast<IPlugin>()
|
||||
.Select(LoadPlugin)
|
||||
.Where(x => x != null)
|
||||
.ToArray();
|
||||
|
||||
oldLen = _plugins.Length;
|
||||
Array.Resize(ref _plugins, oldLen + plugins.Length);
|
||||
plugins.CopyTo(_plugins, oldLen);
|
||||
|
||||
var entries = types.Where(x => x.IsAssignableFrom(typeof(IServerEntryPoint)))
|
||||
.Select(CreateInstanceSafe)
|
||||
.Where(x => x != null)
|
||||
.Cast<IServerEntryPoint>()
|
||||
.ToList();
|
||||
|
||||
await Task.WhenAll(StartEntryPoints(entries, true)).ConfigureAwait(false);
|
||||
await Task.WhenAll(StartEntryPoints(entries, false)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds plugin components and register them with the appropriate services.
|
||||
/// </summary>
|
||||
@@ -1198,7 +1160,7 @@ namespace Emby.Server.Implementations
|
||||
IsShuttingDown = IsShuttingDown,
|
||||
Version = ApplicationVersionString,
|
||||
WebSocketPortNumber = HttpPort,
|
||||
CompletedInstallations = _installationManager.CompletedInstallations.ToArray(),
|
||||
CompletedInstallations = Resolve<IInstallationManager>().CompletedInstallations.ToArray(),
|
||||
Id = SystemId,
|
||||
ProgramDataPath = ApplicationPaths.ProgramDataPath,
|
||||
WebPath = ApplicationPaths.WebPath,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Emby.Server.Implementations.HttpServer;
|
||||
using Emby.Server.Implementations.Updates;
|
||||
using MediaBrowser.Providers.Music;
|
||||
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
||||
|
||||
@@ -17,6 +18,7 @@ namespace Emby.Server.Implementations
|
||||
{
|
||||
{ HostWebClientKey, bool.TrueString },
|
||||
{ HttpListenerHost.DefaultRedirectKey, "web/index.html" },
|
||||
{ InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest.json" },
|
||||
{ FfmpegProbeSizeKey, "1G" },
|
||||
{ FfmpegAnalyzeDurationKey, "200M" },
|
||||
{ PlaylistsAllowDuplicatesKey, bool.TrueString }
|
||||
|
||||
@@ -287,7 +287,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
}
|
||||
|
||||
public static void TryBind(this IStatement statement, string name, byte[] value)
|
||||
public static void TryBind(this IStatement statement, string name, ReadOnlySpan<byte> value)
|
||||
{
|
||||
if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam))
|
||||
{
|
||||
|
||||
@@ -3314,7 +3314,7 @@ namespace Emby.Server.Implementations.Data
|
||||
|
||||
for (int i = 0; i < str.Length; i++)
|
||||
{
|
||||
if (!(char.IsLetter(str[i])) && (!(char.IsNumber(str[i]))))
|
||||
if (!char.IsLetter(str[i]) && !char.IsNumber(str[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -3338,7 +3338,7 @@ namespace Emby.Server.Implementations.Data
|
||||
return IsAlphaNumeric(value);
|
||||
}
|
||||
|
||||
private List<string> GetWhereClauses(InternalItemsQuery query, IStatement statement, string paramSuffix = "")
|
||||
private List<string> GetWhereClauses(InternalItemsQuery query, IStatement statement)
|
||||
{
|
||||
if (query.IsResumable ?? false)
|
||||
{
|
||||
@@ -3350,27 +3350,27 @@ namespace Emby.Server.Implementations.Data
|
||||
|
||||
if (query.IsHD.HasValue)
|
||||
{
|
||||
var threshold = 1200;
|
||||
const int Threshold = 1200;
|
||||
if (query.IsHD.Value)
|
||||
{
|
||||
minWidth = threshold;
|
||||
minWidth = Threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxWidth = threshold - 1;
|
||||
maxWidth = Threshold - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.Is4K.HasValue)
|
||||
{
|
||||
var threshold = 3800;
|
||||
const int Threshold = 3800;
|
||||
if (query.Is4K.Value)
|
||||
{
|
||||
minWidth = threshold;
|
||||
minWidth = Threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxWidth = threshold - 1;
|
||||
maxWidth = Threshold - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3379,93 +3379,61 @@ namespace Emby.Server.Implementations.Data
|
||||
if (minWidth.HasValue)
|
||||
{
|
||||
whereClauses.Add("Width>=@MinWidth");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinWidth", minWidth);
|
||||
}
|
||||
statement?.TryBind("@MinWidth", minWidth);
|
||||
}
|
||||
|
||||
if (query.MinHeight.HasValue)
|
||||
{
|
||||
whereClauses.Add("Height>=@MinHeight");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinHeight", query.MinHeight);
|
||||
}
|
||||
statement?.TryBind("@MinHeight", query.MinHeight);
|
||||
}
|
||||
|
||||
if (maxWidth.HasValue)
|
||||
{
|
||||
whereClauses.Add("Width<=@MaxWidth");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MaxWidth", maxWidth);
|
||||
}
|
||||
statement?.TryBind("@MaxWidth", maxWidth);
|
||||
}
|
||||
|
||||
if (query.MaxHeight.HasValue)
|
||||
{
|
||||
whereClauses.Add("Height<=@MaxHeight");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MaxHeight", query.MaxHeight);
|
||||
}
|
||||
statement?.TryBind("@MaxHeight", query.MaxHeight);
|
||||
}
|
||||
|
||||
if (query.IsLocked.HasValue)
|
||||
{
|
||||
whereClauses.Add("IsLocked=@IsLocked");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsLocked", query.IsLocked);
|
||||
}
|
||||
statement?.TryBind("@IsLocked", query.IsLocked);
|
||||
}
|
||||
|
||||
var tags = query.Tags.ToList();
|
||||
var excludeTags = query.ExcludeTags.ToList();
|
||||
|
||||
if (query.IsMovie ?? false)
|
||||
if (query.IsMovie == true)
|
||||
{
|
||||
var alternateTypes = new List<string>();
|
||||
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
|
||||
if (query.IncludeItemTypes.Length == 0
|
||||
|| query.IncludeItemTypes.Contains(nameof(Movie))
|
||||
|| query.IncludeItemTypes.Contains(nameof(Trailer)))
|
||||
{
|
||||
alternateTypes.Add(typeof(Movie).FullName);
|
||||
}
|
||||
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
|
||||
{
|
||||
alternateTypes.Add(typeof(Trailer).FullName);
|
||||
}
|
||||
|
||||
var programAttribtues = new List<string>();
|
||||
if (alternateTypes.Count == 0)
|
||||
{
|
||||
programAttribtues.Add("IsMovie=@IsMovie");
|
||||
whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
|
||||
}
|
||||
else
|
||||
{
|
||||
programAttribtues.Add("(IsMovie is null OR IsMovie=@IsMovie)");
|
||||
whereClauses.Add("IsMovie=@IsMovie");
|
||||
}
|
||||
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsMovie", true);
|
||||
}
|
||||
|
||||
whereClauses.Add("(" + string.Join(" OR ", programAttribtues) + ")");
|
||||
statement?.TryBind("@IsMovie", true);
|
||||
}
|
||||
else if (query.IsMovie.HasValue)
|
||||
{
|
||||
whereClauses.Add("IsMovie=@IsMovie");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsMovie", query.IsMovie);
|
||||
}
|
||||
statement?.TryBind("@IsMovie", query.IsMovie);
|
||||
}
|
||||
|
||||
if (query.IsSeries.HasValue)
|
||||
{
|
||||
whereClauses.Add("IsSeries=@IsSeries");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsSeries", query.IsSeries);
|
||||
}
|
||||
statement?.TryBind("@IsSeries", query.IsSeries);
|
||||
}
|
||||
|
||||
if (query.IsSports.HasValue)
|
||||
@@ -3517,10 +3485,7 @@ namespace Emby.Server.Implementations.Data
|
||||
if (query.IsFolder.HasValue)
|
||||
{
|
||||
whereClauses.Add("IsFolder=@IsFolder");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsFolder", query.IsFolder);
|
||||
}
|
||||
statement?.TryBind("@IsFolder", query.IsFolder);
|
||||
}
|
||||
|
||||
var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
|
||||
@@ -3531,10 +3496,7 @@ namespace Emby.Server.Implementations.Data
|
||||
if (excludeTypes.Length == 1)
|
||||
{
|
||||
whereClauses.Add("type<>@type");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@type", excludeTypes[0]);
|
||||
}
|
||||
statement?.TryBind("@type", excludeTypes[0]);
|
||||
}
|
||||
else if (excludeTypes.Length > 1)
|
||||
{
|
||||
@@ -3545,10 +3507,7 @@ namespace Emby.Server.Implementations.Data
|
||||
else if (includeTypes.Length == 1)
|
||||
{
|
||||
whereClauses.Add("type=@type");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@type", includeTypes[0]);
|
||||
}
|
||||
statement?.TryBind("@type", includeTypes[0]);
|
||||
}
|
||||
else if (includeTypes.Length > 1)
|
||||
{
|
||||
@@ -3559,10 +3518,7 @@ namespace Emby.Server.Implementations.Data
|
||||
if (query.ChannelIds.Length == 1)
|
||||
{
|
||||
whereClauses.Add("ChannelId=@ChannelId");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@ChannelId", query.ChannelIds[0].ToString("N", CultureInfo.InvariantCulture));
|
||||
}
|
||||
statement?.TryBind("@ChannelId", query.ChannelIds[0].ToString("N", CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (query.ChannelIds.Length > 1)
|
||||
{
|
||||
@@ -3573,98 +3529,65 @@ namespace Emby.Server.Implementations.Data
|
||||
if (!query.ParentId.Equals(Guid.Empty))
|
||||
{
|
||||
whereClauses.Add("ParentId=@ParentId");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@ParentId", query.ParentId);
|
||||
}
|
||||
statement?.TryBind("@ParentId", query.ParentId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.Path))
|
||||
{
|
||||
whereClauses.Add("Path=@Path");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@Path", GetPathToSave(query.Path));
|
||||
}
|
||||
statement?.TryBind("@Path", GetPathToSave(query.Path));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
|
||||
{
|
||||
whereClauses.Add("PresentationUniqueKey=@PresentationUniqueKey");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@PresentationUniqueKey", query.PresentationUniqueKey);
|
||||
}
|
||||
statement?.TryBind("@PresentationUniqueKey", query.PresentationUniqueKey);
|
||||
}
|
||||
|
||||
if (query.MinCommunityRating.HasValue)
|
||||
{
|
||||
whereClauses.Add("CommunityRating>=@MinCommunityRating");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinCommunityRating", query.MinCommunityRating.Value);
|
||||
}
|
||||
statement?.TryBind("@MinCommunityRating", query.MinCommunityRating.Value);
|
||||
}
|
||||
|
||||
if (query.MinIndexNumber.HasValue)
|
||||
{
|
||||
whereClauses.Add("IndexNumber>=@MinIndexNumber");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinIndexNumber", query.MinIndexNumber.Value);
|
||||
}
|
||||
statement?.TryBind("@MinIndexNumber", query.MinIndexNumber.Value);
|
||||
}
|
||||
|
||||
if (query.MinDateCreated.HasValue)
|
||||
{
|
||||
whereClauses.Add("DateCreated>=@MinDateCreated");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinDateCreated", query.MinDateCreated.Value);
|
||||
}
|
||||
statement?.TryBind("@MinDateCreated", query.MinDateCreated.Value);
|
||||
}
|
||||
|
||||
if (query.MinDateLastSaved.HasValue)
|
||||
{
|
||||
whereClauses.Add("(DateLastSaved not null and DateLastSaved>=@MinDateLastSavedForUser)");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinDateLastSaved", query.MinDateLastSaved.Value);
|
||||
}
|
||||
statement?.TryBind("@MinDateLastSaved", query.MinDateLastSaved.Value);
|
||||
}
|
||||
|
||||
if (query.MinDateLastSavedForUser.HasValue)
|
||||
{
|
||||
whereClauses.Add("(DateLastSaved not null and DateLastSaved>=@MinDateLastSavedForUser)");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinDateLastSavedForUser", query.MinDateLastSavedForUser.Value);
|
||||
}
|
||||
statement?.TryBind("@MinDateLastSavedForUser", query.MinDateLastSavedForUser.Value);
|
||||
}
|
||||
|
||||
if (query.IndexNumber.HasValue)
|
||||
{
|
||||
whereClauses.Add("IndexNumber=@IndexNumber");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IndexNumber", query.IndexNumber.Value);
|
||||
}
|
||||
statement?.TryBind("@IndexNumber", query.IndexNumber.Value);
|
||||
}
|
||||
if (query.ParentIndexNumber.HasValue)
|
||||
{
|
||||
whereClauses.Add("ParentIndexNumber=@ParentIndexNumber");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@ParentIndexNumber", query.ParentIndexNumber.Value);
|
||||
}
|
||||
statement?.TryBind("@ParentIndexNumber", query.ParentIndexNumber.Value);
|
||||
}
|
||||
if (query.ParentIndexNumberNotEquals.HasValue)
|
||||
{
|
||||
whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@ParentIndexNumberNotEquals", query.ParentIndexNumberNotEquals.Value);
|
||||
}
|
||||
statement?.TryBind("@ParentIndexNumberNotEquals", query.ParentIndexNumberNotEquals.Value);
|
||||
}
|
||||
|
||||
var minEndDate = query.MinEndDate;
|
||||
@@ -3685,73 +3608,59 @@ namespace Emby.Server.Implementations.Data
|
||||
if (minEndDate.HasValue)
|
||||
{
|
||||
whereClauses.Add("EndDate>=@MinEndDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinEndDate", minEndDate.Value);
|
||||
}
|
||||
statement?.TryBind("@MinEndDate", minEndDate.Value);
|
||||
}
|
||||
|
||||
if (maxEndDate.HasValue)
|
||||
{
|
||||
whereClauses.Add("EndDate<=@MaxEndDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MaxEndDate", maxEndDate.Value);
|
||||
}
|
||||
statement?.TryBind("@MaxEndDate", maxEndDate.Value);
|
||||
}
|
||||
|
||||
if (query.MinStartDate.HasValue)
|
||||
{
|
||||
whereClauses.Add("StartDate>=@MinStartDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinStartDate", query.MinStartDate.Value);
|
||||
}
|
||||
statement?.TryBind("@MinStartDate", query.MinStartDate.Value);
|
||||
}
|
||||
|
||||
if (query.MaxStartDate.HasValue)
|
||||
{
|
||||
whereClauses.Add("StartDate<=@MaxStartDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MaxStartDate", query.MaxStartDate.Value);
|
||||
}
|
||||
statement?.TryBind("@MaxStartDate", query.MaxStartDate.Value);
|
||||
}
|
||||
|
||||
if (query.MinPremiereDate.HasValue)
|
||||
{
|
||||
whereClauses.Add("PremiereDate>=@MinPremiereDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinPremiereDate", query.MinPremiereDate.Value);
|
||||
}
|
||||
statement?.TryBind("@MinPremiereDate", query.MinPremiereDate.Value);
|
||||
}
|
||||
|
||||
if (query.MaxPremiereDate.HasValue)
|
||||
{
|
||||
whereClauses.Add("PremiereDate<=@MaxPremiereDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MaxPremiereDate", query.MaxPremiereDate.Value);
|
||||
}
|
||||
statement?.TryBind("@MaxPremiereDate", query.MaxPremiereDate.Value);
|
||||
}
|
||||
|
||||
if (query.TrailerTypes.Length > 0)
|
||||
var trailerTypes = query.TrailerTypes;
|
||||
int trailerTypesLen = trailerTypes.Length;
|
||||
if (trailerTypesLen > 0)
|
||||
{
|
||||
var clauses = new List<string>();
|
||||
var index = 0;
|
||||
foreach (var type in query.TrailerTypes)
|
||||
const string Or = " OR ";
|
||||
StringBuilder clause = new StringBuilder("(", trailerTypesLen * 32);
|
||||
for (int i = 0; i < trailerTypesLen; i++)
|
||||
{
|
||||
var paramName = "@TrailerTypes" + index;
|
||||
|
||||
clauses.Add("TrailerTypes like " + paramName);
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind(paramName, "%" + type + "%");
|
||||
}
|
||||
index++;
|
||||
var paramName = "@TrailerTypes" + i;
|
||||
clause.Append("TrailerTypes like ")
|
||||
.Append(paramName)
|
||||
.Append(Or);
|
||||
statement?.TryBind(paramName, "%" + trailerTypes[i] + "%");
|
||||
}
|
||||
var clause = "(" + string.Join(" OR ", clauses) + ")";
|
||||
whereClauses.Add(clause);
|
||||
|
||||
// Remove last " OR "
|
||||
clause.Length -= Or.Length;
|
||||
clause.Append(')');
|
||||
|
||||
whereClauses.Add(clause.ToString());
|
||||
}
|
||||
|
||||
if (query.IsAiring.HasValue)
|
||||
@@ -3759,24 +3668,15 @@ namespace Emby.Server.Implementations.Data
|
||||
if (query.IsAiring.Value)
|
||||
{
|
||||
whereClauses.Add("StartDate<=@MaxStartDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MaxStartDate", DateTime.UtcNow);
|
||||
}
|
||||
statement?.TryBind("@MaxStartDate", DateTime.UtcNow);
|
||||
|
||||
whereClauses.Add("EndDate>=@MinEndDate");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinEndDate", DateTime.UtcNow);
|
||||
}
|
||||
statement?.TryBind("@MinEndDate", DateTime.UtcNow);
|
||||
}
|
||||
else
|
||||
{
|
||||
whereClauses.Add("(StartDate>@IsAiringDate OR EndDate < @IsAiringDate)");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsAiringDate", DateTime.UtcNow);
|
||||
}
|
||||
statement?.TryBind("@IsAiringDate", DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3791,13 +3691,10 @@ namespace Emby.Server.Implementations.Data
|
||||
var paramName = "@PersonId" + index;
|
||||
|
||||
clauses.Add("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=" + paramName + ")))");
|
||||
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind(paramName, personId.ToByteArray());
|
||||
}
|
||||
statement?.TryBind(paramName, personId.ToByteArray());
|
||||
index++;
|
||||
}
|
||||
|
||||
var clause = "(" + string.Join(" OR ", clauses) + ")";
|
||||
whereClauses.Add(clause);
|
||||
}
|
||||
@@ -3805,47 +3702,31 @@ namespace Emby.Server.Implementations.Data
|
||||
if (!string.IsNullOrWhiteSpace(query.Person))
|
||||
{
|
||||
whereClauses.Add("Guid in (select ItemId from People where Name=@PersonName)");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@PersonName", query.Person);
|
||||
}
|
||||
statement?.TryBind("@PersonName", query.Person);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.MinSortName))
|
||||
{
|
||||
whereClauses.Add("SortName>=@MinSortName");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinSortName", query.MinSortName);
|
||||
}
|
||||
statement?.TryBind("@MinSortName", query.MinSortName);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.ExternalSeriesId))
|
||||
{
|
||||
whereClauses.Add("ExternalSeriesId=@ExternalSeriesId");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@ExternalSeriesId", query.ExternalSeriesId);
|
||||
}
|
||||
statement?.TryBind("@ExternalSeriesId", query.ExternalSeriesId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.ExternalId))
|
||||
{
|
||||
whereClauses.Add("ExternalId=@ExternalId");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@ExternalId", query.ExternalId);
|
||||
}
|
||||
statement?.TryBind("@ExternalId", query.ExternalId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.Name))
|
||||
{
|
||||
whereClauses.Add("CleanName=@Name");
|
||||
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@Name", GetCleanValue(query.Name));
|
||||
}
|
||||
statement?.TryBind("@Name", GetCleanValue(query.Name));
|
||||
}
|
||||
|
||||
// These are the same, for now
|
||||
@@ -3864,28 +3745,21 @@ namespace Emby.Server.Implementations.Data
|
||||
if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
|
||||
{
|
||||
whereClauses.Add("SortName like @NameStartsWith");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@NameStartsWith", query.NameStartsWith + "%");
|
||||
}
|
||||
statement?.TryBind("@NameStartsWith", query.NameStartsWith + "%");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater))
|
||||
{
|
||||
whereClauses.Add("SortName >= @NameStartsWithOrGreater");
|
||||
// lowercase this because SortName is stored as lowercase
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLowerInvariant());
|
||||
}
|
||||
statement?.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLowerInvariant());
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.NameLessThan))
|
||||
{
|
||||
whereClauses.Add("SortName < @NameLessThan");
|
||||
// lowercase this because SortName is stored as lowercase
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@NameLessThan", query.NameLessThan.ToLowerInvariant());
|
||||
}
|
||||
statement?.TryBind("@NameLessThan", query.NameLessThan.ToLowerInvariant());
|
||||
}
|
||||
|
||||
if (query.ImageTypes.Length > 0)
|
||||
@@ -3901,18 +3775,12 @@ namespace Emby.Server.Implementations.Data
|
||||
if (query.IsLiked.Value)
|
||||
{
|
||||
whereClauses.Add("rating>=@UserRating");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@UserRating", UserItemData.MinLikeValue);
|
||||
}
|
||||
statement?.TryBind("@UserRating", UserItemData.MinLikeValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
whereClauses.Add("(rating is null or rating<@UserRating)");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@UserRating", UserItemData.MinLikeValue);
|
||||
}
|
||||
statement?.TryBind("@UserRating", UserItemData.MinLikeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3926,10 +3794,8 @@ namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavoriteOrLiked)");
|
||||
}
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsFavoriteOrLiked", query.IsFavoriteOrLiked.Value);
|
||||
}
|
||||
|
||||
statement?.TryBind("@IsFavoriteOrLiked", query.IsFavoriteOrLiked.Value);
|
||||
}
|
||||
|
||||
if (query.IsFavorite.HasValue)
|
||||
@@ -3942,10 +3808,8 @@ namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavorite)");
|
||||
}
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsFavorite", query.IsFavorite.Value);
|
||||
}
|
||||
|
||||
statement?.TryBind("@IsFavorite", query.IsFavorite.Value);
|
||||
}
|
||||
|
||||
if (EnableJoinUserData(query))
|
||||
@@ -3974,10 +3838,8 @@ namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
whereClauses.Add("(played is null or played=@IsPlayed)");
|
||||
}
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@IsPlayed", query.IsPlayed.Value);
|
||||
}
|
||||
|
||||
statement?.TryBind("@IsPlayed", query.IsPlayed.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4009,6 +3871,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
var clause = "(" + string.Join(" OR ", clauses) + ")";
|
||||
whereClauses.Add(clause);
|
||||
}
|
||||
@@ -4028,6 +3891,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
var clause = "(" + string.Join(" OR ", clauses) + ")";
|
||||
whereClauses.Add(clause);
|
||||
}
|
||||
@@ -4761,18 +4625,22 @@ namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
list.Add(typeof(Person).Name);
|
||||
}
|
||||
|
||||
if (IsTypeInQuery(typeof(Genre).Name, query))
|
||||
{
|
||||
list.Add(typeof(Genre).Name);
|
||||
}
|
||||
|
||||
if (IsTypeInQuery(typeof(MusicGenre).Name, query))
|
||||
{
|
||||
list.Add(typeof(MusicGenre).Name);
|
||||
}
|
||||
|
||||
if (IsTypeInQuery(typeof(MusicArtist).Name, query))
|
||||
{
|
||||
list.Add(typeof(MusicArtist).Name);
|
||||
}
|
||||
|
||||
if (IsTypeInQuery(typeof(Studio).Name, query))
|
||||
{
|
||||
list.Add(typeof(Studio).Name);
|
||||
@@ -4846,7 +4714,7 @@ namespace Emby.Server.Implementations.Data
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly Type[] KnownTypes =
|
||||
private static readonly Type[] _knownTypes =
|
||||
{
|
||||
typeof(LiveTvProgram),
|
||||
typeof(LiveTvChannel),
|
||||
@@ -4915,7 +4783,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
{
|
||||
var dict = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var t in KnownTypes)
|
||||
foreach (var t in _knownTypes)
|
||||
{
|
||||
dict[t.Name] = new[] { t.FullName };
|
||||
}
|
||||
@@ -4927,7 +4795,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
}
|
||||
|
||||
// Not crazy about having this all the way down here, but at least it's in one place
|
||||
readonly Dictionary<string, string[]> _types = GetTypeMapDictionary();
|
||||
private readonly Dictionary<string, string[]> _types = GetTypeMapDictionary();
|
||||
|
||||
private string[] MapIncludeItemTypes(string value)
|
||||
{
|
||||
@@ -4944,7 +4812,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
public void DeleteItem(Guid id, CancellationToken cancellationToken)
|
||||
public void DeleteItem(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
@@ -4980,7 +4848,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteWithSingleParam(IDatabaseConnection db, string query, byte[] value)
|
||||
private void ExecuteWithSingleParam(IDatabaseConnection db, string query, ReadOnlySpan<byte> value)
|
||||
{
|
||||
using (var statement = PrepareStatement(db, query))
|
||||
{
|
||||
@@ -5540,6 +5408,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
{
|
||||
GetWhereClauses(typeSubQuery, null);
|
||||
}
|
||||
|
||||
BindSimilarParams(query, statement);
|
||||
BindSearchParams(query, statement);
|
||||
GetWhereClauses(innerQuery, statement);
|
||||
@@ -5581,7 +5450,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
}
|
||||
|
||||
var allTypes = typeString.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.ToLookup(i => i);
|
||||
.ToLookup(x => x);
|
||||
|
||||
foreach (var type in allTypes)
|
||||
{
|
||||
@@ -5672,30 +5541,26 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
|
||||
private void InsertItemValues(byte[] idBlob, List<(int, string)> values, IDatabaseConnection db)
|
||||
{
|
||||
const int Limit = 100;
|
||||
var startIndex = 0;
|
||||
var limit = 100;
|
||||
|
||||
while (startIndex < values.Count)
|
||||
{
|
||||
var insertText = new StringBuilder("insert into ItemValues (ItemId, Type, Value, CleanValue) values ");
|
||||
|
||||
var endIndex = Math.Min(values.Count, startIndex + limit);
|
||||
var isSubsequentRow = false;
|
||||
var endIndex = Math.Min(values.Count, startIndex + Limit);
|
||||
|
||||
for (var i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
if (isSubsequentRow)
|
||||
{
|
||||
insertText.Append(',');
|
||||
}
|
||||
|
||||
insertText.AppendFormat(
|
||||
CultureInfo.InvariantCulture,
|
||||
"(@ItemId, @Type{0}, @Value{0}, @CleanValue{0})",
|
||||
"(@ItemId, @Type{0}, @Value{0}, @CleanValue{0}),",
|
||||
i);
|
||||
isSubsequentRow = true;
|
||||
}
|
||||
|
||||
// Remove last comma
|
||||
insertText.Length--;
|
||||
|
||||
using (var statement = PrepareStatement(db, insertText.ToString()))
|
||||
{
|
||||
statement.TryBind("@ItemId", idBlob);
|
||||
@@ -5723,7 +5588,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
startIndex += limit;
|
||||
startIndex += Limit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5758,28 +5623,23 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
|
||||
private void InsertPeople(byte[] idBlob, List<PersonInfo> people, IDatabaseConnection db)
|
||||
{
|
||||
const int Limit = 100;
|
||||
var startIndex = 0;
|
||||
var limit = 100;
|
||||
var listIndex = 0;
|
||||
|
||||
while (startIndex < people.Count)
|
||||
{
|
||||
var insertText = new StringBuilder("insert into People (ItemId, Name, Role, PersonType, SortOrder, ListOrder) values ");
|
||||
|
||||
var endIndex = Math.Min(people.Count, startIndex + limit);
|
||||
var isSubsequentRow = false;
|
||||
|
||||
var endIndex = Math.Min(people.Count, startIndex + Limit);
|
||||
for (var i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
if (isSubsequentRow)
|
||||
{
|
||||
insertText.Append(',');
|
||||
}
|
||||
|
||||
insertText.AppendFormat("(@ItemId, @Name{0}, @Role{0}, @PersonType{0}, @SortOrder{0}, @ListOrder{0})", i.ToString(CultureInfo.InvariantCulture));
|
||||
isSubsequentRow = true;
|
||||
insertText.AppendFormat("(@ItemId, @Name{0}, @Role{0}, @PersonType{0}, @SortOrder{0}, @ListOrder{0}),", i.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
// Remove last comma
|
||||
insertText.Length--;
|
||||
|
||||
using (var statement = PrepareStatement(db, insertText.ToString()))
|
||||
{
|
||||
statement.TryBind("@ItemId", idBlob);
|
||||
@@ -5803,16 +5663,17 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
startIndex += limit;
|
||||
startIndex += Limit;
|
||||
}
|
||||
}
|
||||
|
||||
private PersonInfo GetPerson(IReadOnlyList<IResultSetValue> reader)
|
||||
{
|
||||
var item = new PersonInfo();
|
||||
|
||||
item.ItemId = reader.GetGuid(0);
|
||||
item.Name = reader.GetString(1);
|
||||
var item = new PersonInfo
|
||||
{
|
||||
ItemId = reader.GetGuid(0),
|
||||
Name = reader.GetString(1)
|
||||
};
|
||||
|
||||
if (!reader.IsDBNull(2))
|
||||
{
|
||||
@@ -5919,20 +5780,28 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
|
||||
private void InsertMediaStreams(byte[] idBlob, List<MediaStream> streams, IDatabaseConnection db)
|
||||
{
|
||||
const int Limit = 10;
|
||||
var startIndex = 0;
|
||||
var limit = 10;
|
||||
|
||||
while (startIndex < streams.Count)
|
||||
{
|
||||
var insertText = new StringBuilder(string.Format("insert into mediastreams ({0}) values ", string.Join(",", _mediaStreamSaveColumns)));
|
||||
var insertText = new StringBuilder("insert into mediastreams (");
|
||||
foreach (var column in _mediaStreamSaveColumns)
|
||||
{
|
||||
insertText.Append(column).Append(',');
|
||||
}
|
||||
|
||||
var endIndex = Math.Min(streams.Count, startIndex + limit);
|
||||
// Remove last comma
|
||||
insertText.Length--;
|
||||
insertText.Append(") values ");
|
||||
|
||||
var endIndex = Math.Min(streams.Count, startIndex + Limit);
|
||||
|
||||
for (var i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
if (i != startIndex)
|
||||
{
|
||||
insertText.Append(",");
|
||||
insertText.Append(',');
|
||||
}
|
||||
|
||||
var index = i.ToString(CultureInfo.InvariantCulture);
|
||||
@@ -5940,11 +5809,12 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
|
||||
foreach (var column in _mediaStreamSaveColumns.Skip(1))
|
||||
{
|
||||
insertText.Append("@" + column + index + ",");
|
||||
insertText.Append('@').Append(column).Append(index).Append(',');
|
||||
}
|
||||
|
||||
insertText.Length -= 1; // Remove the last comma
|
||||
|
||||
insertText.Append(")");
|
||||
insertText.Append(')');
|
||||
}
|
||||
|
||||
using (var statement = PrepareStatement(db, insertText.ToString()))
|
||||
@@ -6006,7 +5876,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
startIndex += limit;
|
||||
startIndex += Limit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6023,7 +5893,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||
Index = reader[1].ToInt()
|
||||
};
|
||||
|
||||
item.Type = (MediaStreamType)Enum.Parse(typeof(MediaStreamType), reader[2].ToString(), true);
|
||||
item.Type = Enum.Parse<MediaStreamType>(reader[2].ToString(), true);
|
||||
|
||||
if (reader[3].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
|
||||
@@ -1058,30 +1058,19 @@ namespace Emby.Server.Implementations.Dto
|
||||
|
||||
if (options.ContainsField(ItemFields.SpecialFeatureCount))
|
||||
{
|
||||
if (allExtras == null)
|
||||
{
|
||||
allExtras = item.GetExtras().ToArray();
|
||||
}
|
||||
|
||||
allExtras = item.GetExtras().ToArray();
|
||||
dto.SpecialFeatureCount = allExtras.Count(i => i.ExtraType.HasValue && BaseItem.DisplayExtraTypes.Contains(i.ExtraType.Value));
|
||||
}
|
||||
|
||||
if (options.ContainsField(ItemFields.LocalTrailerCount))
|
||||
{
|
||||
int trailerCount = 0;
|
||||
if (allExtras == null)
|
||||
{
|
||||
allExtras = item.GetExtras().ToArray();
|
||||
}
|
||||
|
||||
trailerCount += allExtras.Count(i => i.ExtraType.HasValue && i.ExtraType.Value == ExtraType.Trailer);
|
||||
allExtras ??= item.GetExtras().ToArray();
|
||||
dto.LocalTrailerCount = allExtras.Count(i => i.ExtraType == ExtraType.Trailer);
|
||||
|
||||
if (item is IHasTrailers hasTrailers)
|
||||
{
|
||||
trailerCount += hasTrailers.GetTrailerCount();
|
||||
dto.LocalTrailerCount += hasTrailers.GetTrailerCount();
|
||||
}
|
||||
|
||||
dto.LocalTrailerCount = trailerCount;
|
||||
}
|
||||
|
||||
// Add EpisodeInfo
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />
|
||||
<PackageReference Include="Mono.Nat" Version="2.0.0" />
|
||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.8.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.24.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.25.0" />
|
||||
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
|
||||
<PackageReference Include="System.Interactive.Async" Version="4.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -23,6 +23,7 @@ using MediaBrowser.Model.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ServiceStack.Text.Jsv;
|
||||
|
||||
@@ -48,6 +49,8 @@ namespace Emby.Server.Implementations.HttpServer
|
||||
private readonly string _baseUrlPrefix;
|
||||
private readonly Dictionary<Type, Type> _serviceOperationsMap = new Dictionary<Type, Type>();
|
||||
private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
|
||||
private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
|
||||
private bool _disposed = false;
|
||||
|
||||
@@ -61,7 +64,8 @@ namespace Emby.Server.Implementations.HttpServer
|
||||
IXmlSerializer xmlSerializer,
|
||||
IHttpListener socketListener,
|
||||
ILocalizationManager localizationManager,
|
||||
ServiceController serviceController)
|
||||
ServiceController serviceController,
|
||||
IHostEnvironment hostEnvironment)
|
||||
{
|
||||
_appHost = applicationHost;
|
||||
_logger = logger;
|
||||
@@ -75,6 +79,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||
ServiceController = serviceController;
|
||||
|
||||
_socketListener.WebSocketConnected = OnWebSocketConnected;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
|
||||
_funcParseFn = t => s => JsvReader.GetParseFn(t)(s);
|
||||
|
||||
@@ -530,22 +535,25 @@ namespace Emby.Server.Implementations.HttpServer
|
||||
}
|
||||
else
|
||||
{
|
||||
await ErrorHandler(new FileNotFoundException(), httpReq, false).ConfigureAwait(false);
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is SocketException || ex is IOException || ex is OperationCanceledException)
|
||||
{
|
||||
await ErrorHandler(ex, httpReq, false).ConfigureAwait(false);
|
||||
}
|
||||
catch (SecurityException ex)
|
||||
{
|
||||
await ErrorHandler(ex, httpReq, false).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var logException = !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase);
|
||||
// Do not handle exceptions manually when in development mode
|
||||
// The framework-defined development exception page will be returned instead
|
||||
if (_hostEnvironment.IsDevelopment())
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
await ErrorHandler(ex, httpReq, logException).ConfigureAwait(false);
|
||||
bool ignoreStackTrace =
|
||||
ex is SocketException
|
||||
|| ex is IOException
|
||||
|| ex is OperationCanceledException
|
||||
|| ex is SecurityException
|
||||
|| ex is FileNotFoundException;
|
||||
await ErrorHandler(ex, httpReq, ignoreStackTrace).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -3,33 +3,38 @@ namespace Emby.Server.Implementations
|
||||
public interface IStartupOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// --ffmpeg
|
||||
/// Gets the value of the --ffmpeg command line option.
|
||||
/// </summary>
|
||||
string FFmpegPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// --service
|
||||
/// Gets the value of the --service command line option.
|
||||
/// </summary>
|
||||
bool IsService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// --noautorunwebapp
|
||||
/// Gets the value of the --noautorunwebapp command line option.
|
||||
/// </summary>
|
||||
bool NoAutoRunWebApp { get; }
|
||||
|
||||
/// <summary>
|
||||
/// --package-name
|
||||
/// Gets the value of the --package-name command line option.
|
||||
/// </summary>
|
||||
string PackageName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// --restartpath
|
||||
/// Gets the value of the --restartpath command line option.
|
||||
/// </summary>
|
||||
string RestartPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// --restartargs
|
||||
/// Gets the value of the --restartargs command line option.
|
||||
/// </summary>
|
||||
string RestartArgs { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the --plugin-manifest-url command line option.
|
||||
/// </summary>
|
||||
string PluginManifestUrl { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,10 +408,10 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
item.SetParent(null);
|
||||
|
||||
_itemRepository.DeleteItem(item.Id, CancellationToken.None);
|
||||
_itemRepository.DeleteItem(item.Id);
|
||||
foreach (var child in children)
|
||||
{
|
||||
_itemRepository.DeleteItem(child.Id, CancellationToken.None);
|
||||
_itemRepository.DeleteItem(child.Id);
|
||||
}
|
||||
|
||||
_libraryItemsCache.TryRemove(item.Id, out BaseItem removed);
|
||||
@@ -2580,14 +2580,12 @@ namespace Emby.Server.Implementations.Library
|
||||
}).OrderBy(i => i.Path);
|
||||
}
|
||||
|
||||
private static readonly string[] ExtrasSubfolderNames = new[] { "extras", "specials", "shorts", "scenes", "featurettes", "behind the scenes", "deleted scenes", "interviews" };
|
||||
|
||||
public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
|
||||
{
|
||||
var namingOptions = GetNamingOptions();
|
||||
|
||||
var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
|
||||
.Where(i => ExtrasSubfolderNames.Contains(i.Name ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||
.Where(i => BaseItem.AllExtrasTypesFolderNames.Contains(i.Name ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||
.SelectMany(i => _fileSystem.GetFiles(i.FullName, _videoFileExtensions, false, false))
|
||||
.ToList();
|
||||
|
||||
|
||||
@@ -102,5 +102,17 @@
|
||||
"TaskRefreshLibrary": "افحص مكتبة الوسائط",
|
||||
"TaskRefreshChapterImagesDescription": "إنشاء صور مصغرة لمقاطع الفيديو ذات فصول.",
|
||||
"TaskRefreshChapterImages": "استخراج صور الفصل",
|
||||
"TasksApplicationCategory": "تطبيق"
|
||||
"TasksApplicationCategory": "تطبيق",
|
||||
"TaskDownloadMissingSubtitlesDescription": "ابحث في الإنترنت على الترجمات المفقودة إستنادا على الميتاداتا.",
|
||||
"TaskDownloadMissingSubtitles": "تحميل الترجمات المفقودة",
|
||||
"TaskRefreshChannelsDescription": "تحديث معلومات قنوات الإنترنت.",
|
||||
"TaskRefreshChannels": "إعادة تحديث القنوات",
|
||||
"TaskCleanTranscodeDescription": "حذف ملفات الترميز الأقدم من يوم واحد.",
|
||||
"TaskCleanTranscode": "حذف سجلات الترميز",
|
||||
"TaskUpdatePluginsDescription": "تحميل وتثبيت الإضافات التي تم تفعيل التحديث التلقائي لها.",
|
||||
"TaskUpdatePlugins": "تحديث الإضافات",
|
||||
"TaskRefreshPeopleDescription": "تحديث البيانات الوصفية للممثلين والمخرجين في مكتبة الوسائط الخاصة بك.",
|
||||
"TaskRefreshPeople": "إعادة تحميل الأشخاص",
|
||||
"TaskCleanLogsDescription": "حذف السجلات الأقدم من {0} يوم.",
|
||||
"TaskCleanLogs": "حذف دليل السجل"
|
||||
}
|
||||
|
||||
@@ -92,5 +92,19 @@
|
||||
"UserStoppedPlayingItemWithValues": "{0} har afsluttet afspilning af {1} på {2}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} er blevet tilføjet til dit mediebibliotek",
|
||||
"ValueSpecialEpisodeName": "Special - {0}",
|
||||
"VersionNumber": "Version {0}"
|
||||
"VersionNumber": "Version {0}",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Søger på internettet efter manglende undertekster baseret på metadata konfiration.",
|
||||
"TaskDownloadMissingSubtitles": "Download manglende undertekster",
|
||||
"TaskUpdatePluginsDescription": "Downloader og installere opdateringer for plugins som er konfigureret til at opdatere automatisk.",
|
||||
"TaskUpdatePlugins": "Opdater Plugins",
|
||||
"TaskCleanLogsDescription": "Sletter log filer som er mere end {0} dage gammle.",
|
||||
"TaskCleanLogs": "Ryd Log Mappe",
|
||||
"TaskRefreshLibraryDescription": "Scanner dit medie bibliotek for nye filer og opdatere metadata.",
|
||||
"TaskRefreshLibrary": "Scan Medie Bibliotek",
|
||||
"TaskCleanCacheDescription": "Sletter cache filer som systemet ikke har brug for længere.",
|
||||
"TaskCleanCache": "Ryd Cache Mappe",
|
||||
"TasksChannelsCategory": "Internet Kanaler",
|
||||
"TasksApplicationCategory": "Applikation",
|
||||
"TasksLibraryCategory": "Bibliotek",
|
||||
"TasksMaintenanceCategory": "Vedligeholdelse"
|
||||
}
|
||||
|
||||
@@ -90,5 +90,13 @@
|
||||
"Artists": "Artista",
|
||||
"Application": "Aplikasyon",
|
||||
"AppDeviceValues": "Aplikasyon: {0}, Aparato: {1}",
|
||||
"Albums": "Albums"
|
||||
"Albums": "Albums",
|
||||
"TaskRefreshLibrary": "Suriin ang nasa librerya",
|
||||
"TaskRefreshChapterImagesDescription": "Gumawa ng larawan para sa mga pelikula na may kabanata",
|
||||
"TaskRefreshChapterImages": "Kunin ang mga larawan ng kabanata",
|
||||
"TaskCleanCacheDescription": "Tanggalin ang mga cache file na hindi na kailangan ng systema.",
|
||||
"TasksChannelsCategory": "Palabas sa internet",
|
||||
"TasksLibraryCategory": "Librerya",
|
||||
"TasksMaintenanceCategory": "Pagpapanatili",
|
||||
"HomeVideos": "Sariling pelikula"
|
||||
}
|
||||
|
||||
61
Emby.Server.Implementations/Localization/Core/mr.json
Normal file
61
Emby.Server.Implementations/Localization/Core/mr.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"Books": "पुस्तकं",
|
||||
"Artists": "संगीतकार",
|
||||
"Albums": "अल्बम",
|
||||
"Playlists": "प्लेलिस्ट",
|
||||
"HeaderAlbumArtists": "अल्बम संगीतकार",
|
||||
"Folders": "फोल्डर",
|
||||
"HeaderFavoriteEpisodes": "आवडते भाग",
|
||||
"HeaderFavoriteSongs": "आवडती गाणी",
|
||||
"Movies": "चित्रपट",
|
||||
"HeaderFavoriteArtists": "आवडते संगीतकार",
|
||||
"Shows": "कार्यक्रम",
|
||||
"HeaderFavoriteAlbums": "आवडते अल्बम",
|
||||
"Channels": "वाहिन्या",
|
||||
"ValueSpecialEpisodeName": "विशेष - {0}",
|
||||
"HeaderFavoriteShows": "आवडते कार्यक्रम",
|
||||
"Favorites": "आवडीचे",
|
||||
"HeaderNextUp": "यानंतर",
|
||||
"Songs": "गाणी",
|
||||
"HeaderLiveTV": "लाइव्ह टीव्ही",
|
||||
"Genres": "जाँनरे",
|
||||
"Photos": "चित्र",
|
||||
"TaskDownloadMissingSubtitles": "नसलेले सबटायटल डाउनलोड करा",
|
||||
"TaskCleanTranscodeDescription": "एक दिवसापेक्षा जुन्या ट्रान्सकोड फायली काढून टाका.",
|
||||
"TaskCleanTranscode": "ट्रान्सकोड डिरेक्टरी साफ करून टाका",
|
||||
"TaskUpdatePlugins": "प्लगइन अपडेट करा",
|
||||
"TaskCleanLogs": "लॉग डिरेक्टरी साफ करून टाका",
|
||||
"TaskCleanCache": "कॅश डिरेक्टरी साफ करून टाका",
|
||||
"TasksChannelsCategory": "इंटरनेट वाहिन्या",
|
||||
"TasksApplicationCategory": "अॅप्लिकेशन",
|
||||
"TasksLibraryCategory": "संग्रहालय",
|
||||
"VersionNumber": "आवृत्ती {0}",
|
||||
"UserPasswordChangedWithName": "{0} या प्रयोक्त्याचे पासवर्ड बदलण्यात आले आहे",
|
||||
"UserOnlineFromDevice": "{0} हे {1} येथून ऑनलाइन आहेत",
|
||||
"UserDeletedWithName": "प्रयोक्ता {0} काढून टाकण्यात आले आहे",
|
||||
"UserCreatedWithName": "प्रयोक्ता {0} बनवण्यात आले आहे",
|
||||
"User": "प्रयोक्ता",
|
||||
"TvShows": "टीव्ही कार्यक्रम",
|
||||
"StartupEmbyServerIsLoading": "जेलिफिन सर्व्हर लोड होत आहे. कृपया थोड्या वेळात पुन्हा प्रयत्न करा.",
|
||||
"Plugin": "प्लगइन",
|
||||
"NotificationOptionCameraImageUploaded": "कॅमेरा चित्र अपलोड केले आहे",
|
||||
"NotificationOptionApplicationUpdateInstalled": "अॅप्लिकेशन अपडेट इन्स्टॉल केले आहे",
|
||||
"NotificationOptionApplicationUpdateAvailable": "अॅप्लिकेशन अपडेट उपलब्ध आहे",
|
||||
"NewVersionIsAvailable": "जेलिफिन सर्व्हरची एक नवीन आवृत्ती डाउनलोड करण्यास उपलब्ध आहे.",
|
||||
"NameSeasonUnknown": "अज्ञात सीझन",
|
||||
"NameSeasonNumber": "सीझन {0}",
|
||||
"MusicVideos": "संगीत व्हिडीयो",
|
||||
"Music": "संगीत",
|
||||
"MessageApplicationUpdatedTo": "जेलिफिन सर्व्हर अपडेट होऊन {0} आवृत्तीवर पोहोचला आहे",
|
||||
"MessageApplicationUpdated": "जेलिफिन सर्व्हर अपडेट केला गेला आहे",
|
||||
"Latest": "नवीनतम",
|
||||
"LabelIpAddressValue": "आयपी पत्ता: {0}",
|
||||
"ItemRemovedWithName": "{0} हे संग्रहालयातून काढून टाकण्यात आले",
|
||||
"ItemAddedWithName": "{0} हे संग्रहालयात जोडले गेले",
|
||||
"HomeVideos": "घरचे व्हिडीयो",
|
||||
"HeaderRecordingGroups": "रेकॉर्डिंग गट",
|
||||
"HeaderCameraUploads": "कॅमेरा अपलोड",
|
||||
"CameraImageUploadedFrom": "एक नवीन कॅमेरा चित्र {0} येथून अपलोड केले आहे",
|
||||
"Application": "अॅप्लिकेशन",
|
||||
"AppDeviceValues": "अॅप: {0}, यंत्र: {1}"
|
||||
}
|
||||
@@ -92,5 +92,27 @@
|
||||
"UserStoppedPlayingItemWithValues": "{0} heeft afspelen van {1} gestopt op {2}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} is toegevoegd aan je mediabibliotheek",
|
||||
"ValueSpecialEpisodeName": "Speciaal - {0}",
|
||||
"VersionNumber": "Versie {0}"
|
||||
"VersionNumber": "Versie {0}",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Zoekt op het internet naar missende ondertitels gebaseerd op metadata configuratie.",
|
||||
"TaskDownloadMissingSubtitles": "Download missende ondertitels",
|
||||
"TaskRefreshChannelsDescription": "Vernieuwt informatie van internet kanalen.",
|
||||
"TaskRefreshChannels": "Vernieuw Kanalen",
|
||||
"TaskCleanTranscodeDescription": "Verwijder transcode bestanden ouder dan 1 dag.",
|
||||
"TaskCleanLogs": "Log Folder Opschonen",
|
||||
"TaskCleanTranscode": "Transcode Folder Opschonen",
|
||||
"TaskUpdatePluginsDescription": "Download en installeert updates voor plugins waar automatisch updaten aan staat.",
|
||||
"TaskUpdatePlugins": "Update Plugins",
|
||||
"TaskRefreshPeopleDescription": "Update metadata for acteurs en regisseurs in de media bibliotheek.",
|
||||
"TaskRefreshPeople": "Vernieuw Personen",
|
||||
"TaskCleanLogsDescription": "Verwijdert log bestanden ouder dan {0} dagen.",
|
||||
"TaskRefreshLibraryDescription": "Scant de media bibliotheek voor nieuwe bestanden en vernieuwt de metadata.",
|
||||
"TaskRefreshLibrary": "Scan Media Bibliotheek",
|
||||
"TaskRefreshChapterImagesDescription": "Maakt thumbnails aan voor videos met hoofdstukken.",
|
||||
"TaskRefreshChapterImages": "Hoofdstukafbeeldingen Uitpakken",
|
||||
"TaskCleanCacheDescription": "Verwijder gecachte bestanden die het systeem niet langer nodig heeft.",
|
||||
"TaskCleanCache": "Cache Folder Opschonen",
|
||||
"TasksChannelsCategory": "Internet Kanalen",
|
||||
"TasksApplicationCategory": "Applicatie",
|
||||
"TasksLibraryCategory": "Bibliotheek",
|
||||
"TasksMaintenanceCategory": "Onderhoud"
|
||||
}
|
||||
|
||||
@@ -92,5 +92,26 @@
|
||||
"UserStoppedPlayingItemWithValues": "{0} har avslutat uppspelningen av {1} på {2}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} har lagts till i ditt mediebibliotek",
|
||||
"ValueSpecialEpisodeName": "Specialavsnitt - {0}",
|
||||
"VersionNumber": "Version {0}"
|
||||
"VersionNumber": "Version {0}",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Söker på internet efter saknade undertexter baserad på metadatas konfiguration.",
|
||||
"TaskDownloadMissingSubtitles": "Ladda ned saknade undertexter",
|
||||
"TaskRefreshChannelsDescription": "Uppdaterar information för internetkanaler.",
|
||||
"TaskRefreshChannels": "Uppdatera kanaler",
|
||||
"TaskCleanTranscodeDescription": "Raderar transkodningsfiler som är mer än en dag gamla.",
|
||||
"TaskCleanTranscode": "Töm transkodningskatalog",
|
||||
"TaskUpdatePluginsDescription": "Laddar ned och installerar uppdateringar till insticksprogram som är konfigurerade att uppdateras automatiskt.",
|
||||
"TaskUpdatePlugins": "Uppdatera insticksprogram",
|
||||
"TaskRefreshPeopleDescription": "Uppdaterar metadata för skådespelare och regissörer i ditt mediabibliotek.",
|
||||
"TaskCleanLogsDescription": "Raderar loggfiler som är mer än {0} dagar gamla.",
|
||||
"TaskCleanLogs": "Töm loggkatalog",
|
||||
"TaskRefreshLibraryDescription": "Söker igenom ditt mediabibliotek efter nya filer och förnyar metadata.",
|
||||
"TaskRefreshLibrary": "Genomsök mediabibliotek",
|
||||
"TaskRefreshChapterImagesDescription": "Skapa miniatyrbilder för videor med kapitel.",
|
||||
"TaskRefreshChapterImages": "Extrahera kapitelbilder",
|
||||
"TaskCleanCacheDescription": "Radera cachade filer som systemet inte längre behöver.",
|
||||
"TaskCleanCache": "Rensa cachekatalog",
|
||||
"TasksChannelsCategory": "Internetkanaler",
|
||||
"TasksApplicationCategory": "Applikation",
|
||||
"TasksLibraryCategory": "Bibliotek",
|
||||
"TasksMaintenanceCategory": "Underhåll"
|
||||
}
|
||||
|
||||
@@ -92,5 +92,10 @@
|
||||
"UserStoppedPlayingItemWithValues": "{0}, {2} cihazında {1} izlemeyi bitirdi",
|
||||
"ValueHasBeenAddedToLibrary": "Medya kitaplığınıza {0} eklendi",
|
||||
"ValueSpecialEpisodeName": "Özel - {0}",
|
||||
"VersionNumber": "Versiyon {0}"
|
||||
"VersionNumber": "Versiyon {0}",
|
||||
"TaskCleanCache": "Geçici dosya klasörünü temizle",
|
||||
"TasksChannelsCategory": "İnternet kanalları",
|
||||
"TasksApplicationCategory": "Yazılım",
|
||||
"TasksLibraryCategory": "Kütüphane",
|
||||
"TasksMaintenanceCategory": "Onarım"
|
||||
}
|
||||
|
||||
1
Emby.Server.Implementations/Localization/Core/ur_PK.json
Normal file
1
Emby.Server.Implementations/Localization/Core/ur_PK.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -55,9 +55,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
||||
{
|
||||
progress.Report(0);
|
||||
|
||||
var packagesToInstall = await _installationManager.GetAvailablePluginUpdates(cancellationToken)
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var packageFetchTask = _installationManager.GetAvailablePluginUpdates(cancellationToken);
|
||||
var packagesToInstall = (await packageFetchTask.ConfigureAwait(false)).ToList();
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -18,6 +20,7 @@ using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Updates;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.Updates
|
||||
@@ -27,6 +30,11 @@ namespace Emby.Server.Implementations.Updates
|
||||
/// </summary>
|
||||
public class InstallationManager : IInstallationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// The key for a setting that specifies a URL for the plugin repository JSON manifest.
|
||||
/// </summary>
|
||||
public const string PluginManifestUrlKey = "InstallationManager:PluginManifestUrl";
|
||||
|
||||
/// <summary>
|
||||
/// The _logger.
|
||||
/// </summary>
|
||||
@@ -44,6 +52,7 @@ namespace Emby.Server.Implementations.Updates
|
||||
private readonly IApplicationHost _applicationHost;
|
||||
|
||||
private readonly IZipClient _zipClient;
|
||||
private readonly IConfiguration _appConfig;
|
||||
|
||||
private readonly object _currentInstallationsLock = new object();
|
||||
|
||||
@@ -65,7 +74,8 @@ namespace Emby.Server.Implementations.Updates
|
||||
IJsonSerializer jsonSerializer,
|
||||
IServerConfigurationManager config,
|
||||
IFileSystem fileSystem,
|
||||
IZipClient zipClient)
|
||||
IZipClient zipClient,
|
||||
IConfiguration appConfig)
|
||||
{
|
||||
if (logger == null)
|
||||
{
|
||||
@@ -83,6 +93,7 @@ namespace Emby.Server.Implementations.Updates
|
||||
_config = config;
|
||||
_fileSystem = fileSystem;
|
||||
_zipClient = zipClient;
|
||||
_appConfig = appConfig;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -112,19 +123,43 @@ namespace Emby.Server.Implementations.Updates
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (var response = await _httpClient.SendAsync(
|
||||
new HttpRequestOptions
|
||||
{
|
||||
Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
|
||||
CancellationToken = cancellationToken,
|
||||
CacheMode = CacheMode.Unconditional,
|
||||
CacheLength = TimeSpan.FromMinutes(3)
|
||||
},
|
||||
HttpMethod.Get).ConfigureAwait(false))
|
||||
using (Stream stream = response.Content)
|
||||
var manifestUrl = _appConfig.GetValue<string>(PluginManifestUrlKey);
|
||||
|
||||
try
|
||||
{
|
||||
return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>(
|
||||
stream).ConfigureAwait(false);
|
||||
using (var response = await _httpClient.SendAsync(
|
||||
new HttpRequestOptions
|
||||
{
|
||||
Url = manifestUrl,
|
||||
CancellationToken = cancellationToken,
|
||||
CacheMode = CacheMode.Unconditional,
|
||||
CacheLength = TimeSpan.FromMinutes(3)
|
||||
},
|
||||
HttpMethod.Get).ConfigureAwait(false))
|
||||
using (Stream stream = response.Content)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>(stream).ConfigureAwait(false);
|
||||
}
|
||||
catch (SerializationException ex)
|
||||
{
|
||||
const string LogTemplate =
|
||||
"Failed to deserialize the plugin manifest retrieved from {PluginManifestUrl}. If you " +
|
||||
"have specified a custom plugin repository manifest URL with --plugin-manifest-url or " +
|
||||
PluginManifestUrlKey + ", please ensure that it is correct.";
|
||||
_logger.LogError(ex, LogTemplate, manifestUrl);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (UriFormatException ex)
|
||||
{
|
||||
const string LogTemplate =
|
||||
"The URL configured for the plugin repository manifest URL is not valid: {PluginManifestUrl}. " +
|
||||
"Please check the URL configured by --plugin-manifest-url or " + PluginManifestUrlKey;
|
||||
_logger.LogError(ex, LogTemplate, manifestUrl);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,16 +224,17 @@ namespace Emby.Server.Implementations.Updates
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async IAsyncEnumerable<PackageVersionInfo> GetAvailablePluginUpdates([EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
|
||||
return GetAvailablePluginUpdates(catalog);
|
||||
}
|
||||
|
||||
var systemUpdateLevel = _applicationHost.SystemUpdateLevel;
|
||||
|
||||
// Figure out what needs to be installed
|
||||
private IEnumerable<PackageVersionInfo> GetAvailablePluginUpdates(IReadOnlyList<PackageInfo> pluginCatalog)
|
||||
{
|
||||
foreach (var plugin in _applicationHost.Plugins)
|
||||
{
|
||||
var compatibleversions = GetCompatibleVersions(catalog, plugin.Name, plugin.Id, plugin.Version, systemUpdateLevel);
|
||||
var compatibleversions = GetCompatibleVersions(pluginCatalog, plugin.Name, plugin.Id, plugin.Version, _applicationHost.SystemUpdateLevel);
|
||||
var version = compatibleversions.FirstOrDefault(y => y.Version > plugin.Version);
|
||||
if (version != null
|
||||
&& !CompletedInstallations.Any(x => string.Equals(x.AssemblyGuid, version.guid, StringComparison.OrdinalIgnoreCase)))
|
||||
|
||||
Reference in New Issue
Block a user