From be48cdd9e90ed147c5526ef3fed0624bcbad7741 Mon Sep 17 00:00:00 2001
From: JPVenson <6794763+JPVenson@users.noreply.github.com>
Date: Wed, 9 Oct 2024 09:53:39 +0000
Subject: Naming refactoring and WIP porting of new interface repositories
---
src/Jellyfin.Drawing/ImageProcessor.cs | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
(limited to 'src')
diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs
index 5d4732234..b57f2753f 100644
--- a/src/Jellyfin.Drawing/ImageProcessor.cs
+++ b/src/Jellyfin.Drawing/ImageProcessor.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
@@ -403,10 +404,34 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return _imageEncoder.GetImageBlurHash(xComp, yComp, path);
}
+ ///
+ public string GetImageCacheTag(string baseItemPath, DateTime imageDateModified)
+ => (baseItemPath + imageDateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+
///
public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
=> (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ ///
+ public string GetImageCacheTag(BaseItemDto item, ItemImageInfo image)
+ => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+
+ ///
+ public string? GetImageCacheTag(BaseItemDto item, ChapterInfo chapter)
+ {
+ if (chapter.ImagePath is null)
+ {
+ return null;
+ }
+
+ return GetImageCacheTag(item, new ItemImageInfo
+ {
+ Path = chapter.ImagePath,
+ Type = ImageType.Chapter,
+ DateModified = chapter.ImageDateModified
+ });
+ }
+
///
public string? GetImageCacheTag(BaseItem item, ChapterInfo chapter)
{
--
cgit v1.2.3
From 421b49dee989a1810fb1703c66dc39ab521a3048 Mon Sep 17 00:00:00 2001
From: JPVenson
Date: Tue, 22 Oct 2024 11:47:05 +0000
Subject: Adapted Review sugestions
---
src/Jellyfin.Drawing/ImageProcessor.cs | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs
index b57f2753f..7ba9ff172 100644
--- a/src/Jellyfin.Drawing/ImageProcessor.cs
+++ b/src/Jellyfin.Drawing/ImageProcessor.cs
@@ -424,12 +424,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return null;
}
- return GetImageCacheTag(item, new ItemImageInfo
- {
- Path = chapter.ImagePath,
- Type = ImageType.Chapter,
- DateModified = chapter.ImageDateModified
- });
+ return (item.Path + chapter.ImageDateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
///
--
cgit v1.2.3
From b39553611d0d6702ef657f76573cefa2ee437745 Mon Sep 17 00:00:00 2001
From: JPVenson
Date: Sun, 17 Nov 2024 11:03:43 +0000
Subject: Applied coding style
---
.../Data/CleanDatabaseScheduledTask.cs | 4 ++--
Emby.Server.Implementations/Data/ItemTypeLookup.cs | 6 ------
Emby.Server.Implementations/Library/LibraryManager.cs | 7 ++++---
Emby.Server.Implementations/Library/MediaSourceManager.cs | 2 +-
Jellyfin.Api/Controllers/InstantMixController.cs | 2 +-
Jellyfin.Api/Controllers/YearsController.cs | 4 ++--
Jellyfin.Server.Implementations/Item/BaseItemRepository.cs | 12 ++++++------
Jellyfin.Server.Implementations/Item/ChapterRepository.cs | 2 +-
.../Item/MediaAttachmentRepository.cs | 2 +-
.../Item/MediaStreamRepository.cs | 2 +-
Jellyfin.Server.Implementations/Item/PeopleRepository.cs | 4 ++--
.../MediaSegments/MediaSegmentManager.cs | 2 +-
MediaBrowser.Controller/Entities/BaseItem.cs | 2 +-
MediaBrowser.Controller/Entities/Folder.cs | 10 +++++-----
MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 4 ++--
MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +-
MediaBrowser.Providers/Music/ArtistMetadataService.cs | 2 +-
src/Jellyfin.LiveTv/Guide/GuideManager.cs | 2 +-
18 files changed, 33 insertions(+), 38 deletions(-)
(limited to 'src')
diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
index 6ea7d9197..aceff8b53 100644
--- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
+++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
@@ -28,9 +28,9 @@ namespace Emby.Server.Implementations.Data
_dbProvider = dbProvider;
}
- public Task Run(IProgress progress, CancellationToken cancellationToken)
+ public async Task Run(IProgress progress, CancellationToken cancellationToken)
{
- return CleanDeadItems(cancellationToken, progress);
+ await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false);
}
private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress progress)
diff --git a/Emby.Server.Implementations/Data/ItemTypeLookup.cs b/Emby.Server.Implementations/Data/ItemTypeLookup.cs
index f5db28c7a..82c0a8b6c 100644
--- a/Emby.Server.Implementations/Data/ItemTypeLookup.cs
+++ b/Emby.Server.Implementations/Data/ItemTypeLookup.cs
@@ -1,12 +1,8 @@
-using System;
using System.Collections.Frozen;
using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
using System.Threading.Channels;
using Emby.Server.Implementations.Playlists;
using Jellyfin.Data.Enums;
-using Jellyfin.Server.Implementations;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
@@ -14,7 +10,6 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
-using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Data;
@@ -23,7 +18,6 @@ public class ItemTypeLookup : IItemTypeLookup
{
///
public IReadOnlyList MusicGenreTypes { get; } = [
-
typeof(Audio).FullName!,
typeof(MusicVideo).FullName!,
typeof(MusicAlbum).FullName!,
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 7e059be23..7b37011cb 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1810,11 +1810,11 @@ namespace Emby.Server.Implementations.Library
///
public void CreateItem(BaseItem item, BaseItem? parent)
{
- CreateItems(new[] { item }, parent, CancellationToken.None);
+ CreateOrUpdateItems(new[] { item }, parent, CancellationToken.None);
}
///
- public void CreateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken)
+ public void CreateOrUpdateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken)
{
_itemRepository.SaveItems(items, cancellationToken);
@@ -2971,10 +2971,11 @@ namespace Emby.Server.Implementations.Library
{
if (createEntity)
{
- CreateItems([personEntity], null, CancellationToken.None);
+ CreateOrUpdateItems([personEntity], null, CancellationToken.None);
}
await RunMetadataSavers(personEntity, itemUpdateType).ConfigureAwait(false);
+ CreateOrUpdateItems([personEntity], null, CancellationToken.None);
}
}
}
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index 2fb571a10..d0f5e60f7 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -218,7 +218,7 @@ namespace Emby.Server.Implementations.Library
list.Add(source);
}
- return SortMediaSources(list).ToImmutableArray();
+ return SortMediaSources(list).ToArray();
}
/// >
diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs
index e89e7ce26..87a856d38 100644
--- a/Jellyfin.Api/Controllers/InstantMixController.cs
+++ b/Jellyfin.Api/Controllers/InstantMixController.cs
@@ -397,7 +397,7 @@ public class InstantMixController : BaseJellyfinApiController
if (limit.HasValue && limit < items.Count)
{
- items = items.Take(limit.Value).ToImmutableArray();
+ items = items.Take(limit.Value).ToArray();
}
var result = new QueryResult(
diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs
index 907724e04..e709e43e2 100644
--- a/Jellyfin.Api/Controllers/YearsController.cs
+++ b/Jellyfin.Api/Controllers/YearsController.cs
@@ -113,11 +113,11 @@ public class YearsController : BaseJellyfinApiController
if (userId.IsNullOrEmpty())
{
- items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToImmutableArray();
+ items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToArray();
}
else
{
- items = recursive ? folder.GetRecursiveChildren(user, query) : folder.GetChildren(user, true).Where(Filter).ToImmutableArray();
+ items = recursive ? folder.GetRecursiveChildren(user, query) : folder.GetChildren(user, true).Where(Filter).ToArray();
}
}
else
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index 0183685be..8670b06cc 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -117,7 +117,7 @@ public sealed class BaseItemRepository(
PrepareFilterQuery(filter);
using var context = dbProvider.CreateDbContext();
- return ApplyQueryFilter(context.BaseItems.AsNoTracking(), context, filter).Select(e => e.Id).ToImmutableArray();
+ return ApplyQueryFilter(context.BaseItems.AsNoTracking(), context, filter).Select(e => e.Id).ToArray();
}
///
@@ -216,7 +216,7 @@ public sealed class BaseItemRepository(
dbQuery = ApplyGroupingFilter(dbQuery, filter);
dbQuery = ApplyQueryPageing(dbQuery, filter);
- result.Items = dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
+ result.Items = dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray();
result.StartIndex = filter.StartIndex ?? 0;
return result;
}
@@ -235,7 +235,7 @@ public sealed class BaseItemRepository(
dbQuery = ApplyGroupingFilter(dbQuery, filter);
dbQuery = ApplyQueryPageing(dbQuery, filter);
- return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToImmutableArray();
+ return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserialiseBaseItem(w, filter.SkipDeserialization)).ToArray();
}
private IQueryable ApplyGroupingFilter(IQueryable dbQuery, InternalItemsQuery filter)
@@ -831,7 +831,7 @@ public sealed class BaseItemRepository(
}
// query = query.DistinctBy(e => e.CleanValue);
- return query.Select(e => e.ItemValue.CleanValue).ToImmutableArray();
+ return query.Select(e => e.ItemValue.CleanValue).ToArray();
}
private static bool TypeRequiresDeserialization(Type type)
@@ -976,10 +976,10 @@ public sealed class BaseItemRepository(
});
result.StartIndex = filter.StartIndex ?? 0;
- result.Items = resultQuery.ToImmutableArray().Where(e => e is not null).Select(e =>
+ result.Items = resultQuery.ToArray().Where(e => e is not null).Select(e =>
{
return (DeserialiseBaseItem(e.item, filter.SkipDeserialization), e.itemCount);
- }).ToImmutableArray();
+ }).ToArray();
return result;
}
diff --git a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs
index dc55484c9..16e8c205d 100644
--- a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs
@@ -73,7 +73,7 @@ public class ChapterRepository : IChapterRepository
})
.ToList()
.Select(e => Map(e.chapter, e.baseItemPath!))
- .ToImmutableArray();
+ .ToArray();
}
///
diff --git a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs
index c6488f321..155798209 100644
--- a/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/MediaAttachmentRepository.cs
@@ -40,7 +40,7 @@ public class MediaAttachmentRepository(IDbContextFactory dbPr
query = query.Where(e => e.Index == filter.Index);
}
- return query.AsEnumerable().Select(Map).ToImmutableArray();
+ return query.AsEnumerable().Select(Map).ToArray();
}
private MediaAttachment Map(AttachmentStreamInfo attachment)
diff --git a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs
index 0617dd81e..d6bfc1a8f 100644
--- a/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/MediaStreamRepository.cs
@@ -51,7 +51,7 @@ public class MediaStreamRepository : IMediaStreamRepository
public IReadOnlyList GetMediaStreams(MediaStreamQuery filter)
{
using var context = _dbProvider.CreateDbContext();
- return TranslateQuery(context.MediaStreamInfos.AsNoTracking(), filter).AsEnumerable().Select(Map).ToImmutableArray();
+ return TranslateQuery(context.MediaStreamInfos.AsNoTracking(), filter).AsEnumerable().Select(Map).ToArray();
}
private string? GetPathToSave(string? path)
diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
index 417212ba4..d1823514a 100644
--- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs
@@ -36,7 +36,7 @@ public class PeopleRepository(IDbContextFactory dbProvider, I
dbQuery = dbQuery.Take(filter.Limit);
}
- return dbQuery.AsEnumerable().Select(Map).ToImmutableArray();
+ return dbQuery.AsEnumerable().Select(Map).ToArray();
}
///
@@ -51,7 +51,7 @@ public class PeopleRepository(IDbContextFactory dbProvider, I
dbQuery = dbQuery.Take(filter.Limit);
}
- return dbQuery.Select(e => e.Name).ToImmutableArray();
+ return dbQuery.Select(e => e.Name).ToArray();
}
///
diff --git a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs
index 151b616f7..d0f41c6fa 100644
--- a/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs
+++ b/Jellyfin.Server.Implementations/MediaSegments/MediaSegmentManager.cs
@@ -154,7 +154,7 @@ public class MediaSegmentManager : IMediaSegmentManager
return query
.OrderBy(e => e.StartTicks)
.AsNoTracking()
- .ToImmutableArray()
+ .ToArray()
.Select(Map);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index d92407a3f..a6bc35a9f 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1092,7 +1092,7 @@ namespace MediaBrowser.Controller.Entities
return 1;
}).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
.ThenByDescending(i => i, new MediaSourceWidthComparator())
- .ToImmutableArray();
+ .ToArray();
}
protected virtual IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 8fff7dbc4..a13f04614 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -452,7 +452,7 @@ namespace MediaBrowser.Controller.Entities
if (newItems.Count > 0)
{
- LibraryManager.CreateItems(newItems, this, cancellationToken);
+ LibraryManager.CreateOrUpdateItems(newItems, this, cancellationToken);
}
}
else
@@ -1306,7 +1306,7 @@ namespace MediaBrowser.Controller.Entities
AddChildren(user, includeLinkedChildren, result, false, query);
- return result.Values.ToImmutableArray();
+ return result.Values.ToArray();
}
protected virtual IEnumerable GetEligibleChildrenForRecursiveChildren(User user)
@@ -1379,7 +1379,7 @@ namespace MediaBrowser.Controller.Entities
AddChildren(user, true, result, true, query);
- return result.Values.ToImmutableArray();
+ return result.Values.ToArray();
}
///
@@ -1407,7 +1407,7 @@ namespace MediaBrowser.Controller.Entities
AddChildrenToList(result, includeLinkedChildren, true, filter);
- return result.Values.ToImmutableArray();
+ return result.Values.ToArray();
}
///
@@ -1563,7 +1563,7 @@ namespace MediaBrowser.Controller.Entities
return LinkedChildren
.Select(i => new Tuple(i, GetLinkedChild(i)))
.Where(i => i.Item2 is not null)
- .ToImmutableArray();
+ .ToArray();
}
protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, IReadOnlyList fileSystemChildren, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index cb17e3faf..d0c9f049a 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -131,13 +131,13 @@ namespace MediaBrowser.Controller.Entities.Movies
public override IReadOnlyList GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
{
var children = base.GetChildren(user, includeLinkedChildren, query);
- return Sort(children, user).ToImmutableArray();
+ return Sort(children, user).ToArray();
}
public override IReadOnlyList GetRecursiveChildren(User user, InternalItemsQuery query)
{
var children = base.GetRecursiveChildren(user, query);
- return Sort(children, user).ToImmutableArray();
+ return Sort(children, user).ToArray();
}
public BoxSetInfo GetLookupInfo()
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 47b1cb16e..8fcd5f605 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -258,7 +258,7 @@ namespace MediaBrowser.Controller.Library
/// Items to create.
/// Parent of new items.
/// CancellationToken to use for operation.
- void CreateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken);
+ void CreateOrUpdateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken);
///
/// Updates the item.
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 8af6de925..c47f9a500 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Music
Recursive = true,
IsFolder = false
})
- : item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder).ToImmutableArray();
+ : item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder);
}
}
}
diff --git a/src/Jellyfin.LiveTv/Guide/GuideManager.cs b/src/Jellyfin.LiveTv/Guide/GuideManager.cs
index f657422a0..ff31b7123 100644
--- a/src/Jellyfin.LiveTv/Guide/GuideManager.cs
+++ b/src/Jellyfin.LiveTv/Guide/GuideManager.cs
@@ -265,7 +265,7 @@ public class GuideManager : IGuideManager
if (newPrograms.Count > 0)
{
- _libraryManager.CreateItems(newPrograms, null, cancellationToken);
+ _libraryManager.CreateOrUpdateItems(newPrograms, null, cancellationToken);
await PrecacheImages(newPrograms, maxCacheDate).ConfigureAwait(false);
}
--
cgit v1.2.3
From b33810534b85f96702035a54a4c661cc4d31d928 Mon Sep 17 00:00:00 2001
From: JPVenson
Date: Wed, 15 Jan 2025 20:12:41 +0000
Subject: Applied review comments
---
.../Data/CleanDatabaseScheduledTask.cs | 14 ++++++++++----
.../Library/UserDataManager.cs | 12 +++++++++---
.../Item/BaseItemRepository.cs | 19 ++++++++++---------
.../Item/ChapterRepository.cs | 2 +-
.../Migrations/Routines/MigrateLibraryDb.cs | 15 ++++++++-------
src/Jellyfin.Drawing/ImageProcessor.cs | 10 +++++-----
.../Controllers/LibraryStructureControllerTests.cs | 2 +-
7 files changed, 44 insertions(+), 30 deletions(-)
(limited to 'src')
diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
index aceff8b53..7ea863d76 100644
--- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
+++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
@@ -67,10 +67,16 @@ namespace Emby.Server.Implementations.Data
progress.Report(percent * 100);
}
- using var context = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
- using var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false);
- await context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false);
- await transaction.CommitAsync(cancellationToken).ConfigureAwait(false);
+ var context = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
+ await using (context.ConfigureAwait(false))
+ {
+ var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false);
+ await using (transaction.ConfigureAwait(false))
+ {
+ await context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false);
+ await transaction.CommitAsync(cancellationToken).ConfigureAwait(false);
+ }
+ }
progress.Report(100);
}
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index 9b3a0c1f9..cc45f2fcb 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -146,8 +146,8 @@ namespace Emby.Server.Implementations.Library
{
ItemId = itemId,
CustomDataKey = dto.Key,
- Item = null!,
- User = null!,
+ Item = null,
+ User = null,
AudioStreamIndex = dto.AudioStreamIndex,
IsFavorite = dto.IsFavorite,
LastPlayedDate = dto.LastPlayedDate,
@@ -181,7 +181,13 @@ namespace Emby.Server.Implementations.Library
private UserItemData? GetUserData(User user, Guid itemId, List keys)
{
var cacheKey = GetCacheKey(user.InternalId, itemId);
- var data = GetUserDataInternal(user.Id, itemId, keys);
+
+ if (_userData.TryGetValue(cacheKey, out var data))
+ {
+ return data;
+ }
+
+ data = GetUserDataInternal(user.Id, itemId, keys);
if (data is null)
{
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index 01e23f56d..1eca0713d 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -125,7 +125,7 @@ public sealed class BaseItemRepository
transaction.Commit();
}
- ///
+ ///
public IReadOnlyList GetItemIdsList(InternalItemsQuery filter)
{
ArgumentNullException.ThrowIfNull(filter);
@@ -201,7 +201,7 @@ public sealed class BaseItemRepository
_itemTypeLookup.MusicGenreTypes);
}
- ///
+ ///
public QueryResult GetItems(InternalItemsQuery filter)
{
ArgumentNullException.ThrowIfNull(filter);
@@ -235,7 +235,7 @@ public sealed class BaseItemRepository
return result;
}
- ///
+ ///
public IReadOnlyList GetItemList(InternalItemsQuery filter)
{
ArgumentNullException.ThrowIfNull(filter);
@@ -354,12 +354,14 @@ public sealed class BaseItemRepository
{
ArgumentException.ThrowIfNullOrEmpty(typeName);
+ // TODO: this isn't great. Refactor later to be both globally handled by a dedicated service not just an static variable and be loaded eagar.
+ // currently this is done so that plugins may introduce their own type of baseitems as we dont know when we are first called, before or after plugins are loaded
return _typeMap.GetOrAdd(typeName, k => AppDomain.CurrentDomain.GetAssemblies()
.Select(a => a.GetType(k))
.FirstOrDefault(t => t is not null));
}
- ///
+ ///
public void SaveImages(BaseItemDto item)
{
ArgumentNullException.ThrowIfNull(item);
@@ -373,13 +375,13 @@ public sealed class BaseItemRepository
transaction.Commit();
}
- ///
+ ///
public void SaveItems(IReadOnlyList items, CancellationToken cancellationToken)
{
UpdateOrInsertItems(items, cancellationToken);
}
- ///
+ ///
public void UpdateOrInsertItems(IReadOnlyList items, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(items);
@@ -479,7 +481,7 @@ public sealed class BaseItemRepository
transaction.Commit();
}
- ///
+ ///
public BaseItemDto? RetrieveItem(Guid id)
{
if (id.IsEmpty())
@@ -890,8 +892,7 @@ public sealed class BaseItemRepository
{
try
{
- using var dataAsStream = new MemoryStream(Encoding.UTF8.GetBytes(baseItemEntity.Data!));
- dto = JsonSerializer.Deserialize(dataAsStream, type, JsonDefaults.Options) as BaseItemDto;
+ dto = JsonSerializer.Deserialize(baseItemEntity.Data, type, JsonDefaults.Options) as BaseItemDto;
}
catch (JsonException ex)
{
diff --git a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs
index 16e8c205d..fc6f04d56 100644
--- a/Jellyfin.Server.Implementations/Item/ChapterRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/ChapterRepository.cs
@@ -71,7 +71,7 @@ public class ChapterRepository : IChapterRepository
chapter = e,
baseItemPath = e.Item.Path
})
- .ToList()
+ .AsEnumerable()
.Select(e => Map(e.chapter, e.baseItemPath!))
.ToArray();
}
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs
index 8b2664ecd..d0360a56d 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs
@@ -1,3 +1,5 @@
+#pragma warning disable RS0030 // Do not use banned APIs
+
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -21,7 +23,6 @@ using Microsoft.Extensions.Logging;
using Chapter = Jellyfin.Data.Entities.Chapter;
namespace Jellyfin.Server.Migrations.Routines;
-#pragma warning disable RS0030 // Do not use banned APIs
///
/// The migration routine for migrating the userdata database to EF Core.
@@ -80,7 +81,7 @@ public class MigrateLibraryDb : IMigrationRoutine
stopwatch.Restart();
_logger.LogInformation("Start moving TypedBaseItem.");
- var typedBaseItemsQuery = """
+ const string 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,
@@ -111,7 +112,7 @@ public class MigrateLibraryDb : IMigrationRoutine
_logger.LogInformation("Start moving ItemValues.");
// do not migrate inherited types as they are now properly mapped in search and lookup.
- var itemValueQuery =
+ const string itemValueQuery =
"""
SELECT ItemId, Type, Value, CleanValue FROM ItemValues
WHERE Type <> 6 AND EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = ItemValues.ItemId)
@@ -187,7 +188,7 @@ public class MigrateLibraryDb : IMigrationRoutine
dbContext.SaveChanges();
_logger.LogInformation("Start moving MediaStreamInfos.");
- var mediaStreamQuery = """
+ const string mediaStreamQuery = """
SELECT ItemId, StreamIndex, StreamType, Codec, Language, ChannelLayout, Profile, AspectRatio, Path,
IsInterlaced, BitRate, Channels, SampleRate, IsDefault, IsForced, IsExternal, Height, Width,
AverageFrameRate, RealFrameRate, Level, PixelFormat, BitDepth, IsAnamorphic, RefFrames, CodecTag,
@@ -211,7 +212,7 @@ public class MigrateLibraryDb : IMigrationRoutine
stopwatch.Restart();
_logger.LogInformation("Start moving People.");
- var personsQuery = """
+ const string personsQuery = """
SELECT ItemId, Name, Role, PersonType, SortOrder FROM People
WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = People.ItemId)
""";
@@ -268,7 +269,7 @@ public class MigrateLibraryDb : IMigrationRoutine
stopwatch.Restart();
_logger.LogInformation("Start moving Chapters.");
- var chapterQuery = """
+ const string chapterQuery = """
SELECT ItemId,StartPositionTicks,Name,ImagePath,ImageDateModified,ChapterIndex from Chapters2
WHERE EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = Chapters2.ItemId)
""";
@@ -287,7 +288,7 @@ public class MigrateLibraryDb : IMigrationRoutine
stopwatch.Restart();
_logger.LogInformation("Start moving AncestorIds.");
- var ancestorIdsQuery = """
+ const string ancestorIdsQuery = """
SELECT ItemId, AncestorId, AncestorIdText FROM AncestorIds
WHERE
EXISTS(SELECT 1 FROM TypedBaseItems WHERE TypedBaseItems.guid = AncestorIds.ItemId)
diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs
index 7ba9ff172..0bd3b8920 100644
--- a/src/Jellyfin.Drawing/ImageProcessor.cs
+++ b/src/Jellyfin.Drawing/ImageProcessor.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Mime;
+using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -410,11 +411,11 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
///
public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
- => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ => GetImageCacheTag(item.Path, image.DateModified);
///
public string GetImageCacheTag(BaseItemDto item, ItemImageInfo image)
- => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ => GetImageCacheTag(item.Path, image.DateModified);
///
public string? GetImageCacheTag(BaseItemDto item, ChapterInfo chapter)
@@ -424,7 +425,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return null;
}
- return (item.Path + chapter.ImageDateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ return GetImageCacheTag(item.Path, chapter.ImageDateModified);
}
///
@@ -451,8 +452,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return null;
}
- return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5()
- .ToString("N", CultureInfo.InvariantCulture);
+ return GetImageCacheTag(user.ProfileImage.Path, user.ProfileImage.LastModified);
}
private Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs
index 0376f57cc..e7166d424 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs
@@ -45,7 +45,7 @@ public sealed class LibraryStructureControllerTests : IClassFixture