Browse Source

Fixed NextUp and Latest query performance

JPVenson 6 months ago
parent
commit
060aa4719e
1 changed files with 1254 additions and 1237 deletions
  1. 1254 1237
      Jellyfin.Server.Implementations/Item/BaseItemRepository.cs

+ 1254 - 1237
Jellyfin.Server.Implementations/Item/BaseItemRepository.cs

@@ -227,7 +227,7 @@ public sealed class BaseItemRepository(
         IQueryable<BaseItemEntity> dbQuery = PrepareItemQuery(context, filter);
 
         dbQuery = TranslateQuery(dbQuery, context, filter);
-        dbQuery = dbQuery.Distinct();
+        // dbQuery = dbQuery.Distinct();
         dbQuery = ApplyOrder(dbQuery, filter);
         dbQuery = ApplyGroupingFilter(dbQuery, filter);
 
@@ -315,1812 +315,1829 @@ public sealed class BaseItemRepository(
     }
 
 #pragma warning disable CA1307 // Specify StringComparison for clarity
-    private IQueryable<BaseItemEntity> TranslateQuery(
-        IQueryable<BaseItemEntity> baseQuery,
-        JellyfinDbContext context,
-        InternalItemsQuery filter)
+    /// <summary>
+    /// Gets the type.
+    /// </summary>
+    /// <param name="typeName">Name of the type.</param>
+    /// <returns>Type.</returns>
+    /// <exception cref="ArgumentNullException"><c>typeName</c> is null.</exception>
+    private static Type? GetType(string typeName)
     {
-        var minWidth = filter.MinWidth;
-        var maxWidth = filter.MaxWidth;
-        var now = DateTime.UtcNow;
-
-        if (filter.IsHD.HasValue)
-        {
-            const int Threshold = 1200;
-            if (filter.IsHD.Value)
-            {
-                minWidth = Threshold;
-            }
-            else
-            {
-                maxWidth = Threshold - 1;
-            }
-        }
+        ArgumentException.ThrowIfNullOrEmpty(typeName);
 
-        if (filter.Is4K.HasValue)
-        {
-            const int Threshold = 3800;
-            if (filter.Is4K.Value)
-            {
-                minWidth = Threshold;
-            }
-            else
-            {
-                maxWidth = Threshold - 1;
-            }
-        }
+        return _typeMap.GetOrAdd(typeName, k => AppDomain.CurrentDomain.GetAssemblies()
+            .Select(a => a.GetType(k))
+            .FirstOrDefault(t => t is not null));
+    }
 
-        if (minWidth.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.Width >= minWidth);
-        }
+    /// <inheritdoc cref="IItemRepository" />
+    public void SaveImages(BaseItemDto item)
+    {
+        ArgumentNullException.ThrowIfNull(item);
 
-        if (filter.MinHeight.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.Height >= filter.MinHeight);
-        }
+        var images = item.ImageInfos.Select(e => Map(item.Id, e));
+        using var context = dbProvider.CreateDbContext();
+        using var transaction = context.Database.BeginTransaction();
+        context.BaseItemImageInfos.Where(e => e.ItemId == item.Id).ExecuteDelete();
+        context.BaseItemImageInfos.AddRange(images);
+        context.SaveChanges();
+        transaction.Commit();
+    }
 
-        if (maxWidth.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.Width >= maxWidth);
-        }
+    /// <inheritdoc cref="IItemRepository" />
+    public void SaveItems(IReadOnlyList<BaseItemDto> items, CancellationToken cancellationToken)
+    {
+        UpdateOrInsertItems(items, cancellationToken);
+    }
 
-        if (filter.MaxHeight.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.Height <= filter.MaxHeight);
-        }
+    /// <inheritdoc cref="IItemRepository" />
+    public void UpdateOrInsertItems(IReadOnlyList<BaseItemDto> items, CancellationToken cancellationToken)
+    {
+        ArgumentNullException.ThrowIfNull(items);
+        cancellationToken.ThrowIfCancellationRequested();
 
-        if (filter.IsLocked.HasValue)
+        var itemsLen = items.Count;
+        var tuples = new (BaseItemDto Item, List<Guid>? AncestorIds, BaseItemDto TopParent, IEnumerable<string> UserDataKey, List<string> InheritedTags)[itemsLen];
+        for (int i = 0; i < itemsLen; i++)
         {
-            baseQuery = baseQuery.Where(e => e.IsLocked == filter.IsLocked);
-        }
-
-        var tags = filter.Tags.ToList();
-        var excludeTags = filter.ExcludeTags.ToList();
+            var item = items[i];
+            var ancestorIds = item.SupportsAncestors ?
+                item.GetAncestorIds().Distinct().ToList() :
+                null;
 
-        if (filter.IsMovie == true)
-        {
-            if (filter.IncludeItemTypes.Length == 0
-                || filter.IncludeItemTypes.Contains(BaseItemKind.Movie)
-                || filter.IncludeItemTypes.Contains(BaseItemKind.Trailer))
-            {
-                baseQuery = baseQuery.Where(e => e.IsMovie);
-            }
-        }
-        else if (filter.IsMovie.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.IsMovie == filter.IsMovie);
-        }
+            var topParent = item.GetTopParent();
 
-        if (filter.IsSeries.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.IsSeries == filter.IsSeries);
-        }
+            var userdataKey = item.GetUserDataKeys();
+            var inheritedTags = item.GetInheritedTags();
 
-        if (filter.IsSports.HasValue)
-        {
-            if (filter.IsSports.Value)
-            {
-                tags.Add("Sports");
-            }
-            else
-            {
-                excludeTags.Add("Sports");
-            }
+            tuples[i] = (item, ancestorIds, topParent, userdataKey, inheritedTags);
         }
 
-        if (filter.IsNews.HasValue)
+        using var context = dbProvider.CreateDbContext();
+        using var transaction = context.Database.BeginTransaction();
+        foreach (var item in tuples)
         {
-            if (filter.IsNews.Value)
-            {
-                tags.Add("News");
-            }
-            else
-            {
-                excludeTags.Add("News");
-            }
-        }
+            var entity = Map(item.Item);
+            // TODO: refactor this "inconsistency"
+            entity.TopParentId = item.TopParent?.Id;
 
-        if (filter.IsKids.HasValue)
-        {
-            if (filter.IsKids.Value)
+            if (!context.BaseItems.Any(e => e.Id == entity.Id))
             {
-                tags.Add("Kids");
+                context.BaseItems.Add(entity);
             }
             else
             {
-                excludeTags.Add("Kids");
+                context.BaseItemProviders.Where(e => e.ItemId == entity.Id).ExecuteDelete();
+                context.BaseItems.Attach(entity).State = EntityState.Modified;
             }
-        }
-
-        if (!string.IsNullOrEmpty(filter.SearchTerm))
-        {
-            baseQuery = baseQuery.Where(e => e.CleanName!.Contains(filter.SearchTerm) || (e.OriginalTitle != null && e.OriginalTitle.Contains(filter.SearchTerm)));
-        }
-
-        if (filter.IsFolder.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.IsFolder == filter.IsFolder);
-        }
 
-        var includeTypes = filter.IncludeItemTypes;
-        // Only specify excluded types if no included types are specified
-        if (filter.IncludeItemTypes.Length == 0)
-        {
-            var excludeTypes = filter.ExcludeItemTypes;
-            if (excludeTypes.Length == 1)
+            context.AncestorIds.Where(e => e.ItemId == entity.Id).ExecuteDelete();
+            if (item.Item.SupportsAncestors && item.AncestorIds != null)
             {
-                if (itemTypeLookup.BaseItemKindNames.TryGetValue(excludeTypes[0], out var excludeTypeName))
+                foreach (var ancestorId in item.AncestorIds)
                 {
-                    baseQuery = baseQuery.Where(e => e.Type != excludeTypeName);
+                    if (!context.BaseItems.Any(f => f.Id == ancestorId))
+                    {
+                        continue;
+                    }
+
+                    context.AncestorIds.Add(new AncestorId()
+                    {
+                        ParentItemId = ancestorId,
+                        ItemId = entity.Id,
+                        Item = null!,
+                        ParentItem = null!
+                    });
                 }
             }
-            else if (excludeTypes.Length > 1)
+
+            // Never save duplicate itemValues as they are now mapped anyway.
+            var itemValuesToSave = GetItemValuesToSave(item.Item, item.InheritedTags).DistinctBy(e => (GetCleanValue(e.Value), e.MagicNumber));
+            context.ItemValuesMap.Where(e => e.ItemId == entity.Id).ExecuteDelete();
+            foreach (var itemValue in itemValuesToSave)
             {
-                var excludeTypeName = new List<string>();
-                foreach (var excludeType in excludeTypes)
+                var refValue = context.ItemValues
+                    .Where(f => f.CleanValue == GetCleanValue(itemValue.Value) && (int)f.Type == itemValue.MagicNumber)
+                    .Select(e => e.ItemValueId)
+                    .FirstOrDefault();
+                if (refValue.IsEmpty())
                 {
-                    if (itemTypeLookup.BaseItemKindNames.TryGetValue(excludeType, out var baseItemKindName))
+                    context.ItemValues.Add(new ItemValue()
                     {
-                        excludeTypeName.Add(baseItemKindName!);
-                    }
+                        CleanValue = GetCleanValue(itemValue.Value),
+                        Type = (ItemValueType)itemValue.MagicNumber,
+                        ItemValueId = refValue = Guid.NewGuid(),
+                        Value = itemValue.Value
+                    });
                 }
 
-                baseQuery = baseQuery.Where(e => !excludeTypeName.Contains(e.Type));
-            }
-        }
-        else if (includeTypes.Length == 1)
-        {
-            if (itemTypeLookup.BaseItemKindNames.TryGetValue(includeTypes[0], out var includeTypeName))
-            {
-                baseQuery = baseQuery.Where(e => e.Type == includeTypeName);
-            }
-        }
-        else if (includeTypes.Length > 1)
-        {
-            var includeTypeName = new List<string>();
-            foreach (var includeType in includeTypes)
-            {
-                if (itemTypeLookup.BaseItemKindNames.TryGetValue(includeType, out var baseItemKindName))
+                context.ItemValuesMap.Add(new ItemValueMap()
                 {
-                    includeTypeName.Add(baseItemKindName!);
-                }
+                    Item = null!,
+                    ItemId = entity.Id,
+                    ItemValue = null!,
+                    ItemValueId = refValue
+                });
             }
-
-            baseQuery = baseQuery.Where(e => includeTypeName.Contains(e.Type));
         }
 
-        if (filter.ChannelIds.Count > 0)
+        context.SaveChanges();
+        transaction.Commit();
+    }
+
+    /// <inheritdoc cref="IItemRepository" />
+    public BaseItemDto? RetrieveItem(Guid id)
+    {
+        if (id.IsEmpty())
         {
-            var channelIds = filter.ChannelIds.Select(e => e.ToString("N", CultureInfo.InvariantCulture)).ToArray();
-            baseQuery = baseQuery.Where(e => channelIds.Contains(e.ChannelId));
+            throw new ArgumentException("Guid can't be empty", nameof(id));
         }
 
-        if (!filter.ParentId.IsEmpty())
+        using var context = dbProvider.CreateDbContext();
+        var item = PrepareItemQuery(context, new()
         {
-            baseQuery = baseQuery.Where(e => e.ParentId!.Value == filter.ParentId);
+            DtoOptions = new()
+            {
+                EnableImages = true
+            }
+        }).FirstOrDefault(e => e.Id == id);
+        if (item is null)
+        {
+            return null;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.Path))
-        {
-            baseQuery = baseQuery.Where(e => e.Path == filter.Path);
-        }
+        return DeserialiseBaseItem(item);
+    }
 
-        if (!string.IsNullOrWhiteSpace(filter.PresentationUniqueKey))
+    /// <summary>
+    /// Maps a Entity to the DTO.
+    /// </summary>
+    /// <param name="entity">The entity.</param>
+    /// <param name="dto">The dto base instance.</param>
+    /// <param name="appHost">The Application server Host.</param>
+    /// <returns>The dto to map.</returns>
+    public static BaseItemDto Map(BaseItemEntity entity, BaseItemDto dto, IServerApplicationHost? appHost)
+    {
+        dto.Id = entity.Id;
+        dto.ParentId = entity.ParentId.GetValueOrDefault();
+        dto.Path = appHost?.ExpandVirtualPath(entity.Path) ?? entity.Path;
+        dto.EndDate = entity.EndDate;
+        dto.CommunityRating = entity.CommunityRating;
+        dto.CustomRating = entity.CustomRating;
+        dto.IndexNumber = entity.IndexNumber;
+        dto.IsLocked = entity.IsLocked;
+        dto.Name = entity.Name;
+        dto.OfficialRating = entity.OfficialRating;
+        dto.Overview = entity.Overview;
+        dto.ParentIndexNumber = entity.ParentIndexNumber;
+        dto.PremiereDate = entity.PremiereDate;
+        dto.ProductionYear = entity.ProductionYear;
+        dto.SortName = entity.SortName;
+        dto.ForcedSortName = entity.ForcedSortName;
+        dto.RunTimeTicks = entity.RunTimeTicks;
+        dto.PreferredMetadataLanguage = entity.PreferredMetadataLanguage;
+        dto.PreferredMetadataCountryCode = entity.PreferredMetadataCountryCode;
+        dto.IsInMixedFolder = entity.IsInMixedFolder;
+        dto.InheritedParentalRatingValue = entity.InheritedParentalRatingValue;
+        dto.CriticRating = entity.CriticRating;
+        dto.PresentationUniqueKey = entity.PresentationUniqueKey;
+        dto.OriginalTitle = entity.OriginalTitle;
+        dto.Album = entity.Album;
+        dto.LUFS = entity.LUFS;
+        dto.NormalizationGain = entity.NormalizationGain;
+        dto.IsVirtualItem = entity.IsVirtualItem;
+        dto.ExternalSeriesId = entity.ExternalSeriesId;
+        dto.Tagline = entity.Tagline;
+        dto.TotalBitrate = entity.TotalBitrate;
+        dto.ExternalId = entity.ExternalId;
+        dto.Size = entity.Size;
+        dto.Genres = entity.Genres?.Split('|') ?? [];
+        dto.DateCreated = entity.DateCreated.GetValueOrDefault();
+        dto.DateModified = entity.DateModified.GetValueOrDefault();
+        dto.ChannelId = string.IsNullOrWhiteSpace(entity.ChannelId) ? Guid.Empty : (Guid.TryParse(entity.ChannelId, out var channelId) ? channelId : Guid.Empty);
+        dto.DateLastRefreshed = entity.DateLastRefreshed.GetValueOrDefault();
+        dto.DateLastSaved = entity.DateLastSaved.GetValueOrDefault();
+        dto.OwnerId = string.IsNullOrWhiteSpace(entity.OwnerId) ? Guid.Empty : (Guid.TryParse(entity.OwnerId, out var ownerId) ? ownerId : Guid.Empty);
+        dto.Width = entity.Width.GetValueOrDefault();
+        dto.Height = entity.Height.GetValueOrDefault();
+        if (entity.Provider is not null)
         {
-            baseQuery = baseQuery.Where(e => e.PresentationUniqueKey == filter.PresentationUniqueKey);
+            dto.ProviderIds = entity.Provider.ToDictionary(e => e.ProviderId, e => e.ProviderValue);
         }
 
-        if (filter.MinCommunityRating.HasValue)
+        if (entity.ExtraType is not null)
         {
-            baseQuery = baseQuery.Where(e => e.CommunityRating >= filter.MinCommunityRating);
+            dto.ExtraType = (ExtraType)entity.ExtraType;
         }
 
-        if (filter.MinIndexNumber.HasValue)
+        if (entity.LockedFields is not null)
         {
-            baseQuery = baseQuery.Where(e => e.IndexNumber >= filter.MinIndexNumber);
+            dto.LockedFields = entity.LockedFields?.Select(e => (MetadataField)e.Id).ToArray() ?? [];
         }
 
-        if (filter.MinParentAndIndexNumber.HasValue)
+        if (entity.Audio is not null)
         {
-            baseQuery = baseQuery
-                .Where(e => (e.ParentIndexNumber == filter.MinParentAndIndexNumber.Value.ParentIndexNumber && e.IndexNumber >= filter.MinParentAndIndexNumber.Value.IndexNumber) || e.ParentIndexNumber > filter.MinParentAndIndexNumber.Value.ParentIndexNumber);
+            dto.Audio = (ProgramAudio)entity.Audio;
         }
 
-        if (filter.MinDateCreated.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.DateCreated >= filter.MinDateCreated);
-        }
+        dto.ExtraIds = string.IsNullOrWhiteSpace(entity.ExtraIds) ? [] : entity.ExtraIds.Split('|').Select(e => Guid.Parse(e)).ToArray();
+        dto.ProductionLocations = entity.ProductionLocations?.Split('|') ?? [];
+        dto.Studios = entity.Studios?.Split('|') ?? [];
+        dto.Tags = entity.Tags?.Split('|') ?? [];
 
