소스 검색

Removed SimilarityScore and ported Search function

JPVenson 8 달 전
부모
커밋
90103165e2
2개의 변경된 파일103개의 추가작업 그리고 156개의 파일을 삭제
  1. 2 2
      Jellyfin.Data/Entities/BaseItem.cs
  2. 101 154
      Jellyfin.Server.Implementations/Item/BaseItemManager.cs

+ 2 - 2
Jellyfin.Data/Entities/BaseItem.cs

@@ -14,7 +14,7 @@ public class BaseItem
 
     public required string Type { get; set; }
 
-    public IReadOnlyList<byte>? Data { get; set; }
+    public string? Data { get; set; }
 
     public Guid? ParentId { get; set; }
 
@@ -94,7 +94,7 @@ public class BaseItem
 
     public string? UnratedType { get; set; }
 
-    public string? TopParentId { get; set; }
+    public Guid? TopParentId { get; set; }
 
     public string? TrailerTypes { get; set; }
 

+ 101 - 154
Jellyfin.Server.Implementations/Item/BaseItemManager.cs

@@ -22,6 +22,7 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.Querying;
 using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
 using BaseItemDto = MediaBrowser.Controller.Entities.BaseItem;
 using BaseItemEntity = Jellyfin.Data.Entities.BaseItem;
 
@@ -281,16 +282,9 @@ public class BaseItemManager : IItemRepository
             }
         }
 
-        if (query.SimilarTo is not null && query.MinSimilarityScore > 0)
-        {
-            // TODO support similarty score via CTE
-            baseQuery = baseQuery.Where(e => e.Sim == query.IsSeries);
-            whereClauses.Add("SimilarityScore > " + (query.MinSimilarityScore - 1).ToString(CultureInfo.InvariantCulture));
-        }
-
         if (!string.IsNullOrEmpty(query.SearchTerm))
         {
-            whereClauses.Add("SearchScore > 0");
+            baseQuery = baseQuery.Where(e => e.CleanName!.Contains(query.SearchTerm, StringComparison.InvariantCultureIgnoreCase) || (e.OriginalTitle != null && e.OriginalTitle.Contains(query.SearchTerm, StringComparison.InvariantCultureIgnoreCase)));
         }
 
         if (query.IsFolder.HasValue)
@@ -917,44 +911,13 @@ public class BaseItemManager : IItemRepository
         {
             var includedItemByNameTypes = GetItemByNameTypesInQuery(query);
             var enableItemsByName = (query.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
-
-            if (queryTopParentIds.Length == 1)
+            if (enableItemsByName && includedItemByNameTypes.Count > 0)
             {
-                if (enableItemsByName && includedItemByNameTypes.Count == 1)
-                {
-                    whereClauses.Add("(TopParentId=@TopParentId or Type=@IncludedItemByNameType)");
-                    statement?.TryBind("@IncludedItemByNameType", includedItemByNameTypes[0]);
-                }
-                else if (enableItemsByName && includedItemByNameTypes.Count > 1)
-                {
-                    var itemByNameTypeVal = string.Join(',', includedItemByNameTypes.Select(i => "'" + i + "'"));
-                    whereClauses.Add("(TopParentId=@TopParentId or Type in (" + itemByNameTypeVal + "))");
-                }
-                else
-                {
-                    whereClauses.Add("(TopParentId=@TopParentId)");
-                }
-
-                statement?.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture));
+                baseQuery = baseQuery.Where(e => includedItemByNameTypes.Contains(e.Type) || queryTopParentIds.Any(w => w.Equals(e.TopParentId!.Value)));
             }
