aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Server.Implementations/Item/BaseItemRepository.cs')
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.cs119
1 files changed, 102 insertions, 17 deletions
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index 52585c996..cf4f405ee 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -110,6 +110,20 @@ public sealed class BaseItemRepository
using var transaction = context.Database.BeginTransaction();
var date = (DateTime?)DateTime.UtcNow;
+
+ // Remove any UserData entries for the placeholder item that would conflict with the UserData
+ // being detached from the item being deleted. This is necessary because, during an update,
+ // UserData may be reattached to a new entry, but some entries can be left behind.
+ // Ensures there are no duplicate UserId/CustomDataKey combinations for the placeholder.
+ context.UserData
+ .Join(
+ context.UserData.Where(e => e.ItemId == id),
+ placeholder => new { placeholder.UserId, placeholder.CustomDataKey },
+ userData => new { userData.UserId, userData.CustomDataKey },
+ (placeholder, userData) => placeholder)
+ .Where(e => e.ItemId == PlaceholderId)
+ .ExecuteDelete();
+
// Detach all user watch data
context.UserData.Where(e => e.ItemId == id)
.ExecuteUpdate(e => e
@@ -443,6 +457,66 @@ public sealed class BaseItemRepository
return dbQuery.Count();
}
+ /// <inheritdoc />
+ public ItemCounts GetItemCounts(InternalItemsQuery filter)
+ {
+ ArgumentNullException.ThrowIfNull(filter);
+ // Hack for right now since we currently don't support filtering out these duplicates within a query
+ PrepareFilterQuery(filter);
+
+ using var context = _dbProvider.CreateDbContext();
+ var dbQuery = TranslateQuery(context.BaseItems.AsNoTracking(), context, filter);
+
+ var counts = dbQuery
+ .GroupBy(x => x.Type)
+ .Select(x => new { x.Key, Count = x.Count() })
+ .AsEnumerable();
+
+ var lookup = _itemTypeLookup.BaseItemKindNames;
+ var result = new ItemCounts();
+ foreach (var count in counts)
+ {
+ if (string.Equals(count.Key, lookup[BaseItemKind.MusicAlbum], StringComparison.Ordinal))
+ {
+ result.AlbumCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.MusicArtist], StringComparison.Ordinal))
+ {
+ result.ArtistCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.Episode], StringComparison.Ordinal))
+ {
+ result.EpisodeCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.Movie], StringComparison.Ordinal))
+ {
+ result.MovieCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.MusicVideo], StringComparison.Ordinal))
+ {
+ result.MusicVideoCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.LiveTvProgram], StringComparison.Ordinal))
+ {
+ result.ProgramCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.Series], StringComparison.Ordinal))
+ {
+ result.SeriesCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.Audio], StringComparison.Ordinal))
+ {
+ result.SongCount = count.Count;
+ }
+ else if (string.Equals(count.Key, lookup[BaseItemKind.Trailer], StringComparison.Ordinal))
+ {
+ result.TrailerCount = count.Count;
+ }
+ }
+
+ return result;
+ }
+
#pragma warning disable CA1307 // Specify StringComparison for clarity
/// <summary>
/// Gets the type.
@@ -468,6 +542,13 @@ public sealed class BaseItemRepository
var images = item.ImageInfos.Select(e => Map(item.Id, e));
using var context = _dbProvider.CreateDbContext();
+
+ if (!context.BaseItems.Any(bi => bi.Id == item.Id))
+ {
+ _logger.LogWarning("Unable to save ImageInfo for non existing BaseItem");
+ return;
+ }
+
context.BaseItemImageInfos.Where(e => e.ItemId == item.Id).ExecuteDelete();
context.BaseItemImageInfos.AddRange(images);
context.SaveChanges();
@@ -567,7 +648,7 @@ public sealed class BaseItemRepository
var itemValuesStore = existingValues.Concat(missingItemValues).ToArray();
var valueMap = itemValueMaps
- .Select(f => (f.Item, Values: f.Values.Select(e => itemValuesStore.First(g => g.Value == e.Value && g.Type == e.MagicNumber)).ToArray()))
+ .Select(f => (f.Item, Values: f.Values.Select(e => itemValuesStore.First(g => g.Value == e.Value && g.Type == e.MagicNumber)).DistinctBy(e => e.ItemValueId).ToArray()))
.ToArray();
var mappedValues = context.ItemValuesMap.Where(e => ids.Contains(e.ItemId)).ToList();
@@ -1094,13 +1175,18 @@ public sealed class BaseItemRepository
IsSeries = filter.IsSeries
});
+ var itemValuesQuery = context.ItemValues
+ .Where(f => itemValueTypes.Contains(f.Type))
+ .SelectMany(f => f.BaseItemsMap!, (f, w) => new { f, w })
+ .Join(
+ innerQueryFilter,
+ fw => fw.w.ItemId,
+ g => g.Id,
+ (fw, g) => fw.f.CleanValue);
+
var innerQuery = PrepareItemQuery(context, filter)
.Where(e => e.Type == returnType)
- .Where(e => context.ItemValues!
- .Where(f => itemValueTypes.Contains(f.Type))
- .Where(f => innerQueryFilter.Any(g => f.BaseItemsMap!.Any(w => w.ItemId == g.Id)))
- .Select(f => f.CleanValue)
- .Contains(e.CleanName));
+ .Where(e => itemValuesQuery.Contains(e.CleanName));
var outerQueryFilter = new InternalItemsQuery(filter.User)
{
@@ -1881,7 +1967,7 @@ public sealed class BaseItemRepository
if (filter.AlbumArtistIds.Length > 0)
{
- baseQuery = baseQuery.WhereReferencedItem(context, ItemValueType.Artist, filter.AlbumArtistIds);
+ baseQuery = baseQuery.WhereReferencedItem(context, ItemValueType.AlbumArtist, filter.AlbumArtistIds);
}
if (filter.ContributingArtistIds.Length > 0)
@@ -2239,8 +2325,8 @@ public sealed class BaseItemRepository
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)));
+ .Where(e => !e.ItemValues!.Where(w => w.ItemValue.Type == ItemValueType.InheritedTags || w.ItemValue.Type == ItemValueType.Tags)
+ .Any(f => filter.ExcludeInheritedTags.Contains(f.ItemValue.CleanValue)));
}
if (filter.IncludeInheritedTags.Length > 0)
@@ -2250,10 +2336,10 @@ public sealed class BaseItemRepository
if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Episode)
{
baseQuery = baseQuery
- .Where(e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.InheritedTags)
+ .Where(e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.InheritedTags || f.ItemValue.Type == ItemValueType.Tags)
.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)
+ (e.ParentId.HasValue && context.ItemValuesMap.Where(w => w.ItemId == e.ParentId.Value && (w.ItemValue.Type == ItemValueType.InheritedTags || w.ItemValue.Type == ItemValueType.Tags))
.Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue))));
}
@@ -2261,17 +2347,16 @@ public sealed class BaseItemRepository
else if (includeTypes.Length == 1 && includeTypes.FirstOrDefault() is BaseItemKind.Playlist)
{
baseQuery = baseQuery
- .Where(e =>
- e.Parents!
- .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}\"")));
+ .Where(e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.InheritedTags || f.ItemValue.Type == ItemValueType.Tags)
+ .Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue))
+ || e.Data!.Contains($"OwnerUserId\":\"{filter.User!.Id:N}\""));
// d ^^ this is stupid it hate this.
}
else
{
baseQuery = baseQuery
- .Where(e => e.Parents!.Any(f => f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))));
+ .Where(e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.InheritedTags || f.ItemValue.Type == ItemValueType.Tags)
+ .Any(f => filter.IncludeInheritedTags.Contains(f.ItemValue.CleanValue)));
}
}