-        if (filter.MinDateLastSaved.HasValue)
+        if (dto is IHasProgramAttributes hasProgramAttributes)
         {
-            baseQuery = baseQuery.Where(e => e.DateLastSaved != null && e.DateLastSaved >= filter.MinDateLastSaved.Value);
+            hasProgramAttributes.IsMovie = entity.IsMovie;
+            hasProgramAttributes.IsSeries = entity.IsSeries;
+            hasProgramAttributes.EpisodeTitle = entity.EpisodeTitle;
+            hasProgramAttributes.IsRepeat = entity.IsRepeat;
         }
 
-        if (filter.MinDateLastSavedForUser.HasValue)
+        if (dto is LiveTvChannel liveTvChannel)
         {
-            baseQuery = baseQuery.Where(e => e.DateLastSaved != null && e.DateLastSaved >= filter.MinDateLastSavedForUser.Value);
+            liveTvChannel.ServiceName = entity.ExternalServiceId;
         }
 
-        if (filter.IndexNumber.HasValue)
+        if (dto is Trailer trailer)
         {
-            baseQuery = baseQuery.Where(e => e.IndexNumber == filter.IndexNumber.Value);
+            trailer.TrailerTypes = entity.TrailerTypes?.Select(e => (TrailerType)e.Id).ToArray() ?? [];
         }
 
-        if (filter.ParentIndexNumber.HasValue)
+        if (dto is Video video)
         {
-            baseQuery = baseQuery.Where(e => e.ParentIndexNumber == filter.ParentIndexNumber.Value);
+            video.PrimaryVersionId = entity.PrimaryVersionId;
         }
 
-        if (filter.ParentIndexNumberNotEquals.HasValue)
+        if (dto is IHasSeries hasSeriesName)
         {
-            baseQuery = baseQuery.Where(e => e.ParentIndexNumber != filter.ParentIndexNumberNotEquals.Value || e.ParentIndexNumber == null);
+            hasSeriesName.SeriesName = entity.SeriesName;
+            hasSeriesName.SeriesId = entity.SeriesId.GetValueOrDefault();
+            hasSeriesName.SeriesPresentationUniqueKey = entity.SeriesPresentationUniqueKey;
         }
 
-        var minEndDate = filter.MinEndDate;
-        var maxEndDate = filter.MaxEndDate;
-
-        if (filter.HasAired.HasValue)
+        if (dto is Episode episode)
         {
-            if (filter.HasAired.Value)
-            {
-                maxEndDate = DateTime.UtcNow;
-            }
-            else
-            {
-                minEndDate = DateTime.UtcNow;
-            }
+            episode.SeasonName = entity.SeasonName;
+            episode.SeasonId = entity.SeasonId.GetValueOrDefault();
         }
 
-        if (minEndDate.HasValue)
+        if (dto is IHasArtist hasArtists)
         {
-            baseQuery = baseQuery.Where(e => e.EndDate >= minEndDate);
+            hasArtists.Artists = entity.Artists?.Split('|', StringSplitOptions.RemoveEmptyEntries) ?? [];
         }
 
-        if (maxEndDate.HasValue)
+        if (dto is IHasAlbumArtist hasAlbumArtists)
         {
-            baseQuery = baseQuery.Where(e => e.EndDate <= maxEndDate);
+            hasAlbumArtists.AlbumArtists = entity.AlbumArtists?.Split('|', StringSplitOptions.RemoveEmptyEntries) ?? [];
         }
 
-        if (filter.MinStartDate.HasValue)
+        if (dto is LiveTvProgram program)
         {
-            baseQuery = baseQuery.Where(e => e.StartDate >= filter.MinStartDate.Value);
+            program.ShowId = entity.ShowId;
         }
 
-        if (filter.MaxStartDate.HasValue)
+        if (entity.Images is not null)
         {
-            baseQuery = baseQuery.Where(e => e.StartDate <= filter.MaxStartDate.Value);
+            dto.ImageInfos = entity.Images.Select(e => Map(e, appHost)).ToArray();
         }
 
-        if (filter.MinPremiereDate.HasValue)
+        // dto.Type = entity.Type;
+        // dto.Data = entity.Data;
+        // dto.MediaType = Enum.TryParse<MediaType>(entity.MediaType);
+        if (dto is IHasStartDate hasStartDate)
         {
-            baseQuery = baseQuery.Where(e => e.PremiereDate <= filter.MinPremiereDate.Value);
+            hasStartDate.StartDate = entity.StartDate;
         }
 
-        if (filter.MaxPremiereDate.HasValue)
-        {
-            baseQuery = baseQuery.Where(e => e.PremiereDate <= filter.MaxPremiereDate.Value);
-        }
+        // Fields that are present in the DB but are never actually used
+        // dto.UnratedType = entity.UnratedType;
+        // dto.TopParentId = entity.TopParentId;
+        // dto.CleanName = entity.CleanName;
+        // dto.UserDataKey = entity.UserDataKey;
 
-        if (filter.TrailerTypes.Length > 0)
+        if (dto is Folder folder)
         {
-            var trailerTypes = filter.TrailerTypes.Select(e => (int)e).ToArray();
-            baseQuery = baseQuery.Where(e => trailerTypes.Any(f => e.TrailerTypes!.Any(w => w.Id == f)));
+            folder.DateLastMediaAdded = entity.DateLastMediaAdded;
         }
 
-        if (filter.IsAiring.HasValue)
-        {
-            if (filter.IsAiring.Value)
-            {
-                baseQuery = baseQuery.Where(e => e.StartDate <= now && e.EndDate >= now);
-            }
-            else
-            {
-                baseQuery = baseQuery.Where(e => e.StartDate > now && e.EndDate < now);
-            }
-        }
+        return dto;
+    }
 
-        if (filter.PersonIds.Length > 0)
+    /// <summary>
+    /// Maps a Entity to the DTO.
+    /// </summary>
+    /// <param name="dto">The entity.</param>
+    /// <returns>The dto to map.</returns>
+    public BaseItemEntity Map(BaseItemDto dto)
+    {
+        var dtoType = dto.GetType();
+        var entity = new BaseItemEntity()
         {
-            baseQuery = baseQuery
-                .Where(e =>
-                    context.PeopleBaseItemMap.Where(w => context.BaseItems.Where(r => filter.PersonIds.Contains(r.Id)).Any(f => f.Name == w.People.Name))
-                        .Any(f => f.ItemId == e.Id));
-        }
+            Type = dtoType.ToString(),
+            Id = dto.Id
+        };
 
-        if (!string.IsNullOrWhiteSpace(filter.Person))
+        if (TypeRequiresDeserialization(dtoType))
         {
-            baseQuery = baseQuery.Where(e => e.Peoples!.Any(f => f.People.Name == filter.Person));
+            entity.Data = JsonSerializer.Serialize(dto, dtoType, JsonDefaults.Options);
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.MinSortName))
+        entity.ParentId = !dto.ParentId.IsEmpty() ? dto.ParentId : null;
+        entity.Path = GetPathToSave(dto.Path);
+        entity.EndDate = dto.EndDate.GetValueOrDefault();
+        entity.CommunityRating = dto.CommunityRating;
+        entity.CustomRating = dto.CustomRating;
+        entity.IndexNumber = dto.IndexNumber;
+        entity.IsLocked = dto.IsLocked;
+        entity.Name = dto.Name;
+        entity.OfficialRating = dto.OfficialRating;
+        entity.Overview = dto.Overview;
+        entity.ParentIndexNumber = dto.ParentIndexNumber;
+        entity.PremiereDate = dto.PremiereDate;
+        entity.ProductionYear = dto.ProductionYear;
+        entity.SortName = dto.SortName;
+        entity.ForcedSortName = dto.ForcedSortName;
+        entity.RunTimeTicks = dto.RunTimeTicks;
+        entity.PreferredMetadataLanguage = dto.PreferredMetadataLanguage;
+        entity.PreferredMetadataCountryCode = dto.PreferredMetadataCountryCode;
+        entity.IsInMixedFolder = dto.IsInMixedFolder;
+        entity.InheritedParentalRatingValue = dto.InheritedParentalRatingValue;
+        entity.CriticRating = dto.CriticRating;
+        entity.PresentationUniqueKey = dto.PresentationUniqueKey;
+        entity.OriginalTitle = dto.OriginalTitle;
+        entity.Album = dto.Album;
+        entity.LUFS = dto.LUFS;
+        entity.NormalizationGain = dto.NormalizationGain;
+        entity.IsVirtualItem = dto.IsVirtualItem;
+        entity.ExternalSeriesId = dto.ExternalSeriesId;
+        entity.Tagline = dto.Tagline;
+        entity.TotalBitrate = dto.TotalBitrate;
+        entity.ExternalId = dto.ExternalId;
+        entity.Size = dto.Size;
+        entity.Genres = string.Join('|', dto.Genres);
+        entity.DateCreated = dto.DateCreated;
+        entity.DateModified = dto.DateModified;
+        entity.ChannelId = dto.ChannelId.ToString();
+        entity.DateLastRefreshed = dto.DateLastRefreshed;
+        entity.DateLastSaved = dto.DateLastSaved;
+        entity.OwnerId = dto.OwnerId.ToString();
+        entity.Width = dto.Width;
+        entity.Height = dto.Height;
+        entity.Provider = dto.ProviderIds.Select(e => new BaseItemProvider()
         {
-            // this does not makes sense.
-            // baseQuery = baseQuery.Where(e => e.SortName >= query.MinSortName);
-            // whereClauses.Add("SortName>=@MinSortName");
-            // statement?.TryBind("@MinSortName", query.MinSortName);
-        }
+            Item = entity,
+            ProviderId = e.Key,
+            ProviderValue = e.Value
+        }).ToList();
 
-        if (!string.IsNullOrWhiteSpace(filter.ExternalSeriesId))
+        if (dto.Audio.HasValue)
         {
-            baseQuery = baseQuery.Where(e => e.ExternalSeriesId == filter.ExternalSeriesId);
+            entity.Audio = (ProgramAudioEntity)dto.Audio;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.ExternalId))
+        if (dto.ExtraType.HasValue)
         {
-            baseQuery = baseQuery.Where(e => e.ExternalId == filter.ExternalId);
+            entity.ExtraType = (BaseItemExtraType)dto.ExtraType;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.Name))
-        {
-            var cleanName = GetCleanValue(filter.Name);
-            baseQuery = baseQuery.Where(e => e.CleanName == cleanName);
-        }
+        entity.ExtraIds = dto.ExtraIds is not null ? string.Join('|', dto.ExtraIds) : null;
+        entity.ProductionLocations = dto.ProductionLocations is not null ? string.Join('|', dto.ProductionLocations) : null;
+        entity.Studios = dto.Studios is not null ? string.Join('|', dto.Studios) : null;
+        entity.Tags = dto.Tags is not null ? string.Join('|', dto.Tags) : null;
+        entity.LockedFields = dto.LockedFields is not null ? dto.LockedFields
+            .Select(e => new BaseItemMetadataField()
+            {
+                Id = (int)e,
+                Item = entity,
+                ItemId = entity.Id
+            })
+            .ToArray() : null;
 
-        // These are the same, for now
-        var nameContains = filter.NameContains;
-        if (!string.IsNullOrWhiteSpace(nameContains))
+        if (dto is IHasProgramAttributes hasProgramAttributes)
         {
-            baseQuery = baseQuery.Where(e =>
-                e.CleanName == filter.NameContains
-                || e.OriginalTitle!.Contains(filter.NameContains!));
+            entity.IsMovie = hasProgramAttributes.IsMovie;
+            entity.IsSeries = hasProgramAttributes.IsSeries;
+            entity.EpisodeTitle = hasProgramAttributes.EpisodeTitle;
+            entity.IsRepeat = hasProgramAttributes.IsRepeat;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.NameStartsWith))
+        if (dto is LiveTvChannel liveTvChannel)
         {
-            baseQuery = baseQuery.Where(e => e.SortName!.StartsWith(filter.NameStartsWith) || e.Name!.StartsWith(filter.NameStartsWith));
+            entity.ExternalServiceId = liveTvChannel.ServiceName;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.NameStartsWithOrGreater))
+        if (dto is Video video)
         {
-            // i hate this
-            baseQuery = baseQuery.Where(e => e.SortName!.FirstOrDefault() > filter.NameStartsWithOrGreater[0] || e.Name!.FirstOrDefault() > filter.NameStartsWithOrGreater[0]);
+            entity.PrimaryVersionId = video.PrimaryVersionId;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.NameLessThan))
+        if (dto is IHasSeries hasSeriesName)
         {
-            // i hate this
-            baseQuery = baseQuery.Where(e => e.SortName!.FirstOrDefault() < filter.NameLessThan[0] || e.Name!.FirstOrDefault() < filter.NameLessThan[0]);
+            entity.SeriesName = hasSeriesName.SeriesName;
+            entity.SeriesId = hasSeriesName.SeriesId;
+            entity.SeriesPresentationUniqueKey = hasSeriesName.SeriesPresentationUniqueKey;
         }
 
-        if (filter.ImageTypes.Length > 0)
+        if (dto is Episode episode)
         {
-            var imgTypes = filter.ImageTypes.Select(e => (ImageInfoImageType)e).ToArray();
-            baseQuery = baseQuery.Where(e => imgTypes.Any(f => e.Images!.Any(w => w.ImageType == f)));
+            entity.SeasonName = episode.SeasonName;
+            entity.SeasonId = episode.SeasonId;
         }
 
-        if (filter.IsLiked.HasValue)
+        if (dto is IHasArtist hasArtists)
         {
-            baseQuery = baseQuery
-                .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.Rating >= UserItemData.MinLikeValue);
+            entity.Artists = hasArtists.Artists is not null ? string.Join('|', hasArtists.Artists) : null;
         }
 
-        if (filter.IsFavoriteOrLiked.HasValue)
+        if (dto is IHasAlbumArtist hasAlbumArtists)
         {
-            baseQuery = baseQuery
-                .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.IsFavorite == filter.IsFavoriteOrLiked);
+            entity.AlbumArtists = hasAlbumArtists.AlbumArtists is not null ? string.Join('|', hasAlbumArtists.AlbumArtists) : null;
         }
 
-        if (filter.IsFavorite.HasValue)
+        if (dto is LiveTvProgram program)
         {
-            baseQuery = baseQuery
-                .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.IsFavorite == filter.IsFavorite);
+            entity.ShowId = program.ShowId;
         }
 
-        if (filter.IsPlayed.HasValue)
+        if (dto.ImageInfos is not null)
         {
-            baseQuery = baseQuery
-                   .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.Played == filter.IsPlayed.Value || e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id) == null);
+            entity.Images = dto.ImageInfos.Select(f => Map(dto.Id, f)).ToArray();
         }
 
