diff options
| author | Nyanmisaka <nst799610810@gmail.com> | 2020-04-10 22:09:48 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-10 22:09:48 +0800 |
| commit | 79e3de15681cc243a42a587d00f1c75c184540e9 (patch) | |
| tree | b71b307057aef887401932259f0ee875f5aa6746 /Emby.Server.Implementations | |
| parent | 645363810370504361cecd5ce4c529343ed28833 (diff) | |
| parent | ec2e9d52badbce6d0c46abd2a14b77f215cfb4b0 (diff) | |
Merge pull request #3 from jellyfin/master
Diffstat (limited to 'Emby.Server.Implementations')
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))) |