-            else if (queryTopParentIds.Length > 1)
+            else
             {
-                var val = string.Join(',', queryTopParentIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
-
-                if (enableItemsByName && includedItemByNameTypes.Count == 1)
-                {
-                    whereClauses.Add("(Type=@IncludedItemByNameType or TopParentId in (" + val + "))");
-                    statement?.TryBind("@IncludedItemByNameType", includedItemByNameTypes[0]);
-                }
-                else if (enableItemsByName && includedItemByNameTypes.Count > 1)
-                {
-                    var itemByNameTypeVal = string.Join(',', includedItemByNameTypes.Select(i => "'" + i + "'"));
-                    whereClauses.Add("(Type in (" + itemByNameTypeVal + ") or TopParentId in (" + val + "))");
-                }
-                else
-                {
-                    whereClauses.Add("TopParentId in (" + val + ")");
-                }
+                baseQuery = baseQuery.Where(e => queryTopParentIds.Any(w => w.Equals(e.TopParentId!.Value)));
             }
         }
 
@@ -965,124 +928,83 @@ public class BaseItemManager : IItemRepository
 
         if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey))
         {
-            var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey";
-            whereClauses.Add(string.Format(CultureInfo.InvariantCulture, "Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause));
-            statement?.TryBind("@AncestorWithPresentationUniqueKey", query.AncestorWithPresentationUniqueKey);
+            baseQuery = baseQuery
+                .Where(e => context.BaseItems.Where(f => f.PresentationUniqueKey == query.AncestorWithPresentationUniqueKey).Any(f => f.AncestorIds!.Any(w => w.ItemId.Equals(f.Id))));
         }
 
         if (!string.IsNullOrWhiteSpace(query.SeriesPresentationUniqueKey))
         {
-            whereClauses.Add("SeriesPresentationUniqueKey=@SeriesPresentationUniqueKey");
-            statement?.TryBind("@SeriesPresentationUniqueKey", query.SeriesPresentationUniqueKey);
+            baseQuery = baseQuery
+                .Where(e => e.SeriesPresentationUniqueKey == query.SeriesPresentationUniqueKey);
         }
 
         if (query.ExcludeInheritedTags.Length > 0)
         {
-            var paramName = "@ExcludeInheritedTags";
-            if (statement is null)
-            {
-                int index = 0;
-                string excludedTags = string.Join(',', query.ExcludeInheritedTags.Select(_ => paramName + index++));
-                whereClauses.Add("((select CleanValue from ItemValues where ItemId=Guid and Type=6 and cleanvalue in (" + excludedTags + ")) is null)");
-            }
-            else
-            {
-                for (int index = 0; index < query.ExcludeInheritedTags.Length; index++)
-                {
-                    statement.TryBind(paramName + index, GetCleanValue(query.ExcludeInheritedTags[index]));
-                }
-            }
+            baseQuery = baseQuery
+                .Where(e => !e.ItemValues!.Where(e => e.Type == 6)
+                    .Any(f => query.ExcludeInheritedTags.Contains(f.CleanValue)));
         }
 
         if (query.IncludeInheritedTags.Length > 0)
         {
-            var paramName = "@IncludeInheritedTags";
-            if (statement is null)
+            // Episodes do not store inherit tags from their parents in the database, and the tag may be still required by the client.
+            // In addtion to the tags for the episodes themselves, we need to manually query its parent (the season)'s tags as well.
+            if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Episode)
             {
-                int index = 0;
-                string includedTags = string.Join(',', query.IncludeInheritedTags.Select(_ => paramName + index++));
-                // Episodes do not store inherit tags from their parents in the database, and the tag may be still required by the client.
-                // In addtion to the tags for the episodes themselves, we need to manually query its parent (the season)'s tags as well.
-                if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Episode)
-                {
-                    whereClauses.Add($"""
-                                          ((select CleanValue from ItemValues where ItemId=Guid and Type=6 and CleanValue in ({includedTags})) is not null
-                                          OR (select CleanValue from ItemValues where ItemId=ParentId and Type=6 and CleanValue in ({includedTags})) is not null)
-                                          """);
-                }
+                baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Where(e => e.Type == 6)
+                        .Any(f => query.IncludeInheritedTags.Contains(f.CleanValue))
+                        ||
+                        (e.ParentId.HasValue && context.ItemValues.Where(w => w.ItemId.Equals(e.ParentId.Value))!.Where(e => e.Type == 6)
+                        .Any(f => query.IncludeInheritedTags.Contains(f.CleanValue))));
+            }
 