-        if (filter.IsResumable.HasValue)
+        if (dto is Trailer trailer)
         {
-            if (filter.IsResumable.Value)
-            {
-                baseQuery = baseQuery
-                       .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.PlaybackPositionTicks > 0);
-            }
-            else
+            entity.TrailerTypes = trailer.TrailerTypes?.Select(e => new BaseItemTrailerType()
             {
-                baseQuery = baseQuery
-                       .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.PlaybackPositionTicks == 0);
-            }
+                Id = (int)e,
+                Item = entity,
+                ItemId = entity.Id
+            }).ToArray() ?? [];
         }
 
-        if (filter.ArtistIds.Length > 0)
+        // dto.Type = entity.Type;
+        // dto.Data = entity.Data;
+        entity.MediaType = dto.MediaType.ToString();
+        if (dto is IHasStartDate hasStartDate)
         {
-            baseQuery = baseQuery
-                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type <= ItemValueType.Artist && filter.ArtistIds.Contains(f.ItemId)));
+            entity.StartDate = hasStartDate.StartDate;
         }
 
-        if (filter.AlbumArtistIds.Length > 0)
+        // Fields that are present in the DB but are never actually used
+        // dto.UnratedType = entity.UnratedType;
+        // dto.TopParentId = entity.TopParentId;
+        // dto.CleanName = entity.CleanName;
+        // dto.UserDataKey = entity.UserDataKey;
+
+        if (dto is Folder folder)
         {
-            baseQuery = baseQuery
-                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Artist && filter.AlbumArtistIds.Contains(f.ItemId)));
+            entity.DateLastMediaAdded = folder.DateLastMediaAdded;
+            entity.IsFolder = folder.IsFolder;
         }
 
-        if (filter.ContributingArtistIds.Length > 0)
+        return entity;
+    }
+
+    private IReadOnlyList<string> GetItemValueNames(ItemValueType[] itemValueTypes, IReadOnlyList<string> withItemTypes, IReadOnlyList<string> excludeItemTypes)
+    {
+        using var context = dbProvider.CreateDbContext();
+
+        var query = context.ItemValuesMap
+            .AsNoTracking()
+            .Where(e => itemValueTypes.Any(w => (ItemValueType)w == e.ItemValue.Type));
+        if (withItemTypes.Count > 0)
         {
-            baseQuery = baseQuery
-                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Artist && filter.ContributingArtistIds.Contains(f.ItemId)));
+            query = query.Where(e => withItemTypes.Contains(e.Item.Type));
         }
 
-        if (filter.AlbumIds.Length > 0)
+        if (excludeItemTypes.Count > 0)
         {
-            baseQuery = baseQuery.Where(e => context.BaseItems.Where(f => filter.AlbumIds.Contains(f.Id)).Any(f => f.Name == e.Album));
+            query = query.Where(e => !excludeItemTypes.Contains(e.Item.Type));
         }
 
-        if (filter.ExcludeArtistIds.Length > 0)
+        // query = query.DistinctBy(e => e.CleanValue);
+        return query.Select(e => e.ItemValue.CleanValue).ToImmutableArray();
+    }
+
+    private static bool TypeRequiresDeserialization(Type type)
+    {
+        return type.GetCustomAttribute<RequiresSourceSerialisationAttribute>() == null;
+    }
+
+    private BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, bool skipDeserialization = false)
+    {
+        ArgumentNullException.ThrowIfNull(baseItemEntity, nameof(baseItemEntity));
+        if (serverConfigurationManager?.Configuration is null)
         {
-            baseQuery = baseQuery
-                   .Where(e => !e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Artist && filter.ExcludeArtistIds.Contains(f.ItemId)));
+            throw new InvalidOperationException("Server Configuration manager or configuration is null");
         }
 
-        if (filter.GenreIds.Count > 0)
+        var typeToSerialise = GetType(baseItemEntity.Type);
+        return BaseItemRepository.DeserialiseBaseItem(
+            baseItemEntity,
+            logger,
+            appHost,
+            skipDeserialization || (serverConfigurationManager.Configuration.SkipDeserializationForBasicTypes && (typeToSerialise == typeof(Channel) || typeToSerialise == typeof(UserRootFolder))));
+    }
+
+    /// <summary>
+    /// Deserialises a BaseItemEntity and sets all properties.
+    /// </summary>
+    /// <param name="baseItemEntity">The DB entity.</param>
+    /// <param name="logger">Logger.</param>
+    /// <param name="appHost">The application server Host.</param>
+    /// <param name="skipDeserialization">If only mapping should be processed.</param>
+    /// <returns>A mapped BaseItem.</returns>
+    /// <exception cref="InvalidOperationException">Will be thrown if an invalid serialisation is requested.</exception>
+    public static BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, ILogger logger, IServerApplicationHost? appHost, bool skipDeserialization = false)
+    {
+        var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
+        BaseItemDto? dto = null;
+        if (TypeRequiresDeserialization(type) && baseItemEntity.Data is not null && !skipDeserialization)
         {
-            baseQuery = baseQuery
-                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Genre && filter.GenreIds.Contains(f.ItemId)));
+            try
+            {
+                using var dataAsStream = new MemoryStream(Encoding.UTF8.GetBytes(baseItemEntity.Data!));
+                dto = JsonSerializer.Deserialize(dataAsStream, type, JsonDefaults.Options) as BaseItemDto;
+            }
+            catch (JsonException ex)
+            {
+                logger.LogError(ex, "Error deserializing item with JSON: {Data}", baseItemEntity.Data);
+            }
         }
 
-        if (filter.Genres.Count > 0)
+        if (dto is null)
         {
-            var cleanGenres = filter.Genres.Select(e => GetCleanValue(e)).ToArray();
-            baseQuery = baseQuery
-                    .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Genre && cleanGenres.Contains(f.ItemValue.CleanValue)));
+            dto = Activator.CreateInstance(type) as BaseItemDto ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
         }
 
-        if (tags.Count > 0)
+        return Map(baseItemEntity, dto, appHost);
+    }
+
+    private QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetItemValues(InternalItemsQuery filter, ItemValueType[] itemValueTypes, string returnType)
+    {
+        ArgumentNullException.ThrowIfNull(filter);
+
+        if (!filter.Limit.HasValue)
         {
-            var cleanValues = tags.Select(e => GetCleanValue(e)).ToArray();
-            baseQuery = baseQuery
-                    .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Tags && cleanValues.Contains(f.ItemValue.CleanValue)));
+            filter.EnableTotalRecordCount = false;
         }
 
-        if (excludeTags.Count > 0)
+        using var context = dbProvider.CreateDbContext();
+
+        var innerQuery = new InternalItemsQuery(filter.User)
         {
-            var cleanValues = excludeTags.Select(e => GetCleanValue(e)).ToArray();
-            baseQuery = baseQuery
-                    .Where(e => !e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Tags && cleanValues.Contains(f.ItemValue.CleanValue)));
-        }
+            ExcludeItemTypes = filter.ExcludeItemTypes,
+            IncludeItemTypes = filter.IncludeItemTypes,
+            MediaTypes = filter.MediaTypes,
+            AncestorIds = filter.AncestorIds,
+            ItemIds = filter.ItemIds,
+            TopParentIds = filter.TopParentIds,
+            ParentId = filter.ParentId,
+            IsAiring = filter.IsAiring,
+            IsMovie = filter.IsMovie,
+            IsSports = filter.IsSports,
+            IsKids = filter.IsKids,
+            IsNews = filter.IsNews,
+            IsSeries = filter.IsSeries
+        };
+        var query = TranslateQuery(context.BaseItems.AsNoTracking(), context, innerQuery);
 
-        if (filter.StudioIds.Length > 0)
+        query = query.Where(e => e.Type == returnType && e.ItemValues!.Any(f => e.CleanName == f.ItemValue.CleanValue && itemValueTypes.Any(w => (ItemValueType)w == f.ItemValue.Type)));
+
+        if (filter.OrderBy.Count != 0
+            || !string.IsNullOrEmpty(filter.SearchTerm))
         {
-            baseQuery = baseQuery
-                    .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Studios && filter.StudioIds.Contains(f.ItemId)));
+            query = ApplyOrder(query, filter);
         }
-
-        if (filter.OfficialRatings.Length > 0)
+        else
         {
-            baseQuery = baseQuery
-                   .Where(e => filter.OfficialRatings.Contains(e.OfficialRating));
+            query = query.OrderBy(e => e.SortName);
         }
 
-        if (filter.HasParentalRating ?? false)
+        if (filter.Limit.HasValue || filter.StartIndex.HasValue)
         {
-            if (filter.MinParentalRating.HasValue)
+            var offset = filter.StartIndex ?? 0;
+
+            if (offset > 0)
             {
-                baseQuery = baseQuery
-                   .Where(e => e.InheritedParentalRatingValue >= filter.MinParentalRating.Value);
+                query = query.Skip(offset);
             }
 
-            if (filter.MaxParentalRating.HasValue)
+            if (filter.Limit.HasValue)
             {
-                baseQuery = baseQuery
-                   .Where(e => e.InheritedParentalRatingValue < filter.MaxParentalRating.Value);
+                query = query.Take(filter.Limit.Value);
             }
         }
-        else if (filter.BlockUnratedItems.Length > 0)
+
+        var result = new QueryResult<(BaseItemDto, ItemCounts)>();
+        if (filter.EnableTotalRecordCount)
         {
-            var unratedItems = filter.BlockUnratedItems.Select(f => f.ToString()).ToArray();
-            if (filter.MinParentalRating.HasValue)
-            {
-                if (filter.MaxParentalRating.HasValue)
-                {
-                    baseQuery = baseQuery
-                        .Where(e => (e.InheritedParentalRatingValue == null && !unratedItems.Contains(e.UnratedType))
-                        || (e.InheritedParentalRatingValue >= filter.MinParentalRating && e.InheritedParentalRatingValue <= filter.MaxParentalRating));
-                }
-                else
-                {
-                    baseQuery = baseQuery
-                        .Where(e => (e.InheritedParentalRatingValue == null && !unratedItems.Contains(e.UnratedType))
-                        || e.InheritedParentalRatingValue >= filter.MinParentalRating);
-                }
-            }
-            else
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.InheritedParentalRatingValue != null && !unratedItems.Contains(e.UnratedType));
-            }
-        }
-        else if (filter.MinParentalRating.HasValue)
-        {
-            if (filter.MaxParentalRating.HasValue)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MinParentalRating.Value && e.InheritedParentalRatingValue <= filter.MaxParentalRating.Value);
-            }
-            else
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MinParentalRating.Value);
-            }
-        }
-        else if (filter.MaxParentalRating.HasValue)
-        {
-            baseQuery = baseQuery
-                .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MaxParentalRating.Value);
-        }
-        else if (!filter.HasParentalRating ?? false)
-        {
-            baseQuery = baseQuery
-                .Where(e => e.InheritedParentalRatingValue == null);
+            result.TotalRecordCount = query.DistinctBy(e => e.PresentationUniqueKey).Count();
         }
 
-        if (filter.HasOfficialRating.HasValue)
-        {
-            if (filter.HasOfficialRating.Value)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.OfficialRating != null && e.OfficialRating != string.Empty);
-            }
-            else
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty);
-            }
-        }
+        var seriesTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Series];
+        var movieTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie];
+        var episodeTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Episode];
+        var musicAlbumTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicAlbum];
+        var musicArtistTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist];
+        var audioTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Audio];
+        var trailerTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Trailer];
 
-        if (filter.HasOverview.HasValue)
+        var resultQuery = query.Select(e => new
         {
-            if (filter.HasOverview.Value)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.Overview != null && e.Overview != string.Empty);
-            }
-            else
+            item = e,
+            // TODO: This is bad refactor!
+            itemCount = new ItemCounts()
             {
-                baseQuery = baseQuery
-                    .Where(e => e.Overview == null || e.Overview == string.Empty);
+                SeriesCount = e.ItemValues!.Count(f => f.Item.Type == seriesTypeName),
+                EpisodeCount = e.ItemValues!.Count(f => f.Item.Type == episodeTypeName),
+                MovieCount = e.ItemValues!.Count(f => f.Item.Type == movieTypeName),
+                AlbumCount = e.ItemValues!.Count(f => f.Item.Type == musicAlbumTypeName),
+                ArtistCount = e.ItemValues!.Count(f => f.Item.Type == musicArtistTypeName),
+                SongCount = e.ItemValues!.Count(f => f.Item.Type == audioTypeName),
+                TrailerCount = e.ItemValues!.Count(f => f.Item.Type == trailerTypeName),
             }
-        }
+        });
 
-        if (filter.HasOwnerId.HasValue)
+        result.StartIndex = filter.StartIndex ?? 0;
+        result.Items = resultQuery.ToImmutableArray().Where(e => e is not null).Select(e =>
         {
-            if (filter.HasOwnerId.Value)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.OwnerId != null);
-            }
-            else
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.OwnerId == null);
-            }
-        }
+            return (DeserialiseBaseItem(e.item, filter.SkipDeserialization), e.itemCount);
+        }).ToImmutableArray();
 
-        if (!string.IsNullOrWhiteSpace(filter.HasNoAudioTrackWithLanguage))
-        {
-            baseQuery = baseQuery
-                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Audio && f.Language == filter.HasNoAudioTrackWithLanguage));
-        }
+        return result;
+    }
 
-        if (!string.IsNullOrWhiteSpace(filter.HasNoInternalSubtitleTrackWithLanguage))
+    private static void PrepareFilterQuery(InternalItemsQuery query)
+    {
+        if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
         {
-            baseQuery = baseQuery
-                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle && !f.IsExternal && f.Language == filter.HasNoInternalSubtitleTrackWithLanguage));
+            query.Limit = query.Limit.Value + 4;
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.HasNoExternalSubtitleTrackWithLanguage))
+        if (query.IsResumable ?? false)
         {
-            baseQuery = baseQuery
-                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle && f.IsExternal && f.Language == filter.HasNoExternalSubtitleTrackWithLanguage));
+            query.IsVirtualItem = false;
         }
+    }
 
-        if (!string.IsNullOrWhiteSpace(filter.HasNoSubtitleTrackWithLanguage))
+    private string GetCleanValue(string value)
+    {
+        if (string.IsNullOrWhiteSpace(value))
         {
-            baseQuery = baseQuery
-                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle && f.Language == filter.HasNoSubtitleTrackWithLanguage));
+            return value;
         }
 
-        if (filter.HasSubtitles.HasValue)
+        return value.RemoveDiacritics().ToLowerInvariant();
+    }
+
+    private List<(int MagicNumber, string Value)> GetItemValuesToSave(BaseItemDto item, List<string> inheritedTags)
+    {
+        var list = new List<(int, string)>();
+
+        if (item is IHasArtist hasArtist)
         {
-            baseQuery = baseQuery
-                .Where(e => e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle) == filter.HasSubtitles.Value);
+            list.AddRange(hasArtist.Artists.Select(i => (0, i)));
         }
 
-        if (filter.HasChapterImages.HasValue)
+        if (item is IHasAlbumArtist hasAlbumArtist)
         {
-            baseQuery = baseQuery
-                .Where(e => e.Chapters!.Any(f => f.ImagePath != null) == filter.HasChapterImages.Value);
+            list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => (1, i)));
         }
 
-        if (filter.HasDeadParentId.HasValue && filter.HasDeadParentId.Value)
+        list.AddRange(item.Genres.Select(i => (2, i)));
+        list.AddRange(item.Studios.Select(i => (3, i)));
+        list.AddRange(item.Tags.Select(i => (4, i)));
+
+        // keywords was 5
+
+        list.AddRange(inheritedTags.Select(i => (6, i)));
+
+        // Remove all invalid values.
+        list.RemoveAll(i => string.IsNullOrWhiteSpace(i.Item2));
+
+        return list;
+    }
+
+    private static BaseItemImageInfo Map(Guid baseItemId, ItemImageInfo e)
+    {
+        return new BaseItemImageInfo()
         {
-            baseQuery = baseQuery
-                .Where(e => e.ParentId.HasValue && !context.BaseItems.Any(f => f.Id == e.ParentId.Value));
-        }
+            ItemId = baseItemId,
+            Id = Guid.NewGuid(),
+            Path = e.Path,
+            Blurhash = e.BlurHash != null ? Encoding.UTF8.GetBytes(e.BlurHash) : null,
+            DateModified = e.DateModified,
+            Height = e.Height,
+            Width = e.Width,
+            ImageType = (ImageInfoImageType)e.Type,
+            Item = null!
+        };
+    }
 
