Fixed AncestorIds

Fixed Sorting, NextUp and Continue Watching
pull/12798/head
JPVenson 5 months ago
parent a7a2257ccb
commit 85b8b2573b

@ -164,7 +164,9 @@ public class BaseItemEntity
public ICollection<BaseItemProvider>? Provider { get; set; }
public ICollection<AncestorId>? AncestorIds { get; set; }
public ICollection<AncestorId>? ParentAncestors { get; set; }
public ICollection<AncestorId>? Children { get; set; }
public ICollection<BaseItemMetadataField>? LockedFields { get; set; }

@ -117,37 +117,37 @@ public sealed class BaseItemRepository(
}
/// <inheritdoc />
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAllArtists(InternalItemsQuery filter)
public QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetAllArtists(InternalItemsQuery filter)
{
return GetItemValues(filter, [ItemValueType.Artist, ItemValueType.AlbumArtist], itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!);
}
/// <inheritdoc />
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetArtists(InternalItemsQuery filter)
public QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetArtists(InternalItemsQuery filter)
{
return GetItemValues(filter, [ItemValueType.Artist], itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!);
}
/// <inheritdoc />
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAlbumArtists(InternalItemsQuery filter)
public QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetAlbumArtists(InternalItemsQuery filter)
{
return GetItemValues(filter, [ItemValueType.AlbumArtist], itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!);
}
/// <inheritdoc />
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetStudios(InternalItemsQuery filter)
public QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetStudios(InternalItemsQuery filter)
{
return GetItemValues(filter, [ItemValueType.Studios], itemTypeLookup.BaseItemKindNames[BaseItemKind.Studio]!);
}
/// <inheritdoc />
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetGenres(InternalItemsQuery filter)
public QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetGenres(InternalItemsQuery filter)
{
return GetItemValues(filter, [ItemValueType.Genre], itemTypeLookup.BaseItemKindNames[BaseItemKind.Genre]!);
}
/// <inheritdoc />
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetMusicGenres(InternalItemsQuery filter)
public QueryResult<(BaseItemDto Item, ItemCounts ItemCounts)> GetMusicGenres(InternalItemsQuery filter)
{
return GetItemValues(filter, [ItemValueType.Genre], itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicGenre]!);
}
@ -200,7 +200,7 @@ public sealed class BaseItemRepository(
using var context = dbProvider.CreateDbContext();
IQueryable<BaseItemEntity> dbQuery = context.BaseItems.AsNoTracking()
IQueryable<BaseItemEntity> dbQuery = context.BaseItems.AsNoTracking().AsSingleQuery()
.Include(e => e.TrailerTypes)
.Include(e => e.Provider)
.Include(e => e.LockedFields);
@ -212,28 +212,13 @@ public sealed class BaseItemRepository(
dbQuery = TranslateQuery(dbQuery, context, filter);
dbQuery = dbQuery.Distinct();
// .DistinctBy(e => e.Id);
if (filter.EnableTotalRecordCount)
{
result.TotalRecordCount = dbQuery.Count();
}
dbQuery = ApplyOrder(dbQuery, filter);
if (filter.Limit.HasValue || filter.StartIndex.HasValue)
{
var offset = filter.StartIndex ?? 0;
if (offset > 0)
{
dbQuery = dbQuery.Skip(offset);
}
if (filter.Limit.HasValue)
{
dbQuery = dbQuery.Take(filter.Limit.Value);
}
}
dbQuery = ApplyQueryPageing(dbQuery, filter);
result.Items = dbQuery.AsEnumerable().Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
result.StartIndex = filter.StartIndex ?? 0;
@ -247,31 +232,43 @@ public sealed class BaseItemRepository(
PrepareFilterQuery(filter);
using var context = dbProvider.CreateDbContext();
IQueryable<BaseItemEntity> dbQuery = context.BaseItems.AsNoTracking().AsSingleQuery()
.Include(e => e.TrailerTypes)
.Include(e => e.Provider)
.Include(e => e.LockedFields);
if (filter.DtoOptions.EnableImages)
{
dbQuery = dbQuery.Include(e => e.Images);
}
return PrepareItemQuery(context, filter).AsEnumerable().Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
dbQuery = TranslateQuery(dbQuery, context, filter);
dbQuery = dbQuery.Distinct();
dbQuery = ApplyOrder(dbQuery, filter);
dbQuery = ApplyGroupingFilter(dbQuery, filter);
return dbQuery.AsEnumerable().Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
}
private IQueryable<BaseItemEntity> ApplyGroupingFilter(IQueryable<BaseItemEntity> dbQuery, InternalItemsQuery filter)
{
dbQuery = dbQuery.Distinct();
// var enableGroupByPresentationUniqueKey = EnableGroupByPresentationUniqueKey(filter);
// if (enableGroupByPresentationUniqueKey && filter.GroupBySeriesPresentationUniqueKey)
// {
// dbQuery = dbQuery.GroupBy(e => new { e.PresentationUniqueKey, e.SeriesPresentationUniqueKey }).Select(e => e.First());
// }
// else if (enableGroupByPresentationUniqueKey)
// {
// dbQuery = dbQuery.GroupBy(e => e.PresentationUniqueKey).Select(e => e.First());
// }
// else if (filter.GroupBySeriesPresentationUniqueKey)
// {
// dbQuery = dbQuery.GroupBy(e => e.SeriesPresentationUniqueKey).Select(e => e.First());
// }
// else
// {
// dbQuery = dbQuery.Distinct();
// }
var enableGroupByPresentationUniqueKey = EnableGroupByPresentationUniqueKey(filter);
if (enableGroupByPresentationUniqueKey && filter.GroupBySeriesPresentationUniqueKey)
{
dbQuery = dbQuery.GroupBy(e => new { e.PresentationUniqueKey, e.SeriesPresentationUniqueKey }).Select(e => e.First());
}
else if (enableGroupByPresentationUniqueKey)
{
dbQuery = dbQuery.GroupBy(e => e.PresentationUniqueKey).Select(e => e.First());
}
else if (filter.GroupBySeriesPresentationUniqueKey)
{
dbQuery = dbQuery.GroupBy(e => e.SeriesPresentationUniqueKey).Select(e => e.First());
}
else
{
dbQuery = dbQuery.Distinct();
}
return dbQuery;
}
@ -307,7 +304,7 @@ public sealed class BaseItemRepository(
private IQueryable<BaseItemEntity> PrepareItemQuery(JellyfinDbContext context, InternalItemsQuery filter)
{
IQueryable<BaseItemEntity> dbQuery = context.BaseItems.AsNoTracking()
IQueryable<BaseItemEntity> dbQuery = context.BaseItems.AsNoTracking().AsSingleQuery()
.Include(e => e.TrailerTypes)
.Include(e => e.Provider)
.Include(e => e.LockedFields);
@ -1086,13 +1083,13 @@ public sealed class BaseItemRepository(
if (filter.AncestorIds.Length > 0)
{
baseQuery = baseQuery.Where(e => e.AncestorIds!.Any(f => filter.AncestorIds.Contains(f.ParentItemId)));
baseQuery = baseQuery.Where(e => e.Children!.Any(f => filter.AncestorIds.Contains(f.ParentItemId)));
}
if (!string.IsNullOrWhiteSpace(filter.AncestorWithPresentationUniqueKey))
{
baseQuery = baseQuery
.Where(e => context.BaseItems.Where(f => f.PresentationUniqueKey == filter.AncestorWithPresentationUniqueKey).Any(f => f.AncestorIds!.Any(w => w.ItemId == f.Id)));
.Where(e => context.BaseItems.Where(f => f.PresentationUniqueKey == filter.AncestorWithPresentationUniqueKey).Any(f => f.ParentAncestors!.Any(w => w.ItemId == f.Id)));
}
if (!string.IsNullOrWhiteSpace(filter.SeriesPresentationUniqueKey))
@ -1127,7 +1124,7 @@ public sealed class BaseItemRepository(
{
baseQuery = baseQuery
.Where(e =>
e.AncestorIds!
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}\"")));
@ -1136,7 +1133,7 @@ public sealed class BaseItemRepository(
else
{
baseQuery = baseQuery
.Where(e => e.AncestorIds!.Any(f => f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))));
.Where(e => e.ParentAncestors!.Any(f => f.ParentItem.ItemValues!.Any(w => w.ItemValue.Type == ItemValueType.Tags && filter.IncludeInheritedTags.Contains(w.ItemValue.CleanValue))));
}
}
@ -1236,7 +1233,7 @@ public sealed class BaseItemRepository(
}
/// <inheritdoc cref="IItemRepository" />
public void SaveImages(BaseItem item)
public void SaveImages(BaseItemDto item)
{
ArgumentNullException.ThrowIfNull(item);
@ -1295,10 +1292,9 @@ public sealed class BaseItemRepository(
context.AncestorIds.Where(e => e.ItemId == entity.Id).ExecuteDelete();
if (item.Item.SupportsAncestors && item.AncestorIds != null)
{
entity.AncestorIds = new List<AncestorId>();
foreach (var ancestorId in item.AncestorIds)
{
entity.AncestorIds.Add(new AncestorId()
context.AncestorIds.Add(new AncestorId()
{
ParentItemId = ancestorId,
ItemId = entity.Id,
@ -1378,7 +1374,7 @@ public sealed class BaseItemRepository(
/// <param name="entity">The entity.</param>
/// <param name="dto">The dto base instance.</param>
/// <returns>The dto to map.</returns>
public BaseItemDto Map(BaseItemEntity entity, BaseItemDto dto)
public static BaseItemDto Map(BaseItemEntity entity, BaseItemDto dto)
{
dto.Id = entity.Id;
dto.ParentId = entity.ParentId.GetValueOrDefault();
@ -1416,10 +1412,10 @@ public sealed class BaseItemRepository(
dto.Genres = entity.Genres?.Split('|') ?? [];
dto.DateCreated = entity.DateCreated.GetValueOrDefault();
dto.DateModified = entity.DateModified.GetValueOrDefault();
dto.ChannelId = string.IsNullOrWhiteSpace(entity.ChannelId) ? Guid.Empty : Guid.Parse(entity.ChannelId);
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.Parse(entity.OwnerId);
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)
@ -1720,21 +1716,29 @@ public sealed class BaseItemRepository(
return query.Select(e => e.ItemValue.CleanValue).ToImmutableArray();
}
private bool TypeRequiresDeserialization(Type type)
private static bool TypeRequiresDeserialization(Type type)
{
if (serverConfigurationManager.Configuration.SkipDeserializationForBasicTypes)
{
if (type == typeof(Channel)
|| type == typeof(UserRootFolder))
{
return false;
}
}
return type.GetCustomAttribute<RequiresSourceSerialisationAttribute>() == null;
}
private BaseItemDto DeserialiseBaseItem(BaseItemEntity baseItemEntity, bool skipDeserialization = false)
{
var typeToSerialise = GetType(baseItemEntity.Type);
return BaseItemRepository.DeserialiseBaseItem(
baseItemEntity,
logger,
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="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, bool skipDeserialization = false)
{
var type = GetType(baseItemEntity.Type) ?? throw new InvalidOperationException("Cannot deserialise unkown type.");
BaseItemDto? dto = null;
@ -1815,7 +1819,7 @@ public sealed class BaseItemRepository(
}
}
var result = new QueryResult<(BaseItem, ItemCounts)>();
var result = new QueryResult<(BaseItemDto, ItemCounts)>();
if (filter.EnableTotalRecordCount)
{
result.TotalRecordCount = query.DistinctBy(e => e.PresentationUniqueKey).Count();
@ -1877,7 +1881,7 @@ public sealed class BaseItemRepository(
return value.RemoveDiacritics().ToLowerInvariant();
}
private List<(int MagicNumber, string Value)> GetItemValuesToSave(BaseItem item, List<string> inheritedTags)
private List<(int MagicNumber, string Value)> GetItemValuesToSave(BaseItemDto item, List<string> inheritedTags)
{
var list = new List<(int, string)>();
@ -2144,6 +2148,18 @@ public sealed class BaseItemRepository(
{
orderedQuery = query.OrderByDescending(expression);
}
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);
}
}
}
foreach (var item in orderBy.Skip(1))

@ -0,0 +1,49 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Jellyfin.Server.Implementations.Migrations
{
/// <inheritdoc />
public partial class FixAncestorIdConfig : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AncestorIds_BaseItems_BaseItemEntityId",
table: "AncestorIds");
migrationBuilder.DropIndex(
name: "IX_AncestorIds_BaseItemEntityId",
table: "AncestorIds");
migrationBuilder.DropColumn(
name: "BaseItemEntityId",
table: "AncestorIds");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "BaseItemEntityId",
table: "AncestorIds",
type: "TEXT",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_AncestorIds_BaseItemEntityId",
table: "AncestorIds",
column: "BaseItemEntityId");
migrationBuilder.AddForeignKey(
name: "FK_AncestorIds_BaseItems_BaseItemEntityId",
table: "AncestorIds",
column: "BaseItemEntityId",
principalTable: "BaseItems",
principalColumn: "Id");
}
}
}

@ -98,13 +98,8 @@ namespace Jellyfin.Server.Implementations.Migrations
b.Property<Guid>("ParentItemId")
.HasColumnType("TEXT");
b.Property<Guid?>("BaseItemEntityId")
.HasColumnType("TEXT");
b.HasKey("ItemId", "ParentItemId");
b.HasIndex("BaseItemEntityId");
b.HasIndex("ParentItemId");
b.ToTable("AncestorIds");
@ -1332,18 +1327,14 @@ namespace Jellyfin.Server.Implementations.Migrations
modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b =>
{
b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", null)
.WithMany("AncestorIds")
.HasForeignKey("BaseItemEntityId");
b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item")
.WithMany()
.WithMany("Children")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem")
.WithMany()
.WithMany("ParentAncestors")
.HasForeignKey("ParentItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
@ -1551,10 +1542,10 @@ namespace Jellyfin.Server.Implementations.Migrations
modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b =>
{
b.Navigation("AncestorIds");
b.Navigation("Chapters");
b.Navigation("Children");
b.Navigation("Images");
b.Navigation("ItemValues");
@ -1563,6 +1554,8 @@ namespace Jellyfin.Server.Implementations.Migrations
b.Navigation("MediaStreams");
b.Navigation("ParentAncestors");
b.Navigation("Peoples");
b.Navigation("Provider");

@ -15,7 +15,7 @@ public class AncestorIdConfiguration : IEntityTypeConfiguration<AncestorId>
{
builder.HasKey(e => new { e.ItemId, e.ParentItemId });
builder.HasIndex(e => e.ParentItemId);
builder.HasOne(e => e.ParentItem);
builder.HasOne(e => e.Item);
builder.HasOne(e => e.ParentItem).WithMany(e => e.ParentAncestors).HasForeignKey(f => f.ParentItemId);
builder.HasOne(e => e.Item).WithMany(e => e.Children).HasForeignKey(f => f.ItemId);
}
}

@ -26,7 +26,8 @@ public class BaseItemConfiguration : IEntityTypeConfiguration<BaseItemEntity>
builder.HasMany(e => e.MediaStreams);
builder.HasMany(e => e.Chapters);
builder.HasMany(e => e.Provider);
builder.HasMany(e => e.AncestorIds);
builder.HasMany(e => e.ParentAncestors);
builder.HasMany(e => e.Children);
builder.HasMany(e => e.LockedFields);
builder.HasMany(e => e.TrailerTypes);
builder.HasMany(e => e.Images);

@ -11,6 +11,7 @@ using Emby.Server.Implementations.Data;
using Jellyfin.Data.Entities;
using Jellyfin.Extensions;
using Jellyfin.Server.Implementations;
using Jellyfin.Server.Implementations.Item;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
@ -79,7 +80,14 @@ public class MigrateLibraryDb : IMigrationRoutine
stopwatch.Restart();
_logger.LogInformation("Start moving TypedBaseItem.");
var typedBaseItemsQuery = "SELECT guid, type, data, StartDate, EndDate, ChannelId, IsMovie, IsSeries, EpisodeTitle, IsRepeat, CommunityRating, CustomRating, IndexNumber, IsLocked, PreferredMetadataLanguage, PreferredMetadataCountryCode, Width, Height, DateLastRefreshed, Name, Path, PremiereDate, Overview, ParentIndexNumber, ProductionYear, OfficialRating, ForcedSortName, RunTimeTicks, Size, DateCreated, DateModified, Genres, ParentId, TopParentId, Audio, ExternalServiceId, IsInMixedFolder, DateLastSaved, LockedFields, Studios, Tags, TrailerTypes, OriginalTitle, PrimaryVersionId, DateLastMediaAdded, Album, LUFS, NormalizationGain, CriticRating, IsVirtualItem, SeriesName, UserDataKey, SeasonName, SeasonId, SeriesId, PresentationUniqueKey, InheritedParentalRatingValue, ExternalSeriesId, Tagline, ProviderIds, Images, ProductionLocations, ExtraIds, TotalBitrate, ExtraType, Artists, AlbumArtists, ExternalId, SeriesPresentationUniqueKey, ShowId, OwnerId FROM TypedBaseItems";
var typedBaseItemsQuery = "SELECT guid, type, data, StartDate, EndDate, ChannelId, IsMovie, " +
"IsSeries, EpisodeTitle, IsRepeat, CommunityRating, CustomRating, IndexNumber, IsLocked, PreferredMetadataLanguage, " +
"PreferredMetadataCountryCode, Width, Height, DateLastRefreshed, Name, Path, PremiereDate, Overview, ParentIndexNumber, " +
"ProductionYear, OfficialRating, ForcedSortName, RunTimeTicks, Size, DateCreated, DateModified, Genres, ParentId, TopParentId, " +
"Audio, ExternalServiceId, IsInMixedFolder, DateLastSaved, LockedFields, Studios, Tags, TrailerTypes, OriginalTitle, PrimaryVersionId, " +
"DateLastMediaAdded, Album, LUFS, NormalizationGain, CriticRating, IsVirtualItem, SeriesName, UserDataKey, SeasonName, SeasonId, SeriesId, " +
"PresentationUniqueKey, InheritedParentalRatingValue, ExternalSeriesId, Tagline, ProviderIds, Images, ProductionLocations, ExtraIds, TotalBitrate, " +
"ExtraType, Artists, AlbumArtists, ExternalId, SeriesPresentationUniqueKey, ShowId, OwnerId, MediaType FROM TypedBaseItems";
dbContext.BaseItems.ExecuteDelete();
var legacyBaseItemWithUserKeys = new Dictionary<string, BaseItemEntity>();
@ -87,7 +95,10 @@ public class MigrateLibraryDb : IMigrationRoutine
{
var baseItem = GetItem(dto);
dbContext.BaseItems.Add(baseItem.BaseItem);
legacyBaseItemWithUserKeys[baseItem.LegacyUserDataKey] = baseItem.BaseItem;
foreach (var dataKey in baseItem.LegacyUserDataKey)
{
legacyBaseItemWithUserKeys[dataKey] = baseItem.BaseItem;
}
}
_logger.LogInformation("Try saving {0} BaseItem entries.", dbContext.BaseItems.Local.Count);
@ -636,7 +647,7 @@ public class MigrateLibraryDb : IMigrationRoutine
return item;
}
private (BaseItemEntity BaseItem, string LegacyUserDataKey) GetItem(SqliteDataReader reader)
private (BaseItemEntity BaseItem, string[] LegacyUserDataKey) GetItem(SqliteDataReader reader)
{
var entity = new BaseItemEntity()
{
@ -905,8 +916,10 @@ public class MigrateLibraryDb : IMigrationRoutine
entity.SeriesName = seriesName;
}
if (reader.TryGetString(index++, out var userDataKey))
var userDataKeys = new List<string>();
if (reader.TryGetString(index++, out var directUserDataKey))
{
userDataKeys.Add(directUserDataKey);
}
if (reader.TryGetString(index++, out var seasonName))
@ -1010,7 +1023,16 @@ public class MigrateLibraryDb : IMigrationRoutine
entity.OwnerId = ownerId;
}
return (entity, userDataKey);
if (reader.TryGetString(index++, out var mediaType))
{
entity.MediaType = mediaType;
}
var baseItem = BaseItemRepository.DeserialiseBaseItem(entity, _logger, false);
var dataKeys = baseItem.GetUserDataKeys();
userDataKeys.AddRange(dataKeys);
return (entity, userDataKeys.ToArray());
}
private static BaseItemImageInfo Map(Guid baseItemId, ItemImageInfo e)

Loading…
Cancel
Save