-                // A playlist should be accessible to its owner regardless of allowed tags.
-                else if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Playlist)
-                {
-                    whereClauses.Add($"""
-                                          ((select CleanValue from ItemValues where ItemId=Guid and Type=6 and CleanValue in ({includedTags})) is not null
-                                          OR data like @PlaylistOwnerUserId)
-                                          """);
-                }
-                else
-                {
-                    whereClauses.Add("((select CleanValue from ItemValues where ItemId=Guid and Type=6 and cleanvalue in (" + includedTags + ")) is not null)");
-                }
+            // A playlist should be accessible to its owner regardless of allowed tags.
+            else if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Playlist)
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Where(e => e.Type == 6)
+                        .Any(f => query.IncludeInheritedTags.Contains(f.CleanValue)) || e.Data!.Contains($"OwnerUserId\":\"{query.User!.Id:N}\""));
+                // d                                                                      ^^ this is stupid it hate this.
             }
             else
             {
-                for (int index = 0; index < query.IncludeInheritedTags.Length; index++)
-                {
-                    statement.TryBind(paramName + index, GetCleanValue(query.IncludeInheritedTags[index]));
-                }
-
-                if (query.User is not null)
-                {
-                    statement.TryBind("@PlaylistOwnerUserId", $"""%"OwnerUserId":"{query.User.Id.ToString("N")}"%""");
-                }
+                baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Where(e => e.Type == 6)
+                        .Any(f => query.IncludeInheritedTags.Contains(f.CleanValue)));
             }
         }
 
         if (query.SeriesStatuses.Length > 0)
         {
-            var statuses = new List<string>();
-
-            foreach (var seriesStatus in query.SeriesStatuses)
-            {
-                statuses.Add("data like  '%" + seriesStatus + "%'");
-            }
-
-            whereClauses.Add("(" + string.Join(" OR ", statuses) + ")");
+            baseQuery = baseQuery
+                .Where(e => query.SeriesStatuses.Any(f => e.Data!.Contains(f.ToString(), StringComparison.InvariantCultureIgnoreCase)));
         }
 
         if (query.BoxSetLibraryFolders.Length > 0)
         {
-            var folderIdQueries = new List<string>();
-
-            foreach (var folderId in query.BoxSetLibraryFolders)
-            {
-                folderIdQueries.Add("data like '%" + folderId.ToString("N", CultureInfo.InvariantCulture) + "%'");
-            }
-
-            whereClauses.Add("(" + string.Join(" OR ", folderIdQueries) + ")");
+            baseQuery = baseQuery
+                .Where(e => query.BoxSetLibraryFolders.Any(f => e.Data!.Contains(f.ToString("N", CultureInfo.InvariantCulture), StringComparison.InvariantCultureIgnoreCase)));
         }
 
         if (query.VideoTypes.Length > 0)
         {
-            var videoTypes = new List<string>();
-
-            foreach (var videoType in query.VideoTypes)
-            {
-                videoTypes.Add("data like '%\"VideoType\":\"" + videoType + "\"%'");
-            }
-
-            whereClauses.Add("(" + string.Join(" OR ", videoTypes) + ")");
+            var videoTypeBs = query.VideoTypes.Select(e => $"\"VideoType\":\"" + e + "\"");
+            baseQuery = baseQuery
+                .Where(e => videoTypeBs.Any(f => e.Data!.Contains(f, StringComparison.InvariantCultureIgnoreCase)));
         }
 
         if (query.Is3D.HasValue)
         {
             if (query.Is3D.Value)
             {
-                whereClauses.Add("data like '%Video3DFormat%'");
+                baseQuery = baseQuery
+                    .Where(e => e.Data!.Contains("Video3DFormat", StringComparison.InvariantCultureIgnoreCase));
             }
             else
             {
-                whereClauses.Add("data not like '%Video3DFormat%'");
+                baseQuery = baseQuery
+                    .Where(e => !e.Data!.Contains("Video3DFormat", StringComparison.InvariantCultureIgnoreCase));
             }
         }
 