-        if (filter.IsDeadArtist.HasValue && filter.IsDeadArtist.Value)
+    private static ItemImageInfo Map(BaseItemImageInfo e, IServerApplicationHost? appHost)
+    {
+        return new ItemImageInfo()
         {
-            baseQuery = baseQuery
-                    .Where(e => e.ItemValues!.Count(f => f.ItemValue.Type == ItemValueType.Artist || f.ItemValue.Type == ItemValueType.AlbumArtist) == 1);
-        }
+            Path = appHost?.ExpandVirtualPath(e.Path) ?? e.Path,
+            BlurHash = e.Blurhash != null ? Encoding.UTF8.GetString(e.Blurhash) : null,
+            DateModified = e.DateModified,
+            Height = e.Height,
+            Width = e.Width,
+            Type = (ImageType)e.ImageType
+        };
+    }
 
-        if (filter.IsDeadStudio.HasValue && filter.IsDeadStudio.Value)
+    private string? GetPathToSave(string path)
+    {
+        if (path is null)
         {
-            baseQuery = baseQuery
-                    .Where(e => e.ItemValues!.Count(f => f.ItemValue.Type == ItemValueType.Studios) == 1);
+            return null;
         }
 
-        if (filter.IsDeadPerson.HasValue && filter.IsDeadPerson.Value)
+        return appHost.ReverseVirtualPath(path);
+    }
+
+    private List<string> GetItemByNameTypesInQuery(InternalItemsQuery query)
+    {
+        var list = new List<string>();
+
+        if (IsTypeInQuery(BaseItemKind.Person, query))
         {
-            baseQuery = baseQuery
-                .Where(e => !context.Peoples.Any(f => f.Name == e.Name));
+            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.Person]!);
         }
 
-        if (filter.Years.Length == 1)
+        if (IsTypeInQuery(BaseItemKind.Genre, query))
         {
-            baseQuery = baseQuery
-                .Where(e => e.ProductionYear == filter.Years[0]);
+            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.Genre]!);
         }
-        else if (filter.Years.Length > 1)
+
+        if (IsTypeInQuery(BaseItemKind.MusicGenre, query))
         {
-            baseQuery = baseQuery
-                .Where(e => filter.Years.Any(f => f == e.ProductionYear));
+            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicGenre]!);
         }
 
-        var isVirtualItem = filter.IsVirtualItem ?? filter.IsMissing;
-        if (isVirtualItem.HasValue)
+        if (IsTypeInQuery(BaseItemKind.MusicArtist, query))
         {
-            baseQuery = baseQuery
-                .Where(e => e.IsVirtualItem == isVirtualItem.Value);
+            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!);
         }
 
-        if (filter.IsSpecialSeason.HasValue)
+        if (IsTypeInQuery(BaseItemKind.Studio, query))
         {
-            if (filter.IsSpecialSeason.Value)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.IndexNumber == 0);
-            }
-            else
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.IndexNumber != 0);
-            }
+            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.Studio]!);
         }
 
-        if (filter.IsUnaired.HasValue)
+        return list;
+    }
+
+    private bool IsTypeInQuery(BaseItemKind type, InternalItemsQuery query)
+    {
+        if (query.ExcludeItemTypes.Contains(type))
         {
-            if (filter.IsUnaired.Value)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.PremiereDate >= now);
-            }
-            else
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.PremiereDate < now);
-            }
+            return false;
         }
 
-        if (filter.MediaTypes.Length > 0)
+        return query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(type);
+    }
+
+    private Expression<Func<BaseItemEntity, object>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query)
+    {
+#pragma warning disable CS8603 // Possible null reference return.
+        return sortBy switch
         {
-            var mediaTypes = filter.MediaTypes.Select(f => f.ToString()).ToArray();
-            baseQuery = baseQuery
-                .Where(e => mediaTypes.Contains(e.MediaType));
-        }
+            ItemSortBy.AirTime => e => e.SortName, // TODO
+            ItemSortBy.Runtime => e => e.RunTimeTicks,
+            ItemSortBy.Random => e => EF.Functions.Random(),
+            ItemSortBy.DatePlayed => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.LastPlayedDate,
+            ItemSortBy.PlayCount => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.PlayCount,
+            ItemSortBy.IsFavoriteOrLiked => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.IsFavorite,
+            ItemSortBy.IsFolder => e => e.IsFolder,
+            ItemSortBy.IsPlayed => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.Played,
+            ItemSortBy.IsUnplayed => e => !e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.Played,
+            ItemSortBy.DateLastContentAdded => e => e.DateLastMediaAdded,
+            ItemSortBy.Artist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f => f.ItemValue.CleanValue),
+            ItemSortBy.AlbumArtist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).Select(f => f.ItemValue.CleanValue),
+            ItemSortBy.Studio => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f => f.ItemValue.CleanValue),
+            ItemSortBy.OfficialRating => e => e.InheritedParentalRatingValue,
+            // ItemSortBy.SeriesDatePlayed => "(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where Played=1 and B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)",
+            ItemSortBy.SeriesSortName => e => e.SeriesName,
+            // ItemSortBy.AiredEpisodeOrder => "AiredEpisodeOrder",
+            ItemSortBy.Album => e => e.Album,
+            ItemSortBy.DateCreated => e => e.DateCreated,
+            ItemSortBy.PremiereDate => e => e.PremiereDate,
+            ItemSortBy.StartDate => e => e.StartDate,
+            ItemSortBy.Name => e => e.Name,
+            ItemSortBy.CommunityRating => e => e.CommunityRating,
+            ItemSortBy.ProductionYear => e => e.ProductionYear,
+            ItemSortBy.CriticRating => e => e.CriticRating,
+            ItemSortBy.VideoBitRate => e => e.TotalBitrate,
+            ItemSortBy.ParentIndexNumber => e => e.ParentIndexNumber,
+            ItemSortBy.IndexNumber => e => e.IndexNumber,
+            _ => e => e.SortName
+        };
+#pragma warning restore CS8603 // Possible null reference return.
 
-        if (filter.ItemIds.Length > 0)
+    }
+
+    private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
+    {
+        if (!query.GroupByPresentationUniqueKey)
         {
-            baseQuery = baseQuery
-                .Where(e => filter.ItemIds.Contains(e.Id));
+            return false;
         }
 
-        if (filter.ExcludeItemIds.Length > 0)
+        if (query.GroupBySeriesPresentationUniqueKey)
         {
-            baseQuery = baseQuery
-                .Where(e => !filter.ItemIds.Contains(e.Id));
+            return false;
         }
 
-        if (filter.ExcludeProviderIds is not null && filter.ExcludeProviderIds.Count > 0)
+        if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
         {
-            baseQuery = baseQuery.Where(e => !e.Provider!.All(f => !filter.ExcludeProviderIds.All(w => f.ProviderId == w.Key && f.ProviderValue == w.Value)));
+            return false;
         }
 
-        if (filter.HasAnyProviderId is not null && filter.HasAnyProviderId.Count > 0)
+        if (query.User is null)
         {
-            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => !filter.HasAnyProviderId.Any(w => f.ProviderId == w.Key && f.ProviderValue == w.Value)));
+            return false;
         }
 
-        if (filter.HasImdbId.HasValue)
+        if (query.IncludeItemTypes.Length == 0)
         {
-            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => f.ProviderId == "imdb"));
+            return true;
         }
 
-        if (filter.HasTmdbId.HasValue)
+        return query.IncludeItemTypes.Contains(BaseItemKind.Episode)
+            || query.IncludeItemTypes.Contains(BaseItemKind.Video)
+            || query.IncludeItemTypes.Contains(BaseItemKind.Movie)
+            || query.IncludeItemTypes.Contains(BaseItemKind.MusicVideo)
+            || query.IncludeItemTypes.Contains(BaseItemKind.Series)
+            || query.IncludeItemTypes.Contains(BaseItemKind.Season);
+    }
+
+    private IQueryable<BaseItemEntity> ApplyOrder(IQueryable<BaseItemEntity> query, InternalItemsQuery filter)
+    {
+        var orderBy = filter.OrderBy;
+        bool hasSearch = !string.IsNullOrEmpty(filter.SearchTerm);
+
+        if (hasSearch)
         {
-            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => f.ProviderId == "tmdb"));
-        }
+            List<(ItemSortBy, SortOrder)> prepend = new List<(ItemSortBy, SortOrder)>(4);
+            if (hasSearch)
+            {
+                prepend.Add((ItemSortBy.SortName, SortOrder.Ascending));
+            }
 
-        if (filter.HasTvdbId.HasValue)
+            orderBy = filter.OrderBy = [.. prepend, .. orderBy];
+        }
+        else if (orderBy.Count == 0)
         {
-            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => f.ProviderId == "tvdb"));
+            return query;
         }
 
-        var queryTopParentIds = filter.TopParentIds;
+        IOrderedQueryable<BaseItemEntity>? orderedQuery = null;
 
-        if (queryTopParentIds.Length > 0)
+        var firstOrdering = orderBy.FirstOrDefault();
+        if (firstOrdering != default)
         {
-            var includedItemByNameTypes = GetItemByNameTypesInQuery(filter);
-            var enableItemsByName = (filter.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
-            if (enableItemsByName && includedItemByNameTypes.Count > 0)
+            var expression = MapOrderByField(firstOrdering.OrderBy, filter);
+            if (firstOrdering.SortOrder == SortOrder.Ascending)
             {
-                baseQuery = baseQuery.Where(e => includedItemByNameTypes.Contains(e.Type) || queryTopParentIds.Any(w => w == e.TopParentId!.Value));
+                orderedQuery = query.OrderBy(expression);
             }
             else
             {
-                baseQuery = baseQuery.Where(e => queryTopParentIds.Contains(e.TopParentId!.Value));
+                orderedQuery = query.OrderByDescending(expression);
             }
-        }
 
-        if (filter.AncestorIds.Length > 0)
-        {
-            baseQuery = baseQuery.Where(e => e.Children!.Any(f => filter.AncestorIds.Contains(f.ParentItemId)));
+            if (firstOrdering.OrderBy is ItemSortBy.Default or ItemSortBy.SortName)
+            {
+                if (firstOrdering.SortOrder is SortOrder.Ascending)
+                {
+                    orderedQuery = orderedQuery.ThenBy(e => e.Name);
+                }
+                else
+                {
+                    orderedQuery = orderedQuery.ThenByDescending(e => e.Name);
+                }
+            }
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.AncestorWithPresentationUniqueKey))
+        foreach (var item in orderBy.Skip(1))
         {
-            baseQuery = baseQuery
-                .Where(e => context.BaseItems.Where(f => f.PresentationUniqueKey == filter.AncestorWithPresentationUniqueKey).Any(f => f.ParentAncestors!.Any(w => w.ItemId == f.Id)));
+            var expression = MapOrderByField(item.OrderBy, filter);
+            if (item.SortOrder == SortOrder.Ascending)
+            {
+                orderedQuery = orderedQuery!.ThenBy(expression);
+            }
+            else
+            {
+                orderedQuery = orderedQuery!.ThenByDescending(expression);
+            }
         }
 
-        if (!string.IsNullOrWhiteSpace(filter.SeriesPresentationUniqueKey))
-        {
-            baseQuery = baseQuery
-                .Where(e => e.SeriesPresentationUniqueKey == filter.SeriesPresentationUniqueKey);
-        }
+        return orderedQuery ?? query;
+    }
 
-        if (filter.ExcludeInheritedTags.Length > 0)
-        {
-            baseQuery = baseQuery
-                .Where(e => !e.ItemValues!.Where(w => w.ItemValue.Type == ItemValueType.InheritedTags)
-                    .Any(f => filter.ExcludeInheritedTags.Contains(f.ItemValue.CleanValue)));
-        }
+    private IQueryable<BaseItemEntity> TranslateQuery(
+        IQueryable<BaseItemEntity> baseQuery,
+        JellyfinDbContext context,
+        InternalItemsQuery filter)
+    {
+        var minWidth = filter.MinWidth;
+        var maxWidth = filter.MaxWidth;
+        var now = DateTime.UtcNow;
 
-        if (filter.IncludeInheritedTags.Length > 0)
+        if (filter.IsHD.HasValue)
         {
-            // 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)
+            const int Threshold = 1200;
+            if (filter.IsHD.Value)
             {
-                baseQuery = baseQuery
-                    .Where(e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.InheritedTags)
-                        .Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue))
-                        ||
-                        (e.ParentId.HasValue && context.ItemValuesMap.Where(w => w.ItemId == e.ParentId.Value)!.Where(w => w.ItemValue.Type == ItemValueType.InheritedTags)
-                        .Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue))));
+                minWidth = Threshold;
+            }
+            else
+            {
+                maxWidth = Threshold - 1;
             }
+        }
 
-            // A playlist should be accessible to its owner regardless of allowed tags.
-            else if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Playlist)
+        if (filter.Is4K.HasValue)
+        {
+            const int Threshold = 3800;
+            if (filter.Is4K.Value)
             {
-                baseQuery = baseQuery
-                    .Where(e =>
-                    e.ParentAncestors!
-                        .Any(f =>
-                            f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))
-                            || e.Data!.Contains($"OwnerUserId\":\"{filter.User!.Id:N}\"")));
-                // d        ^^ this is stupid it hate this.
+                minWidth = Threshold;
             }
             else
             {
-                baseQuery = baseQuery
-                    .Where(e => e.ParentAncestors!.Any(f => f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))));
+                maxWidth = Threshold - 1;
             }
         }
 
-        if (filter.SeriesStatuses.Length > 0)
+        if (minWidth.HasValue)
         {
-            var seriesStatus = filter.SeriesStatuses.Select(e => e.ToString()).ToArray();
-            baseQuery = baseQuery
-                .Where(e => seriesStatus.Any(f => e.Data!.Contains(f)));
+            baseQuery = baseQuery.Where(e => e.Width >= minWidth);
         }
 
-        if (filter.BoxSetLibraryFolders.Length > 0)
+        if (filter.MinHeight.HasValue)
         {
-            var boxsetFolders = filter.BoxSetLibraryFolders.Select(e => e.ToString("N", CultureInfo.InvariantCulture)).ToArray();
-            baseQuery = baseQuery
-                .Where(e => boxsetFolders.Any(f => e.Data!.Contains(f)));
+            baseQuery = baseQuery.Where(e => e.Height >= filter.MinHeight);
         }
 
-        if (filter.VideoTypes.Length > 0)
+        if (maxWidth.HasValue)
         {
-            var videoTypeBs = filter.VideoTypes.Select(e => $"\"VideoType\":\"{e}\"");
-            baseQuery = baseQuery
-                .Where(e => videoTypeBs.Any(f => e.Data!.Contains(f)));
+            baseQuery = baseQuery.Where(e => e.Width >= maxWidth);
         }
 
-        if (filter.Is3D.HasValue)
+        if (filter.MaxHeight.HasValue)
         {
-            if (filter.Is3D.Value)
-            {
-                baseQuery = baseQuery
-                    .Where(e => e.Data!.Contains("Video3DFormat"));
-            }
-            else
+            baseQuery = baseQuery.Where(e => e.Height <= filter.MaxHeight);
+        }
+
+        if (filter.IsLocked.HasValue)
+        {
+            baseQuery = baseQuery.Where(e => e.IsLocked == filter.IsLocked);
+        }
+
+        var tags = filter.Tags.ToList();
+        var excludeTags = filter.ExcludeTags.ToList();
+
+        if (filter.IsMovie == true)
+        {
+            if (filter.IncludeItemTypes.Length == 0
+                || filter.IncludeItemTypes.Contains(BaseItemKind.Movie)
+                || filter.IncludeItemTypes.Contains(BaseItemKind.Trailer))
             {
-                baseQuery = baseQuery
-                    .Where(e => !e.Data!.Contains("Video3DFormat"));
+                baseQuery = baseQuery.Where(e => e.IsMovie);
             }
         }
