aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
authorNyanmisaka <nst799610810@gmail.com>2020-04-10 22:09:48 +0800
committerGitHub <noreply@github.com>2020-04-10 22:09:48 +0800
commit79e3de15681cc243a42a587d00f1c75c184540e9 (patch)
treeb71b307057aef887401932259f0ee875f5aa6746 /Emby.Server.Implementations
parent645363810370504361cecd5ce4c529343ed28833 (diff)
parentec2e9d52badbce6d0c46abd2a14b77f215cfb4b0 (diff)
Merge pull request #3 from jellyfin/master
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/ConfigurationOptions.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteExtensions.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs402
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs19
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj3
-rw-r--r--Emby.Server.Implementations/IStartupOptions.cs17
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs8
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json14
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json16
-rw-r--r--Emby.Server.Implementations/Localization/Core/fil.json10
-rw-r--r--Emby.Server.Implementations/Localization/Core/mr.json1
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json24
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json23
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs5
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs70
15 files changed, 296 insertions, 320 deletions
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index 4574a64fd..20bdd18e7 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -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 }
diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs
index c87793072..e7c5270b9 100644
--- a/Emby.Server.Implementations/Data/SqliteExtensions.cs
+++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs
@@ -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))
{
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 46c6d5520..33ff74bb5 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -3315,7 +3315,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;
}
@@ -3339,7 +3339,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)
{
@@ -3351,27 +3351,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;
}
}
@@ -3380,93 +3380,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))
- {
- alternateTypes.Add(typeof(Movie).FullName);
- }
- if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
+ if (query.IncludeItemTypes.Length == 0
+ || query.IncludeItemTypes.Contains(nameof(Movie))
+ || query.IncludeItemTypes.Contains(nameof(Trailer)))
{
- 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)
@@ -3518,10 +3486,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();
@@ -3532,10 +3497,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)
{
@@ -3546,10 +3508,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)
{
@@ -3560,10 +3519,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)
{
@@ -3574,98 +3530,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;
@@ -3686,73 +3609,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)
@@ -3760,24 +3669,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);
}
}
@@ -3792,13 +3692,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);
}
@@ -3806,47 +3703,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
@@ -3865,28 +3746,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)
@@ -3902,18 +3776,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);
}
}
@@ -3927,10 +3795,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)
@@ -3943,10 +3809,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))
@@ -3975,10 +3839,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);
}
}
}
@@ -4010,6 +3872,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4029,6 +3892,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4762,18 +4626,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);
@@ -4847,7 +4715,7 @@ namespace Emby.Server.Implementations.Data
return false;
}
- private static readonly Type[] KnownTypes =
+ private static readonly Type[] _knownTypes =
{
typeof(LiveTvProgram),
typeof(LiveTvChannel),
@@ -4916,7 +4784,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 };
}
@@ -4928,7 +4796,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)
{
@@ -4945,7 +4813,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)
{
@@ -4981,7 +4849,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))
{
@@ -5541,6 +5409,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);
@@ -5582,7 +5451,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)
{
@@ -5673,30 +5542,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);
@@ -5724,7 +5589,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.MoveNext();
}
- startIndex += limit;
+ startIndex += Limit;
}
}
@@ -5759,28 +5624,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);
@@ -5804,16 +5664,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))
{
@@ -5920,20 +5781,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);
@@ -5941,11 +5810,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()))
@@ -6007,7 +5877,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.MoveNext();
}
- startIndex += limit;
+ startIndex += Limit;
}
}
@@ -6024,7 +5894,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)
{
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 65711e89d..34a342cf7 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1056,30 +1056,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
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index ef6e37c8e..d46b9507b 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -35,9 +35,8 @@
<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>
diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs
index 6e915de3d..16b68170b 100644
--- a/Emby.Server.Implementations/IStartupOptions.cs
+++ b/Emby.Server.Implementations/IStartupOptions.cs
@@ -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; }
}
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 8ec4d08be..4e2cf334c 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -437,10 +437,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);
@@ -2609,14 +2609,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();
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index 2fe232e79..f313039a6 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -102,5 +102,17 @@
"TaskRefreshLibrary": "افحص مكتبة الوسائط",
"TaskRefreshChapterImagesDescription": "إنشاء صور مصغرة لمقاطع الفيديو ذات فصول.",
"TaskRefreshChapterImages": "استخراج صور الفصل",
- "TasksApplicationCategory": "تطبيق"
+ "TasksApplicationCategory": "تطبيق",
+ "TaskDownloadMissingSubtitlesDescription": "ابحث في الإنترنت على الترجمات المفقودة إستنادا على الميتاداتا.",
+ "TaskDownloadMissingSubtitles": "تحميل الترجمات المفقودة",
+ "TaskRefreshChannelsDescription": "تحديث معلومات قنوات الإنترنت.",
+ "TaskRefreshChannels": "إعادة تحديث القنوات",
+ "TaskCleanTranscodeDescription": "حذف ملفات الترميز الأقدم من يوم واحد.",
+ "TaskCleanTranscode": "حذف سجلات الترميز",
+ "TaskUpdatePluginsDescription": "تحميل وتثبيت الإضافات التي تم تفعيل التحديث التلقائي لها.",
+ "TaskUpdatePlugins": "تحديث الإضافات",
+ "TaskRefreshPeopleDescription": "تحديث البيانات الوصفية للممثلين والمخرجين في مكتبة الوسائط الخاصة بك.",
+ "TaskRefreshPeople": "إعادة تحميل الأشخاص",
+ "TaskCleanLogsDescription": "حذف السجلات الأقدم من {0} يوم.",
+ "TaskCleanLogs": "حذف دليل السجل"
}
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index 94437d237..92719a9fd 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -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"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fil.json b/Emby.Server.Implementations/Localization/Core/fil.json
index 86a6d1836..47daf2044 100644
--- a/Emby.Server.Implementations/Localization/Core/fil.json
+++ b/Emby.Server.Implementations/Localization/Core/fil.json
@@ -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"
}
diff --git a/Emby.Server.Implementations/Localization/Core/mr.json b/Emby.Server.Implementations/Localization/Core/mr.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/mr.json
@@ -0,0 +1 @@
+{}
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index bc36cbdd3..3bc9c2a77 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -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"
}
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index 96891f994..b7c50394a 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -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"
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
index 588944d0e..6a1afced7 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
@@ -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);
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index c897036eb..25f70471a 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -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
@@ -28,6 +31,11 @@ namespace Emby.Server.Implementations.Updates
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>
private readonly ILogger _logger;
@@ -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
+ var manifestUrl = _appConfig.GetValue<string>(PluginManifestUrlKey);
+
+ try
+ {
+ 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)
{
- 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)
+ 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)
{
- return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>(
- stream).ConfigureAwait(false);
+ 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)))