@@ -1090,11 +1012,13 @@ public class BaseItemManager : IItemRepository
         {
             if (query.IsPlaceHolder.Value)
             {
-                whereClauses.Add("data like '%\"IsPlaceHolder\":true%'");
+                baseQuery = baseQuery
+                    .Where(e => e.Data!.Contains("IsPlaceHolder\":true", StringComparison.InvariantCultureIgnoreCase));
             }
             else
             {
-                whereClauses.Add("(data is null or data not like '%\"IsPlaceHolder\":true%')");
+                baseQuery = baseQuery
+                    .Where(e => !e.Data!.Contains("IsPlaceHolder\":true", StringComparison.InvariantCultureIgnoreCase));
             }
         }
 
@@ -1102,47 +1026,27 @@ public class BaseItemManager : IItemRepository
         {
             if (query.HasSpecialFeature.Value)
             {
-                whereClauses.Add("ExtraIds not null");
-            }
-            else
-            {
-                whereClauses.Add("ExtraIds is null");
-            }
-        }
-
-        if (query.HasTrailer.HasValue)
-        {
-            if (query.HasTrailer.Value)
-            {
-                whereClauses.Add("ExtraIds not null");
-            }
-            else
-            {
-                whereClauses.Add("ExtraIds is null");
-            }
-        }
-
-        if (query.HasThemeSong.HasValue)
-        {
-            if (query.HasThemeSong.Value)
-            {
-                whereClauses.Add("ExtraIds not null");
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds != null);
             }
             else
             {
-                whereClauses.Add("ExtraIds is null");
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds == null);
             }
         }
 
-        if (query.HasThemeVideo.HasValue)
+        if (query.HasTrailer.HasValue || query.HasThemeSong.HasValue || query.HasThemeVideo.HasValue)
         {
-            if (query.HasThemeVideo.Value)
+            if (query.HasTrailer.GetValueOrDefault() || query.HasThemeSong.GetValueOrDefault() || query.HasThemeVideo.GetValueOrDefault())
             {
-                whereClauses.Add("ExtraIds not null");
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds != null);
             }
             else
             {
-                whereClauses.Add("ExtraIds is null");
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds == null);
             }
         }
     }
@@ -1867,4 +1771,47 @@ public class BaseItemManager : IItemRepository
 
         return image;
     }
+
+    private List<string> GetItemByNameTypesInQuery(InternalItemsQuery query)
+    {
+        var list = new List<string>();
+
+        if (IsTypeInQuery(BaseItemKind.Person, query))
+        {
+            list.Add(typeof(Person).FullName!);
+        }
+
+        if (IsTypeInQuery(BaseItemKind.Genre, query))
+        {
+            list.Add(typeof(Genre).FullName!);
+        }
+
+        if (IsTypeInQuery(BaseItemKind.MusicGenre, query))
+        {
+            list.Add(typeof(MusicGenre).FullName!);
+        }
+
+        if (IsTypeInQuery(BaseItemKind.MusicArtist, query))
+        {
+            list.Add(typeof(MusicArtist).FullName!);
+        }
+
+        if (IsTypeInQuery(BaseItemKind.Studio, query))
+        {
+            list.Add(typeof(Studio).FullName!);
+        }
+
+        return list;
+    }
+
+    private bool IsTypeInQuery(BaseItemKind type, InternalItemsQuery query)
+    {
+        if (query.ExcludeItemTypes.Contains(type))
+        {
+            return false;
+        }
+
+        return query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(type);
+    }
+
 }