+        else if (filter.IsMovie.HasValue)
+        {
+            baseQuery = baseQuery.Where(e => e.IsMovie == filter.IsMovie);
+        }
 
-        if (filter.IsPlaceHolder.HasValue)
+        if (filter.IsSeries.HasValue)
         {
-            if (filter.IsPlaceHolder.Value)
+            baseQuery = baseQuery.Where(e => e.IsSeries == filter.IsSeries);
+        }
+
+        if (filter.IsSports.HasValue)
+        {
+            if (filter.IsSports.Value)
             {
-                baseQuery = baseQuery
-                    .Where(e => e.Data!.Contains("IsPlaceHolder\":true"));
+                tags.Add("Sports");
             }
             else
             {
-                baseQuery = baseQuery
-                    .Where(e => !e.Data!.Contains("IsPlaceHolder\":true"));
+                excludeTags.Add("Sports");
             }
         }
 
-        if (filter.HasSpecialFeature.HasValue)
+        if (filter.IsNews.HasValue)
         {
-            if (filter.HasSpecialFeature.Value)
+            if (filter.IsNews.Value)
             {
-                baseQuery = baseQuery
-                    .Where(e => e.ExtraIds != null);
+                tags.Add("News");
             }
             else
             {
-                baseQuery = baseQuery
-                    .Where(e => e.ExtraIds == null);
+                excludeTags.Add("News");
             }
         }
 
-        if (filter.HasTrailer.HasValue || filter.HasThemeSong.HasValue || filter.HasThemeVideo.HasValue)
+        if (filter.IsKids.HasValue)
         {
-            if (filter.HasTrailer.GetValueOrDefault() || filter.HasThemeSong.GetValueOrDefault() || filter.HasThemeVideo.GetValueOrDefault())
+            if (filter.IsKids.Value)
             {
-                baseQuery = baseQuery
-                    .Where(e => e.ExtraIds != null);
+                tags.Add("Kids");
             }
             else
             {
-                baseQuery = baseQuery
-                    .Where(e => e.ExtraIds == null);
+                excludeTags.Add("Kids");
             }
         }
 
-        return baseQuery;
-    }
-
-    /// <summary>
-    /// Gets the type.
-    /// </summary>
-    /// <param name="typeName">Name of the type.</param>
-    /// <returns>Type.</returns>
-    /// <exception cref="ArgumentNullException"><c>typeName</c> is null.</exception>
-    private static Type? GetType(string typeName)
-    {
-        ArgumentException.ThrowIfNullOrEmpty(typeName);
-
-        return _typeMap.GetOrAdd(typeName, k => AppDomain.CurrentDomain.GetAssemblies()
-            .Select(a => a.GetType(k))
-            .FirstOrDefault(t => t is not null));
-    }
-
-    /// <inheritdoc cref="IItemRepository" />
-    public void SaveImages(BaseItemDto item)
-    {
-        ArgumentNullException.ThrowIfNull(item);
-
-        var images = item.ImageInfos.Select(e => Map(item.Id, e));
-        using var context = dbProvider.CreateDbContext();
-        using var transaction = context.Database.BeginTransaction();
-        context.BaseItemImageInfos.Where(e => e.ItemId == item.Id).ExecuteDelete();
-        context.BaseItemImageInfos.AddRange(images);
-        context.SaveChanges();
-        transaction.Commit();
-    }
-
-    /// <inheritdoc cref="IItemRepository" />
-    public void SaveItems(IReadOnlyList<BaseItemDto> items, CancellationToken cancellationToken)
-    {
-        UpdateOrInsertItems(items, cancellationToken);
-    }
-
-    /// <inheritdoc cref="IItemRepository" />
-    public void UpdateOrInsertItems(IReadOnlyList<BaseItemDto> items, CancellationToken cancellationToken)
-    {
-        ArgumentNullException.ThrowIfNull(items);
-        cancellationToken.ThrowIfCancellationRequested();
-
-        var itemsLen = items.Count;
-        var tuples = new (BaseItemDto Item, List<Guid>? AncestorIds, BaseItemDto TopParent, string? UserDataKey, List<string> InheritedTags)[itemsLen];
-        for (int i = 0; i < itemsLen; i++)
+        if (!string.IsNullOrEmpty(filter.SearchTerm))
         {
-            var item = items[i];
-            var ancestorIds = item.SupportsAncestors ?
-                item.GetAncestorIds().Distinct().ToList() :
-                null;
-
-            var topParent = item.GetTopParent();
-
-            var userdataKey = item.GetUserDataKeys().FirstOrDefault();
-            var inheritedTags = item.GetInheritedTags();
-
-            tuples[i] = (item, ancestorIds, topParent, userdataKey, inheritedTags);
+            baseQuery = baseQuery.Where(e => e.CleanName!.Contains(filter.SearchTerm) || (e.OriginalTitle != null && e.OriginalTitle.Contains(filter.SearchTerm)));
         }
 
-        using var context = dbProvider.CreateDbContext();
-        using var transaction = context.Database.BeginTransaction();
-        foreach (var item in tuples)
+        if (filter.IsFolder.HasValue)
         {
-            var entity = Map(item.Item);
-            // TODO: refactor this "inconsistency"
-            entity.TopParentId = item.TopParent?.Id;
-
-            if (!context.BaseItems.Any(e => e.Id == entity.Id))
-            {
-                context.BaseItems.Add(entity);
-            }
-            else
-            {
-                context.BaseItemProviders.Where(e => e.ItemId == entity.Id).ExecuteDelete();
-                context.BaseItems.Attach(entity).State = EntityState.Modified;
-            }
+            baseQuery = baseQuery.Where(e => e.IsFolder == filter.IsFolder);
+        }
 
-            context.AncestorIds.Where(e => e.ItemId == entity.Id).ExecuteDelete();
-            if (item.Item.SupportsAncestors && item.AncestorIds != null)
+        var includeTypes = filter.IncludeItemTypes;
+        // Only specify excluded types if no included types are specified
+        if (filter.IncludeItemTypes.Length == 0)
+        {
+            var excludeTypes = filter.ExcludeItemTypes;
+            if (excludeTypes.Length == 1)
             {
-                foreach (var ancestorId in item.AncestorIds)
+                if (itemTypeLookup.BaseItemKindNames.TryGetValue(excludeTypes[0], out var excludeTypeName))
                 {
-                    if (!context.BaseItems.Any(f => f.Id == ancestorId))
-                    {
-                        continue;
-                    }
-
-                    context.AncestorIds.Add(new AncestorId()
-                    {
-                        ParentItemId = ancestorId,
-                        ItemId = entity.Id,
-                        Item = null!,
-                        ParentItem = null!
-                    });
+                    baseQuery = baseQuery.Where(e => e.Type != excludeTypeName);
                 }
             }
-
-            // Never save duplicate itemValues as they are now mapped anyway.
-            var itemValuesToSave = GetItemValuesToSave(item.Item, item.InheritedTags).DistinctBy(e => (GetCleanValue(e.Value), e.MagicNumber));
-            context.ItemValuesMap.Where(e => e.ItemId == entity.Id).ExecuteDelete();
-            foreach (var itemValue in itemValuesToSave)
+            else if (excludeTypes.Length > 1)
             {
-                var refValue = context.ItemValues
-                    .Where(f => f.CleanValue == GetCleanValue(itemValue.Value) && (int)f.Type == itemValue.MagicNumber)
-                    .Select(e => e.ItemValueId)
-                    .FirstOrDefault();
-                if (refValue.IsEmpty())
+                var excludeTypeName = new List<string>();
+                foreach (var excludeType in excludeTypes)
                 {
-                    context.ItemValues.Add(new ItemValue()
+                    if (itemTypeLookup.BaseItemKindNames.TryGetValue(excludeType, out var baseItemKindName))
                     {
-                        CleanValue = GetCleanValue(itemValue.Value),
-                        Type = (ItemValueType)itemValue.MagicNumber,
-                        ItemValueId = refValue = Guid.NewGuid(),
-                        Value = itemValue.Value
-                    });
+                        excludeTypeName.Add(baseItemKindName!);
+                    }
                 }
 
-                context.ItemValuesMap.Add(new ItemValueMap()
-                {
-                    Item = null!,
-                    ItemId = entity.Id,
-                    ItemValue = null!,
-                    ItemValueId = refValue
-                });
+                baseQuery = baseQuery.Where(e => !excludeTypeName.Contains(e.Type));
             }
         }
-
-        context.SaveChanges();
-        transaction.Commit();
-    }
-
-    /// <inheritdoc cref="IItemRepository" />
-    public BaseItemDto? RetrieveItem(Guid id)
-    {
-        if (id.IsEmpty())
+        else if (includeTypes.Length == 1)
         {
-            throw new ArgumentException("Guid can't be empty", nameof(id));
-        }
-
-        using var context = dbProvider.CreateDbContext();
-        var item = PrepareItemQuery(context, new()
+            if (itemTypeLookup.BaseItemKindNames.TryGetValue(includeTypes[0], out var includeTypeName))
+            {
+                baseQuery = baseQuery.Where(e => e.Type == includeTypeName);
+            }
+        }
+        else if (includeTypes.Length > 1)
         {
-            DtoOptions = new()
+            var includeTypeName = new List<string>();
+            foreach (var includeType in includeTypes)
             {
-                EnableImages = true
+                if (itemTypeLookup.BaseItemKindNames.TryGetValue(includeType, out var baseItemKindName))
+                {
+                    includeTypeName.Add(baseItemKindName!);
+                }
             }
-        }).FirstOrDefault(e => e.Id == id);
-        if (item is null)
-        {
-            return null;
+
+            baseQuery = baseQuery.Where(e => includeTypeName.Contains(e.Type));
         }
 
-        return DeserialiseBaseItem(item);
-    }
+        if (filter.ChannelIds.Count > 0)
+        {
+            var channelIds = filter.ChannelIds.Select(e => e.ToString("N", CultureInfo.InvariantCulture)).ToArray();
+            baseQuery = baseQuery.Where(e => channelIds.Contains(e.ChannelId));
+        }
 
-    /// <summary>
-    /// Maps a Entity to the DTO.
-    /// </summary>
-    /// <param name="entity">The entity.</param>
-    /// <param name="dto">The dto base instance.</param>
-    /// <param name="appHost">The Application server Host.</param>
-    /// <returns>The dto to map.</returns>
-    public static BaseItemDto Map(BaseItemEntity entity, BaseItemDto dto, IServerApplicationHost? appHost)
-    {
-        dto.Id = entity.Id;
-        dto.ParentId = entity.ParentId.GetValueOrDefault();
-        dto.Path = appHost?.ExpandVirtualPath(entity.Path) ?? entity.Path;
-        dto.EndDate = entity.EndDate;
-        dto.CommunityRating = entity.CommunityRating;
-        dto.CustomRating = entity.CustomRating;
-        dto.IndexNumber = entity.IndexNumber;
-        dto.IsLocked = entity.IsLocked;
-        dto.Name = entity.Name;
-        dto.OfficialRating = entity.OfficialRating;
-        dto.Overview = entity.Overview;
-        dto.ParentIndexNumber = entity.ParentIndexNumber;
-        dto.PremiereDate = entity.PremiereDate;
-        dto.ProductionYear = entity.ProductionYear;
-        dto.SortName = entity.SortName;
-        dto.ForcedSortName = entity.ForcedSortName;
-        dto.RunTimeTicks = entity.RunTimeTicks;
-        dto.PreferredMetadataLanguage = entity.PreferredMetadataLanguage;
-        dto.PreferredMetadataCountryCode = entity.PreferredMetadataCountryCode;
-        dto.IsInMixedFolder = entity.IsInMixedFolder;
-        dto.InheritedParentalRatingValue = entity.InheritedParentalRatingValue;
-        dto.CriticRating = entity.CriticRating;
-        dto.PresentationUniqueKey = entity.PresentationUniqueKey;
-        dto.OriginalTitle = entity.OriginalTitle;
-        dto.Album = entity.Album;
-        dto.LUFS = entity.LUFS;
-        dto.NormalizationGain = entity.NormalizationGain;
-        dto.IsVirtualItem = entity.IsVirtualItem;
-        dto.ExternalSeriesId = entity.ExternalSeriesId;
-        dto.Tagline = entity.Tagline;
-        dto.TotalBitrate = entity.TotalBitrate;
-        dto.ExternalId = entity.ExternalId;
-        dto.Size = entity.Size;
-        dto.Genres = entity.Genres?.Split('|') ?? [];
-        dto.DateCreated = entity.DateCreated.GetValueOrDefault();
-        dto.DateModified = entity.DateModified.GetValueOrDefault();
-        dto.ChannelId = string.IsNullOrWhiteSpace(entity.ChannelId) ? Guid.Empty : (Guid.TryParse(entity.ChannelId, out var channelId) ? channelId : Guid.Empty);
-        dto.DateLastRefreshed = entity.DateLastRefreshed.GetValueOrDefault();
-        dto.DateLastSaved = entity.DateLastSaved.GetValueOrDefault();
-        dto.OwnerId = string.IsNullOrWhiteSpace(entity.OwnerId) ? Guid.Empty : (Guid.TryParse(entity.OwnerId, out var ownerId) ? ownerId : Guid.Empty);
-        dto.Width = entity.Width.GetValueOrDefault();
-        dto.Height = entity.Height.GetValueOrDefault();
-        if (entity.Provider is not null)
+        if (!filter.ParentId.IsEmpty())
         {
-            dto.ProviderIds = entity.Provider.ToDictionary(e => e.ProviderId, e => e.ProviderValue);
+            baseQuery = baseQuery.Where(e => e.ParentId!.Value == filter.ParentId);
         }
 
-        if (entity.ExtraType is not null)
+        if (!string.IsNullOrWhiteSpace(filter.Path))
         {
-            dto.ExtraType = (ExtraType)entity.ExtraType;
+            baseQuery = baseQuery.Where(e => e.Path == filter.Path);
         }
 
-        if (entity.LockedFields is not null)
+        if (!string.IsNullOrWhiteSpace(filter.PresentationUniqueKey))
         {
-            dto.LockedFields = entity.LockedFields?.Select(e => (MetadataField)e.Id).ToArray() ?? [];
+            baseQuery = baseQuery.Where(e => e.PresentationUniqueKey == filter.PresentationUniqueKey);
         }
 
-        if (entity.Audio is not null)
+        if (filter.MinCommunityRating.HasValue)
         {
-            dto.Audio = (ProgramAudio)entity.Audio;
+            baseQuery = baseQuery.Where(e => e.CommunityRating >= filter.MinCommunityRating);
         }
 
-        dto.ExtraIds = string.IsNullOrWhiteSpace(entity.ExtraIds) ? [] : entity.ExtraIds.Split('|').Select(e => Guid.Parse(e)).ToArray();
-        dto.ProductionLocations = entity.ProductionLocations?.Split('|') ?? [];
-        dto.Studios = entity.Studios?.Split('|') ?? [];
-        dto.Tags = entity.Tags?.Split('|') ?? [];
+        if (filter.MinIndexNumber.HasValue)
+        {
+            baseQuery = baseQuery.Where(e => e.IndexNumber >= filter.MinIndexNumber);
+        }
 
-        if (dto is IHasProgramAttributes hasProgramAttributes)
+        if (filter.MinParentAndIndexNumber.HasValue)
         {
-            hasProgramAttributes.IsMovie = entity.IsMovie;
-            hasProgramAttributes.IsSeries = entity.IsSeries;
-            hasProgramAttributes.EpisodeTitle = entity.EpisodeTitle;
-            hasProgramAttributes.IsRepeat = entity.IsRepeat;
+            baseQuery = baseQuery
+                .Where(e => (e.ParentIndexNumber == filter.MinParentAndIndexNumber.Value.ParentIndexNumber && e.IndexNumber >= filter.MinParentAndIndexNumber.Value.IndexNumber) || e.ParentIndexNumber > filter.MinParentAndIndexNumber.Value.ParentIndexNumber);
         }
 
-        if (dto is LiveTvChannel liveTvChannel)
+        if (filter.MinDateCreated.HasValue)
         {
-            liveTvChannel.ServiceName = entity.ExternalServiceId;
+            baseQuery = baseQuery.Where(e => e.DateCreated >= filter.MinDateCreated);
         }
 
-        if (dto is Trailer trailer)
+        if (filter.MinDateLastSaved.HasValue)
         {
-            trailer.TrailerTypes = entity.TrailerTypes?.Select(e => (TrailerType)e.Id).ToArray() ?? [];
+            baseQuery = baseQuery.Where(e => e.DateLastSaved != null && e.DateLastSaved >= filter.MinDateLastSaved.Value);
         }
 
-        if (dto is Video video)
+        if (filter.MinDateLastSavedForUser.HasValue)
         {
-            video.PrimaryVersionId = entity.PrimaryVersionId;
+            baseQuery = baseQuery.Where(e => e.DateLastSaved != null && e.DateLastSaved >= filter.MinDateLastSavedForUser.Value);
         }
 
-        if (dto is IHasSeries hasSeriesName)
+        if (filter.IndexNumber.HasValue)
         {
-            hasSeriesName.SeriesName = entity.SeriesName;
-            hasSeriesName.SeriesId = entity.SeriesId.GetValueOrDefault();
-            hasSeriesName.SeriesPresentationUniqueKey = entity.SeriesPresentationUniqueKey;
+            baseQuery = baseQuery.Where(e => e.IndexNumber == filter.IndexNumber.Value);
         }
 
-        if (dto is Episode episode)
+        if (filter.ParentIndexNumber.HasValue)
         {
-            episode.SeasonName = entity.SeasonName;
-            episode.SeasonId = entity.SeasonId.GetValueOrDefault();
+            baseQuery = baseQuery.Where(e => e.ParentIndexNumber == filter.ParentIndexNumber.Value);
         }
 
-        if (dto is IHasArtist hasArtists)
+        if (filter.ParentIndexNumberNotEquals.HasValue)
         {
-            hasArtists.Artists = entity.Artists?.Split('|', StringSplitOptions.RemoveEmptyEntries) ?? [];
+            baseQuery = baseQuery.Where(e => e.ParentIndexNumber != filter.ParentIndexNumberNotEquals.Value || e.ParentIndexNumber == null);
         }
 
-        if (dto is IHasAlbumArtist hasAlbumArtists)
+        var minEndDate = filter.MinEndDate;
+        var maxEndDate = filter.MaxEndDate;
+
+        if (filter.HasAired.HasValue)
         {
-            hasAlbumArtists.AlbumArtists = entity.AlbumArtists?.Split('|', StringSplitOptions.RemoveEmptyEntries) ?? [];
+            if (filter.HasAired.Value)
+            {
+                maxEndDate = DateTime.UtcNow;
+            }
+            else
+            {
+                minEndDate = DateTime.UtcNow;
+            }
         }
 
-        if (dto is LiveTvProgram program)
+        if (minEndDate.HasValue)
         {
-            program.ShowId = entity.ShowId;
+            baseQuery = baseQuery.Where(e => e.EndDate >= minEndDate);
         }
 
-        if (entity.Images is not null)
+        if (maxEndDate.HasValue)
         {
-            dto.ImageInfos = entity.Images.Select(e => Map(e, appHost)).ToArray();
+            baseQuery = baseQuery.Where(e => e.EndDate <= maxEndDate);
         }
 
-        // dto.Type = entity.Type;
-        // dto.Data = entity.Data;
-        // dto.MediaType = Enum.TryParse<MediaType>(entity.MediaType);
-        if (dto is IHasStartDate hasStartDate)
+        if (filter.MinStartDate.HasValue)
         {
-            hasStartDate.StartDate = entity.StartDate;
+            baseQuery = baseQuery.Where(e => e.StartDate >= filter.MinStartDate.Value);
         }
 
-        // Fields that are present in the DB but are never actually used
-        // dto.UnratedType = entity.UnratedType;
-        // dto.TopParentId = entity.TopParentId;
-        // dto.CleanName = entity.CleanName;
-        // dto.UserDataKey = entity.UserDataKey;
+        if (filter.MaxStartDate.HasValue)
+        {
+            baseQuery = baseQuery.Where(e => e.StartDate <= filter.MaxStartDate.Value);
+        }
 
-        if (dto is Folder folder)
+        if (filter.MinPremiereDate.HasValue)
         {
-            folder.DateLastMediaAdded = entity.DateLastMediaAdded;
+            baseQuery = baseQuery.Where(e => e.PremiereDate <= filter.MinPremiereDate.Value);
         }
 
-        return dto;
-    }
+        if (filter.MaxPremiereDate.HasValue)
+        {
+            baseQuery = baseQuery.Where(e => e.PremiereDate <= filter.MaxPremiereDate.Value);
+        }
 
-    /// <summary>
-    /// Maps a Entity to the DTO.
-    /// </summary>
-    /// <param name="dto">The entity.</param>
-    /// <returns>The dto to map.</returns>
-    public BaseItemEntity Map(BaseItemDto dto)
-    {
-        var dtoType = dto.GetType();
-        var entity = new BaseItemEntity()
+        if (filter.TrailerTypes.Length > 0)
         {
-            Type = dtoType.ToString(),
-            Id = dto.Id
-        };
+            var trailerTypes = filter.TrailerTypes.Select(e => (int)e).ToArray();
+            baseQuery = baseQuery.Where(e => trailerTypes.Any(f => e.TrailerTypes!.Any(w => w.Id == f)));
+        }
 
-        if (TypeRequiresDeserialization(dtoType))
+        if (filter.IsAiring.HasValue)
         {
-            entity.Data = JsonSerializer.Serialize(dto, dtoType, JsonDefaults.Options);
+            if (filter.IsAiring.Value)
+            {
+                baseQuery = baseQuery.Where(e => e.StartDate <= now && e.EndDate >= now);
+            }
+            else
+            {
+                baseQuery = baseQuery.Where(e => e.StartDate > now && e.EndDate < now);
+            }
         }
 
-        entity.ParentId = !dto.ParentId.IsEmpty() ? dto.ParentId : null;
-        entity.Path = GetPathToSave(dto.Path);
-        entity.EndDate = dto.EndDate.GetValueOrDefault();
-        entity.CommunityRating = dto.CommunityRating;
-        entity.CustomRating = dto.CustomRating;
-        entity.IndexNumber = dto.IndexNumber;
-        entity.IsLocked = dto.IsLocked;
-        entity.Name = dto.Name;
-        entity.OfficialRating = dto.OfficialRating;
-        entity.Overview = dto.Overview;
-        entity.ParentIndexNumber = dto.ParentIndexNumber;
-        entity.PremiereDate = dto.PremiereDate;
-        entity.ProductionYear = dto.ProductionYear;
-        entity.SortName = dto.SortName;
-        entity.ForcedSortName = dto.ForcedSortName;
-        entity.RunTimeTicks = dto.RunTimeTicks;
-        entity.PreferredMetadataLanguage = dto.PreferredMetadataLanguage;
-        entity.PreferredMetadataCountryCode = dto.PreferredMetadataCountryCode;
-        entity.IsInMixedFolder = dto.IsInMixedFolder;
-        entity.InheritedParentalRatingValue = dto.InheritedParentalRatingValue;
-        entity.CriticRating = dto.CriticRating;
-        entity.PresentationUniqueKey = dto.PresentationUniqueKey;
-        entity.OriginalTitle = dto.OriginalTitle;
-        entity.Album = dto.Album;
-        entity.LUFS = dto.LUFS;
-        entity.NormalizationGain = dto.NormalizationGain;
-        entity.IsVirtualItem = dto.IsVirtualItem;
-        entity.ExternalSeriesId = dto.ExternalSeriesId;
-        entity.Tagline = dto.Tagline;
-        entity.TotalBitrate = dto.TotalBitrate;
-        entity.ExternalId = dto.ExternalId;
-        entity.Size = dto.Size;
-        entity.Genres = string.Join('|', dto.Genres);
-        entity.DateCreated = dto.DateCreated;
-        entity.DateModified = dto.DateModified;
-        entity.ChannelId = dto.ChannelId.ToString();
-        entity.DateLastRefreshed = dto.DateLastRefreshed;
-        entity.DateLastSaved = dto.DateLastSaved;
-        entity.OwnerId = dto.OwnerId.ToString();
-        entity.Width = dto.Width;
-        entity.Height = dto.Height;
-        entity.Provider = dto.ProviderIds.Select(e => new BaseItemProvider()
+        if (filter.PersonIds.Length > 0)
+        {
+            baseQuery = baseQuery
+                .Where(e =>
+                    context.PeopleBaseItemMap.Where(w => context.BaseItems.Where(r => filter.PersonIds.Contains(r.Id)).Any(f => f.Name == w.People.Name))
+                        .Any(f => f.ItemId == e.Id));
+        }
+
+        if (!string.IsNullOrWhiteSpace(filter.Person))
         {
-            Item = entity,
-            ProviderId = e.Key,
-            ProviderValue = e.Value
-        }).ToList();
+            baseQuery = baseQuery.Where(e => e.Peoples!.Any(f => f.People.Name == filter.Person));
+        }
 
-        if (dto.Audio.HasValue)
+        if (!string.IsNullOrWhiteSpace(filter.MinSortName))
         {
-            entity.Audio = (ProgramAudioEntity)dto.Audio;
+            // this does not makes sense.
+            // baseQuery = baseQuery.Where(e => e.SortName >= query.MinSortName);
+            // whereClauses.Add("SortName>=@MinSortName");
+            // statement?.TryBind("@MinSortName", query.MinSortName);
         }
 
-        if (dto.ExtraType.HasValue)
+        if (!string.IsNullOrWhiteSpace(filter.ExternalSeriesId))
         {
-            entity.ExtraType = (BaseItemExtraType)dto.ExtraType;
+            baseQuery = baseQuery.Where(e => e.ExternalSeriesId == filter.ExternalSeriesId);
         }
 
-        entity.ExtraIds = dto.ExtraIds is not null ? string.Join('|', dto.ExtraIds) : null;
-        entity.ProductionLocations = dto.ProductionLocations is not null ? string.Join('|', dto.ProductionLocations) : null;
-        entity.Studios = dto.Studios is not null ? string.Join('|', dto.Studios) : null;
-        entity.Tags = dto.Tags is not null ? string.Join('|', dto.Tags) : null;
-        entity.LockedFields = dto.LockedFields is not null ? dto.LockedFields
-            .Select(e => new BaseItemMetadataField()
-            {
-                Id = (int)e,
-                Item = entity,
-                ItemId = entity.Id
-            })
-            .ToArray() : null;
+        if (!string.IsNullOrWhiteSpace(filter.ExternalId))
+        {
+            baseQuery = baseQuery.Where(e => e.ExternalId == filter.ExternalId);
+        }
 
-        if (dto is IHasProgramAttributes hasProgramAttributes)
+        if (!string.IsNullOrWhiteSpace(filter.Name))
         {
-            entity.IsMovie = hasProgramAttributes.IsMovie;
-            entity.IsSeries = hasProgramAttributes.IsSeries;
-            entity.EpisodeTitle = hasProgramAttributes.EpisodeTitle;
-            entity.IsRepeat = hasProgramAttributes.IsRepeat;
+            var cleanName = GetCleanValue(filter.Name);
+            baseQuery = baseQuery.Where(e => e.CleanName == cleanName);
         }
 
-        if (dto is LiveTvChannel liveTvChannel)
+        // These are the same, for now
+        var nameContains = filter.NameContains;
+        if (!string.IsNullOrWhiteSpace(nameContains))
         {
-            entity.ExternalServiceId = liveTvChannel.ServiceName;
+            baseQuery = baseQuery.Where(e =>
+                e.CleanName == filter.NameContains
+                || e.OriginalTitle!.Contains(filter.NameContains!));
         }
 
-        if (dto is Video video)
+        if (!string.IsNullOrWhiteSpace(filter.NameStartsWith))
         {
-            entity.PrimaryVersionId = video.PrimaryVersionId;
+            baseQuery = baseQuery.Where(e => e.SortName!.StartsWith(filter.NameStartsWith) || e.Name!.StartsWith(filter.NameStartsWith));
         }
 
-        if (dto is IHasSeries hasSeriesName)
+        if (!string.IsNullOrWhiteSpace(filter.NameStartsWithOrGreater))
         {
-            entity.SeriesName = hasSeriesName.SeriesName;
-            entity.SeriesId = hasSeriesName.SeriesId;
-            entity.SeriesPresentationUniqueKey = hasSeriesName.SeriesPresentationUniqueKey;
+            // i hate this
+            baseQuery = baseQuery.Where(e => e.SortName!.FirstOrDefault() > filter.NameStartsWithOrGreater[0] || e.Name!.FirstOrDefault() > filter.NameStartsWithOrGreater[0]);
         }
 
-        if (dto is Episode episode)
+        if (!string.IsNullOrWhiteSpace(filter.NameLessThan))
         {
-            entity.SeasonName = episode.SeasonName;
-            entity.SeasonId = episode.SeasonId;
+            // i hate this
+            baseQuery = baseQuery.Where(e => e.SortName!.FirstOrDefault() < filter.NameLessThan[0] || e.Name!.FirstOrDefault() < filter.NameLessThan[0]);
         }
 
-        if (dto is IHasArtist hasArtists)
+        if (filter.ImageTypes.Length > 0)
         {
-            entity.Artists = hasArtists.Artists is not null ? string.Join('|', hasArtists.Artists) : null;
+            var imgTypes = filter.ImageTypes.Select(e => (ImageInfoImageType)e).ToArray();
+            baseQuery = baseQuery.Where(e => imgTypes.Any(f => e.Images!.Any(w => w.ImageType == f)));
         }
 
-        if (dto is IHasAlbumArtist hasAlbumArtists)
+        if (filter.IsLiked.HasValue)
         {
-            entity.AlbumArtists = hasAlbumArtists.AlbumArtists is not null ? string.Join('|', hasAlbumArtists.AlbumArtists) : null;
+            baseQuery = baseQuery
+                .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.Rating >= UserItemData.MinLikeValue);
         }
 
-        if (dto is LiveTvProgram program)
+        if (filter.IsFavoriteOrLiked.HasValue)
         {
-            entity.ShowId = program.ShowId;
+            baseQuery = baseQuery
+                .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.IsFavorite == filter.IsFavoriteOrLiked);
         }
 
-        if (dto.ImageInfos is not null)
+        if (filter.IsFavorite.HasValue)
         {
-            entity.Images = dto.ImageInfos.Select(f => Map(dto.Id, f)).ToArray();
+            baseQuery = baseQuery
+                .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.IsFavorite == filter.IsFavorite);
         }
 
-        if (dto is Trailer trailer)
+        if (filter.IsPlayed.HasValue)
         {
-            entity.TrailerTypes = trailer.TrailerTypes?.Select(e => new BaseItemTrailerType()
+            // We should probably figure this out for all folders, but for right now, this is the only place where we need it
+            if (filter.IncludeItemTypes.Length == 1 && filter.IncludeItemTypes[0] == BaseItemKind.Series)
             {
-                Id = (int)e,
-                Item = entity,
-                ItemId = entity.Id
-            }).ToArray() ?? [];
+                baseQuery = baseQuery.Where(e => context.BaseItems
+                    .Where(e => e.IsFolder == false && e.IsVirtualItem == false)
+                    .Where(f => f.UserData!.FirstOrDefault(e => e.UserId == filter.User!.Id && e.Played)!.Played)
+                    .Any(f => f.SeriesPresentationUniqueKey == e.PresentationUniqueKey) == filter.IsPlayed);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Select(e => new
+                    {
+                        IsPlayed = e.UserData!.Where(f => f.UserId == filter.User!.Id).Select(f => (bool?)f.Played).FirstOrDefault() ?? false,
+                        Item = e
+                    })
+                    .Where(e => e.IsPlayed == filter.IsPlayed)
+                    .Select(f => f.Item);
+            }
         }
 
-        // dto.Type = entity.Type;
-        // dto.Data = entity.Data;
-        entity.MediaType = dto.MediaType.ToString();
-        if (dto is IHasStartDate hasStartDate)
+        if (filter.IsResumable.HasValue)
         {
-            entity.StartDate = hasStartDate.StartDate;
+            if (filter.IsResumable.Value)
+            {
+                baseQuery = baseQuery
+                       .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.PlaybackPositionTicks > 0);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                       .Where(e => e.UserData!.FirstOrDefault(f => f.UserId == filter.User!.Id)!.PlaybackPositionTicks == 0);
+            }
         }
 
-        // Fields that are present in the DB but are never actually used
-        // dto.UnratedType = entity.UnratedType;
-        // dto.TopParentId = entity.TopParentId;
-        // dto.CleanName = entity.CleanName;
-        // dto.UserDataKey = entity.UserDataKey;
+        if (filter.ArtistIds.Length > 0)
+        {
+            baseQuery = baseQuery
+                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type <= ItemValueType.Artist && filter.ArtistIds.Contains(f.ItemId)));
+        }
 
-        if (dto is Folder folder)
+        if (filter.AlbumArtistIds.Length > 0)
         {
-            entity.DateLastMediaAdded = folder.DateLastMediaAdded;
-            entity.IsFolder = folder.IsFolder;
+            baseQuery = baseQuery
+                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Artist && filter.AlbumArtistIds.Contains(f.ItemId)));
         }
 
-        return entity;
-    }
+        if (filter.ContributingArtistIds.Length > 0)
+        {
+            baseQuery = baseQuery
+                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Artist && filter.ContributingArtistIds.Contains(f.ItemId)));
+        }
 
-    private IReadOnlyList<string> GetItemValueNames(ItemValueType[] itemValueTypes, IReadOnlyList<string> withItemTypes, IReadOnlyList<string> excludeItemTypes)
-    {
-        using var context = dbProvider.CreateDbContext();
+        if (filter.AlbumIds.Length > 0)
+        {
+            baseQuery = baseQuery.Where(e => context.BaseItems.Where(f => filter.AlbumIds.Contains(f.Id)).Any(f => f.Name == e.Album));
+        }
 
-        var query = context.ItemValuesMap
-            .AsNoTracking()
-            .Where(e => itemValueTypes.Any(w => (ItemValueType)w == e.ItemValue.Type));
-        if (withItemTypes.Count > 0)
+        if (filter.ExcludeArtistIds.Length > 0)
         {
-            query = query.Where(e => withItemTypes.Contains(e.Item.Type));
+            baseQuery = baseQuery
+                   .Where(e => !e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Artist && filter.ExcludeArtistIds.Contains(f.ItemId)));
         }
 
-        if (excludeItemTypes.Count > 0)
+        if (filter.GenreIds.Count > 0)
         {
-            query = query.Where(e => !excludeItemTypes.Contains(e.Item.Type));
+            baseQuery = baseQuery
+                   .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Genre && filter.GenreIds.Contains(f.ItemId)));
         }
 
-        // query = query.DistinctBy(e => e.CleanValue);
-        return query.Select(e => e.ItemValue.CleanValue).ToImmutableArray();
-    }
+        if (filter.Genres.Count > 0)
+        {
+            var cleanGenres = filter.Genres.Select(e => GetCleanValue(e)).ToArray();
+            baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Genre && cleanGenres.Contains(f.ItemValue.CleanValue)));
+        }
 
-    private static bool TypeRequiresDeserialization(Type type)
-    {
-        return type.GetCustomAttribute<RequiresSourceSerialisationAttribute>() == null;
-    }
+        if (tags.Count > 0)
+        {
+            var cleanValues = tags.Select(e => GetCleanValue(e)).ToArray();
+            baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Tags && cleanValues.Contains(f.ItemValue.CleanValue)));
+        }
 
-    private BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, bool skipDeserialization = false)
-    {
-        ArgumentNullException.ThrowIfNull(baseItemEntity, nameof(baseItemEntity));
-        if (serverConfigurationManager?.Configuration is null)
+        if (excludeTags.Count > 0)
         {
-            throw new InvalidOperationException("Server Configuration manager or configuration is null");
+            var cleanValues = excludeTags.Select(e => GetCleanValue(e)).ToArray();
+            baseQuery = baseQuery
+                    .Where(e => !e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Tags && cleanValues.Contains(f.ItemValue.CleanValue)));
         }
 
-        var typeToSerialise = GetType(baseItemEntity.Type);
-        return BaseItemRepository.DeserialiseBaseItem(
-            baseItemEntity,
-            logger,
-            appHost,
-            skipDeserialization || (serverConfigurationManager.Configuration.SkipDeserializationForBasicTypes && (typeToSerialise == typeof(Channel) || typeToSerialise == typeof(UserRootFolder))));
-    }
+        if (filter.StudioIds.Length > 0)
+        {
+            baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Any(f => f.ItemValue.Type == ItemValueType.Studios && filter.StudioIds.Contains(f.ItemId)));
+        }
 
-    /// <summary>
-    /// Deserialises a BaseItemEntity and sets all properties.
-    /// </summary>
-    /// <param name="baseItemEntity">The DB entity.</param>
-    /// <param name="logger">Logger.</param>
-    /// <param name="appHost">The application server Host.</param>
-    /// <param name="skipDeserialization">If only mapping should be processed.</param>
-    /// <returns>A mapped BaseItem.</returns>
-    /// <exception cref="InvalidOperationException">Will be thrown if an invalid serialisation is requested.</exception>
-    public static BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, ILogger logger, IServerApplicationHost? appHost, bool skipDeserialization = false)
-    {
-        var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
-        BaseItemDto? dto = null;
-        if (TypeRequiresDeserialization(type) && baseItemEntity.Data is not null && !skipDeserialization)
+        if (filter.OfficialRatings.Length > 0)
+        {
+            baseQuery = baseQuery
+                   .Where(e => filter.OfficialRatings.Contains(e.OfficialRating));
+        }
+
+        if (filter.HasParentalRating ?? false)
+        {
+            if (filter.MinParentalRating.HasValue)
+            {
+                baseQuery = baseQuery
+                   .Where(e => e.InheritedParentalRatingValue >= filter.MinParentalRating.Value);
+            }
+
+            if (filter.MaxParentalRating.HasValue)
+            {
+                baseQuery = baseQuery
+                   .Where(e => e.InheritedParentalRatingValue < filter.MaxParentalRating.Value);
+            }
+        }
+        else if (filter.BlockUnratedItems.Length > 0)
+        {
+            var unratedItems = filter.BlockUnratedItems.Select(f => f.ToString()).ToArray();
+            if (filter.MinParentalRating.HasValue)
+            {
+                if (filter.MaxParentalRating.HasValue)
+                {
+                    baseQuery = baseQuery
+                        .Where(e => (e.InheritedParentalRatingValue == null && !unratedItems.Contains(e.UnratedType))
+                        || (e.InheritedParentalRatingValue >= filter.MinParentalRating && e.InheritedParentalRatingValue <= filter.MaxParentalRating));
+                }
+                else
+                {
+                    baseQuery = baseQuery
+                        .Where(e => (e.InheritedParentalRatingValue == null && !unratedItems.Contains(e.UnratedType))
+                        || e.InheritedParentalRatingValue >= filter.MinParentalRating);
+                }
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.InheritedParentalRatingValue != null && !unratedItems.Contains(e.UnratedType));
+            }
+        }
+        else if (filter.MinParentalRating.HasValue)
         {
-            try
+            if (filter.MaxParentalRating.HasValue)
             {
-                using var dataAsStream = new MemoryStream(Encoding.UTF8.GetBytes(baseItemEntity.Data!));
-                dto = JsonSerializer.Deserialize(dataAsStream, type, JsonDefaults.Options) as BaseItemDto;
+                baseQuery = baseQuery
+                    .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MinParentalRating.Value && e.InheritedParentalRatingValue <= filter.MaxParentalRating.Value);
             }
-            catch (JsonException ex)
+            else
             {
-                logger.LogError(ex, "Error deserializing item with JSON: {Data}", baseItemEntity.Data);
+                baseQuery = baseQuery
+                    .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MinParentalRating.Value);
             }
         }
-
-        if (dto is null)
+        else if (filter.MaxParentalRating.HasValue)
         {
-            dto = Activator.CreateInstance(type) as BaseItemDto ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
+            baseQuery = baseQuery
+                .Where(e => e.InheritedParentalRatingValue != null && e.InheritedParentalRatingValue >= filter.MaxParentalRating.Value);
         }
-
-        return Map(baseItemEntity, dto, appHost);
-    }
-
-    private QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetItemValues(InternalItemsQuery filter, ItemValueType[] itemValueTypes, string returnType)
-    {
-        ArgumentNullException.ThrowIfNull(filter);
-
-        if (!filter.Limit.HasValue)
+        else if (!filter.HasParentalRating ?? false)
         {
-            filter.EnableTotalRecordCount = false;
+            baseQuery = baseQuery
+                .Where(e => e.InheritedParentalRatingValue == null);
         }
 
-        using var context = dbProvider.CreateDbContext();
-
-        var innerQuery = new InternalItemsQuery(filter.User)
-        {
-            ExcludeItemTypes = filter.ExcludeItemTypes,
-            IncludeItemTypes = filter.IncludeItemTypes,
-            MediaTypes = filter.MediaTypes,
-            AncestorIds = filter.AncestorIds,
-            ItemIds = filter.ItemIds,
-            TopParentIds = filter.TopParentIds,
-            ParentId = filter.ParentId,
-            IsAiring = filter.IsAiring,
-            IsMovie = filter.IsMovie,
-            IsSports = filter.IsSports,
-            IsKids = filter.IsKids,
-            IsNews = filter.IsNews,
-            IsSeries = filter.IsSeries
-        };
-        var query = TranslateQuery(context.BaseItems.AsNoTracking(), context, innerQuery);
-
-        query = query.Where(e => e.Type == returnType && e.ItemValues!.Any(f => e.CleanName == f.ItemValue.CleanValue && itemValueTypes.Any(w => (ItemValueType)w == f.ItemValue.Type)));
-
-        if (filter.OrderBy.Count != 0
-            || !string.IsNullOrEmpty(filter.SearchTerm))
+        if (filter.HasOfficialRating.HasValue)
         {
-            query = ApplyOrder(query, filter);
+            if (filter.HasOfficialRating.Value)
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.OfficialRating != null && e.OfficialRating != string.Empty);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty);
+            }
         }
-        else
+
+        if (filter.HasOverview.HasValue)
         {
-            query = query.OrderBy(e => e.SortName);
+            if (filter.HasOverview.Value)
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.Overview != null && e.Overview != string.Empty);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.Overview == null || e.Overview == string.Empty);
+            }
         }
 
-        if (filter.Limit.HasValue || filter.StartIndex.HasValue)
+        if (filter.HasOwnerId.HasValue)
         {
-            var offset = filter.StartIndex ?? 0;
-
-            if (offset > 0)
+            if (filter.HasOwnerId.Value)
             {
-                query = query.Skip(offset);
+                baseQuery = baseQuery
+                    .Where(e => e.OwnerId != null);
             }
-
-            if (filter.Limit.HasValue)
+            else
             {
-                query = query.Take(filter.Limit.Value);
+                baseQuery = baseQuery
+                    .Where(e => e.OwnerId == null);
             }
         }
 
-        var result = new QueryResult<(BaseItemDto, ItemCounts)>();
-        if (filter.EnableTotalRecordCount)
+        if (!string.IsNullOrWhiteSpace(filter.HasNoAudioTrackWithLanguage))
         {
-            result.TotalRecordCount = query.DistinctBy(e => e.PresentationUniqueKey).Count();
+            baseQuery = baseQuery
+                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Audio && f.Language == filter.HasNoAudioTrackWithLanguage));
         }
 
-        var seriesTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Series];
-        var movieTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie];
-        var episodeTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Episode];
-        var musicAlbumTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicAlbum];
-        var musicArtistTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist];
-        var audioTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Audio];
-        var trailerTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Trailer];
-
-        var resultQuery = query.Select(e => new
+        if (!string.IsNullOrWhiteSpace(filter.HasNoInternalSubtitleTrackWithLanguage))
         {
-            item = e,
-            // TODO: This is bad refactor!
-            itemCount = new ItemCounts()
-            {
-                SeriesCount = e.ItemValues!.Count(f => f.Item.Type == seriesTypeName),
-                EpisodeCount = e.ItemValues!.Count(f => f.Item.Type == episodeTypeName),
-                MovieCount = e.ItemValues!.Count(f => f.Item.Type == movieTypeName),
-                AlbumCount = e.ItemValues!.Count(f => f.Item.Type == musicAlbumTypeName),
-                ArtistCount = e.ItemValues!.Count(f => f.Item.Type == musicArtistTypeName),
-                SongCount = e.ItemValues!.Count(f => f.Item.Type == audioTypeName),
-                TrailerCount = e.ItemValues!.Count(f => f.Item.Type == trailerTypeName),
-            }
-        });
+            baseQuery = baseQuery
+                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle && !f.IsExternal && f.Language == filter.HasNoInternalSubtitleTrackWithLanguage));
+        }
 
-        result.StartIndex = filter.StartIndex ?? 0;
-        result.Items = resultQuery.ToImmutableArray().Where(e => e is not null).Select(e =>
+        if (!string.IsNullOrWhiteSpace(filter.HasNoExternalSubtitleTrackWithLanguage))
         {
-            return (DeserialiseBaseItem(e.item, filter.SkipDeserialization), e.itemCount);
-        }).ToImmutableArray();
-
-        return result;
-    }
+            baseQuery = baseQuery
+                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle && f.IsExternal && f.Language == filter.HasNoExternalSubtitleTrackWithLanguage));
+        }
 
-    private static void PrepareFilterQuery(InternalItemsQuery query)
-    {
-        if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
+        if (!string.IsNullOrWhiteSpace(filter.HasNoSubtitleTrackWithLanguage))
         {
-            query.Limit = query.Limit.Value + 4;
+            baseQuery = baseQuery
+                .Where(e => !e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle && f.Language == filter.HasNoSubtitleTrackWithLanguage));
         }
 
-        if (query.IsResumable ?? false)
+        if (filter.HasSubtitles.HasValue)
         {
-            query.IsVirtualItem = false;
+            baseQuery = baseQuery
+                .Where(e => e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle) == filter.HasSubtitles.Value);
         }
-    }
 
-    private string GetCleanValue(string value)
-    {
-        if (string.IsNullOrWhiteSpace(value))
+        if (filter.HasChapterImages.HasValue)
         {
-            return value;
+            baseQuery = baseQuery
+                .Where(e => e.Chapters!.Any(f => f.ImagePath != null) == filter.HasChapterImages.Value);
         }
 
-        return value.RemoveDiacritics().ToLowerInvariant();
-    }
-
-    private List<(int MagicNumber, string Value)> GetItemValuesToSave(BaseItemDto item, List<string> inheritedTags)
-    {
-        var list = new List<(int, string)>();
-
-        if (item is IHasArtist hasArtist)
+        if (filter.HasDeadParentId.HasValue && filter.HasDeadParentId.Value)
         {
-            list.AddRange(hasArtist.Artists.Select(i => (0, i)));
+            baseQuery = baseQuery
+                .Where(e => e.ParentId.HasValue && !context.BaseItems.Any(f => f.Id == e.ParentId.Value));
         }
 
-        if (item is IHasAlbumArtist hasAlbumArtist)
+        if (filter.IsDeadArtist.HasValue && filter.IsDeadArtist.Value)
         {
-            list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => (1, i)));
+            baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Count(f => f.ItemValue.Type == ItemValueType.Artist || f.ItemValue.Type == ItemValueType.AlbumArtist) == 1);
         }
 
-        list.AddRange(item.Genres.Select(i => (2, i)));
-        list.AddRange(item.Studios.Select(i => (3, i)));
-        list.AddRange(item.Tags.Select(i => (4, i)));
-
-        // keywords was 5
-
-        list.AddRange(inheritedTags.Select(i => (6, i)));
+        if (filter.IsDeadStudio.HasValue && filter.IsDeadStudio.Value)
+        {
+            baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Count(f => f.ItemValue.Type == ItemValueType.Studios) == 1);
+        }
 
-        // Remove all invalid values.
-        list.RemoveAll(i => string.IsNullOrWhiteSpace(i.Item2));
+        if (filter.IsDeadPerson.HasValue && filter.IsDeadPerson.Value)
+        {
+            baseQuery = baseQuery
+                .Where(e => !context.Peoples.Any(f => f.Name == e.Name));
+        }
 
-        return list;
-    }
+        if (filter.Years.Length == 1)
+        {
+            baseQuery = baseQuery
+                .Where(e => e.ProductionYear == filter.Years[0]);
+        }
+        else if (filter.Years.Length > 1)
+        {
+            baseQuery = baseQuery
+                .Where(e => filter.Years.Any(f => f == e.ProductionYear));
+        }
 
-    private static BaseItemImageInfo Map(Guid baseItemId, ItemImageInfo e)
-    {
-        return new BaseItemImageInfo()
+        var isVirtualItem = filter.IsVirtualItem ?? filter.IsMissing;
+        if (isVirtualItem.HasValue)
         {
-            ItemId = baseItemId,
-            Id = Guid.NewGuid(),
-            Path = e.Path,
-            Blurhash = e.BlurHash != null ? Encoding.UTF8.GetBytes(e.BlurHash) : null,
-            DateModified = e.DateModified,
-            Height = e.Height,
-            Width = e.Width,
-            ImageType = (ImageInfoImageType)e.Type,
-            Item = null!
-        };
-    }
+            baseQuery = baseQuery
+                .Where(e => e.IsVirtualItem == isVirtualItem.Value);
+        }
 
-    private static ItemImageInfo Map(BaseItemImageInfo e, IServerApplicationHost? appHost)
-    {
-        return new ItemImageInfo()
+        if (filter.IsSpecialSeason.HasValue)
         {
-            Path = appHost?.ExpandVirtualPath(e.Path) ?? e.Path,
-            BlurHash = e.Blurhash != null ? Encoding.UTF8.GetString(e.Blurhash) : null,
-            DateModified = e.DateModified,
-            Height = e.Height,
-            Width = e.Width,
-            Type = (ImageType)e.ImageType
-        };
-    }
+            if (filter.IsSpecialSeason.Value)
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.IndexNumber == 0);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.IndexNumber != 0);
+            }
+        }
 
-    private string? GetPathToSave(string path)
-    {
-        if (path is null)
+        if (filter.IsUnaired.HasValue)
         {
-            return null;
+            if (filter.IsUnaired.Value)
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.PremiereDate >= now);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.PremiereDate < now);
+            }
         }
 
-        return appHost.ReverseVirtualPath(path);
-    }
-
-    private List<string> GetItemByNameTypesInQuery(InternalItemsQuery query)
-    {
-        var list = new List<string>();
-
-        if (IsTypeInQuery(BaseItemKind.Person, query))
+        if (filter.MediaTypes.Length > 0)
         {
-            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.Person]!);
+            var mediaTypes = filter.MediaTypes.Select(f => f.ToString()).ToArray();
+            baseQuery = baseQuery
+                .Where(e => mediaTypes.Contains(e.MediaType));
         }
 
-        if (IsTypeInQuery(BaseItemKind.Genre, query))
+        if (filter.ItemIds.Length > 0)
         {
-            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.Genre]!);
+            baseQuery = baseQuery
+                .Where(e => filter.ItemIds.Contains(e.Id));
         }
 
-        if (IsTypeInQuery(BaseItemKind.MusicGenre, query))
+        if (filter.ExcludeItemIds.Length > 0)
         {
-            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicGenre]!);
+            baseQuery = baseQuery
+                .Where(e => !filter.ItemIds.Contains(e.Id));
         }
 
-        if (IsTypeInQuery(BaseItemKind.MusicArtist, query))
+        if (filter.ExcludeProviderIds is not null && filter.ExcludeProviderIds.Count > 0)
         {
-            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!);
+            baseQuery = baseQuery.Where(e => !e.Provider!.All(f => !filter.ExcludeProviderIds.All(w => f.ProviderId == w.Key && f.ProviderValue == w.Value)));
         }
 
-        if (IsTypeInQuery(BaseItemKind.Studio, query))
+        if (filter.HasAnyProviderId is not null && filter.HasAnyProviderId.Count > 0)
         {
-            list.Add(itemTypeLookup.BaseItemKindNames[BaseItemKind.Studio]!);
+            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => !filter.HasAnyProviderId.Any(w => f.ProviderId == w.Key && f.ProviderValue == w.Value)));
         }
 
-        return list;
-    }
-
-    private bool IsTypeInQuery(BaseItemKind type, InternalItemsQuery query)
-    {
-        if (query.ExcludeItemTypes.Contains(type))
+        if (filter.HasImdbId.HasValue)
         {
-            return false;
+            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => f.ProviderId == "imdb"));
         }
 
-        return query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(type);
-    }
+        if (filter.HasTmdbId.HasValue)
+        {
+            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => f.ProviderId == "tmdb"));
+        }
 
-    private Expression<Func<BaseItemEntity, object>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query)
-    {
-#pragma warning disable CS8603 // Possible null reference return.
-        return sortBy switch
+        if (filter.HasTvdbId.HasValue)
         {
-            ItemSortBy.AirTime => e => e.SortName, // TODO
-            ItemSortBy.Runtime => e => e.RunTimeTicks,
-            ItemSortBy.Random => e => EF.Functions.Random(),
-            ItemSortBy.DatePlayed => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.LastPlayedDate,
-            ItemSortBy.PlayCount => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.PlayCount,
-            ItemSortBy.IsFavoriteOrLiked => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.IsFavorite,
-            ItemSortBy.IsFolder => e => e.IsFolder,
-            ItemSortBy.IsPlayed => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.Played,
-            ItemSortBy.IsUnplayed => e => !e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.Played,
-            ItemSortBy.DateLastContentAdded => e => e.DateLastMediaAdded,
-            ItemSortBy.Artist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f => f.ItemValue.CleanValue),
-            ItemSortBy.AlbumArtist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).Select(f => f.ItemValue.CleanValue),
-            ItemSortBy.Studio => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f => f.ItemValue.CleanValue),
-            ItemSortBy.OfficialRating => e => e.InheritedParentalRatingValue,
-            // ItemSortBy.SeriesDatePlayed => "(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where Played=1 and B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)",
-            ItemSortBy.SeriesSortName => e => e.SeriesName,
-            // ItemSortBy.AiredEpisodeOrder => "AiredEpisodeOrder",
-            ItemSortBy.Album => e => e.Album,
-            ItemSortBy.DateCreated => e => e.DateCreated,
-            ItemSortBy.PremiereDate => e => e.PremiereDate,
-            ItemSortBy.StartDate => e => e.StartDate,
-            ItemSortBy.Name => e => e.Name,
-            ItemSortBy.CommunityRating => e => e.CommunityRating,
-            ItemSortBy.ProductionYear => e => e.ProductionYear,
-            ItemSortBy.CriticRating => e => e.CriticRating,
-            ItemSortBy.VideoBitRate => e => e.TotalBitrate,
-            ItemSortBy.ParentIndexNumber => e => e.ParentIndexNumber,
-            ItemSortBy.IndexNumber => e => e.IndexNumber,
-            _ => e => e.SortName
-        };
-#pragma warning restore CS8603 // Possible null reference return.
+            baseQuery = baseQuery.Where(e => e.Provider!.Any(f => f.ProviderId == "tvdb"));
+        }
 
-    }
+        var queryTopParentIds = filter.TopParentIds;
 
-    private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
-    {
-        if (!query.GroupByPresentationUniqueKey)
+        if (queryTopParentIds.Length > 0)
         {
-            return false;
+            var includedItemByNameTypes = GetItemByNameTypesInQuery(filter);
+            var enableItemsByName = (filter.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
+            if (enableItemsByName && includedItemByNameTypes.Count > 0)
+            {
+                baseQuery = baseQuery.Where(e => includedItemByNameTypes.Contains(e.Type) || queryTopParentIds.Any(w => w == e.TopParentId!.Value));
+            }
+            else
+            {
+                baseQuery = baseQuery.Where(e => queryTopParentIds.Contains(e.TopParentId!.Value));
+            }
         }
 
-        if (query.GroupBySeriesPresentationUniqueKey)
+        if (filter.AncestorIds.Length > 0)
         {
-            return false;
+            baseQuery = baseQuery.Where(e => e.Children!.Any(f => filter.AncestorIds.Contains(f.ParentItemId)));
         }
 
-        if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
+        if (!string.IsNullOrWhiteSpace(filter.AncestorWithPresentationUniqueKey))
         {
-            return false;
+            baseQuery = baseQuery
+                .Where(e => context.BaseItems.Where(f => f.PresentationUniqueKey == filter.AncestorWithPresentationUniqueKey).Any(f => f.ParentAncestors!.Any(w => w.ItemId == f.Id)));
         }
 
-        if (query.User is null)
+        if (!string.IsNullOrWhiteSpace(filter.SeriesPresentationUniqueKey))
         {
-            return false;
+            baseQuery = baseQuery
+                .Where(e => e.SeriesPresentationUniqueKey == filter.SeriesPresentationUniqueKey);
         }
 
-        if (query.IncludeItemTypes.Length == 0)
+        if (filter.ExcludeInheritedTags.Length > 0)
         {
-            return true;
+            baseQuery = baseQuery
+                .Where(e => !e.ItemValues!.Where(w => w.ItemValue.Type == ItemValueType.InheritedTags)
+                    .Any(f => filter.ExcludeInheritedTags.Contains(f.ItemValue.CleanValue)));
         }
 
-        return query.IncludeItemTypes.Contains(BaseItemKind.Episode)
-            || query.IncludeItemTypes.Contains(BaseItemKind.Video)
-            || query.IncludeItemTypes.Contains(BaseItemKind.Movie)
-            || query.IncludeItemTypes.Contains(BaseItemKind.MusicVideo)
-            || query.IncludeItemTypes.Contains(BaseItemKind.Series)
-            || query.IncludeItemTypes.Contains(BaseItemKind.Season);
-    }
-
-    private IQueryable<BaseItemEntity> ApplyOrder(IQueryable<BaseItemEntity> query, InternalItemsQuery filter)
-    {
-        var orderBy = filter.OrderBy;
-        bool hasSearch = !string.IsNullOrEmpty(filter.SearchTerm);
-
-        if (hasSearch)
+        if (filter.IncludeInheritedTags.Length > 0)
         {
-            List<(ItemSortBy, SortOrder)> prepend = new List<(ItemSortBy, SortOrder)>(4);
-            if (hasSearch)
+            // 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)
             {
-                prepend.Add((ItemSortBy.SortName, SortOrder.Ascending));
+                baseQuery = baseQuery
+                    .Where(e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.InheritedTags)
+                        .Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue))
+                        ||
+                        (e.ParentId.HasValue && context.ItemValuesMap.Where(w => w.ItemId == e.ParentId.Value)!.Where(w => w.ItemValue.Type == ItemValueType.InheritedTags)
+                        .Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue))));
             }
 
-            orderBy = filter.OrderBy = [.. prepend, .. orderBy];
+            // 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.ParentAncestors!
+                        .Any(f =>
+                            f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))
+                            || e.Data!.Contains($"OwnerUserId\":\"{filter.User!.Id:N}\"")));
+                // d        ^^ this is stupid it hate this.
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.ParentAncestors!.Any(f => f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))));
+            }
         }
-        else if (orderBy.Count == 0)
+
+        if (filter.SeriesStatuses.Length > 0)
         {
-            return query;
+            var seriesStatus = filter.SeriesStatuses.Select(e => e.ToString()).ToArray();
+            baseQuery = baseQuery
+                .Where(e => seriesStatus.Any(f => e.Data!.Contains(f)));
         }
 
-        IOrderedQueryable<BaseItemEntity>? orderedQuery = null;
+        if (filter.BoxSetLibraryFolders.Length > 0)
+        {
+            var boxsetFolders = filter.BoxSetLibraryFolders.Select(e => e.ToString("N", CultureInfo.InvariantCulture)).ToArray();
+            baseQuery = baseQuery
+                .Where(e => boxsetFolders.Any(f => e.Data!.Contains(f)));
+        }
 
-        var firstOrdering = orderBy.FirstOrDefault();
-        if (firstOrdering != default)
+        if (filter.VideoTypes.Length > 0)
         {
-            var expression = MapOrderByField(firstOrdering.OrderBy, filter);
-            if (firstOrdering.SortOrder == SortOrder.Ascending)
+            var videoTypeBs = filter.VideoTypes.Select(e => $"\"VideoType\":\"{e}\"");
+            baseQuery = baseQuery
+                .Where(e => videoTypeBs.Any(f => e.Data!.Contains(f)));
+        }
+
+        if (filter.Is3D.HasValue)
+        {
+            if (filter.Is3D.Value)
             {
-                orderedQuery = query.OrderBy(expression);
+                baseQuery = baseQuery
+                    .Where(e => e.Data!.Contains("Video3DFormat"));
             }
             else
             {
-                orderedQuery = query.OrderByDescending(expression);
+                baseQuery = baseQuery
+                    .Where(e => !e.Data!.Contains("Video3DFormat"));
             }
+        }
 
-            if (firstOrdering.OrderBy is ItemSortBy.Default or ItemSortBy.SortName)
+        if (filter.IsPlaceHolder.HasValue)
+        {
+            if (filter.IsPlaceHolder.Value)
             {
-                if (firstOrdering.SortOrder is SortOrder.Ascending)
-                {
-                    orderedQuery = orderedQuery.ThenBy(e => e.Name);
-                }
-                else
-                {
-                    orderedQuery = orderedQuery.ThenByDescending(e => e.Name);
-                }
+                baseQuery = baseQuery
+                    .Where(e => e.Data!.Contains("IsPlaceHolder\":true"));
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => !e.Data!.Contains("IsPlaceHolder\":true"));
             }
         }
 
-        foreach (var item in orderBy.Skip(1))
+        if (filter.HasSpecialFeature.HasValue)
         {
-            var expression = MapOrderByField(item.OrderBy, filter);
-            if (item.SortOrder == SortOrder.Ascending)
+            if (filter.HasSpecialFeature.Value)
             {
-                orderedQuery = orderedQuery!.ThenBy(expression);
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds != null);
             }
             else
             {
-                orderedQuery = orderedQuery!.ThenByDescending(expression);
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds == null);
             }
         }
 
-        return orderedQuery ?? query;
+        if (filter.HasTrailer.HasValue || filter.HasThemeSong.HasValue || filter.HasThemeVideo.HasValue)
+        {
+            if (filter.HasTrailer.GetValueOrDefault() || filter.HasThemeSong.GetValueOrDefault() || filter.HasThemeVideo.GetValueOrDefault())
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds != null);
+            }
+            else
+            {
+                baseQuery = baseQuery
+                    .Where(e => e.ExtraIds == null);
+            }
+        }
+
+        return baseQuery;
     }
 }