diff options
| author | MarcoCoreDuo <90222533+MarcoCoreDuo@users.noreply.github.com> | 2026-01-18 11:30:38 -0500 |
|---|---|---|
| committer | Bond_009 <bond.009@outlook.com> | 2026-01-18 11:30:38 -0500 |
| commit | 09edca8b7a9174c374a7d03bb1ec3aea32d02ffd (patch) | |
| tree | 09a385c323b075df2b3e97355a130964ac53f1d4 | |
| parent | f9fd34b11ec962d8d76bf36854c4d4e7e037bdc5 (diff) | |
Backport pull request #15899 from jellyfin/release-10.11.z
Fix watched state not kept on Media replace/rename
Original-merge: 8433b6d8a41f66f6eef36bb950927c6a6afa1a36
Merged-by: joshuaboniface <joshua@boniface.me>
Backported-by: Bond_009 <bond.009@outlook.com>
| -rw-r--r-- | CONTRIBUTORS.md | 1 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Library/LibraryManager.cs | 6 | ||||
| -rw-r--r-- | Jellyfin.Server.Implementations/Item/BaseItemRepository.cs | 37 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/ILibraryManager.cs | 8 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Persistence/IItemRepository.cs | 8 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/MetadataService.cs | 11 |
7 files changed, 57 insertions, 17 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 171509382..1770db60b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -210,6 +210,7 @@ - [bjorntp](https://github.com/bjorntp) - [martenumberto](https://github.com/martenumberto) - [ZeusCraft10](https://github.com/ZeusCraft10) + - [MarcoCoreDuo](https://github.com/MarcoCoreDuo) # Emby Contributors diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index f35d85f65..bdf04edc2 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2202,6 +2202,12 @@ namespace Emby.Server.Implementations.Library public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) => UpdateItemsAsync([item], parent, updateReason, cancellationToken); + /// <inheritdoc /> + public async Task ReattachUserDataAsync(BaseItem item, CancellationToken cancellationToken) + { + await _itemRepository.ReattachUserDataAsync(item, cancellationToken).ConfigureAwait(false); + } + public async Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason) { if (item.IsFileProtocol) diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs index 3b3d3c4f4..646a9c483 100644 --- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs +++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs @@ -624,7 +624,6 @@ public sealed class BaseItemRepository var ids = tuples.Select(f => f.Item.Id).ToArray(); var existingItems = context.BaseItems.Where(e => ids.Contains(e.Id)).Select(f => f.Id).ToArray(); - var newItems = tuples.Where(e => !existingItems.Contains(e.Item.Id)).ToArray(); foreach (var item in tuples) { @@ -658,19 +657,6 @@ public sealed class BaseItemRepository context.SaveChanges(); - foreach (var item in newItems) - { - // reattach old userData entries - var userKeys = item.UserDataKey.ToArray(); - var retentionDate = (DateTime?)null; - context.UserData - .Where(e => e.ItemId == PlaceholderId) - .Where(e => userKeys.Contains(e.CustomDataKey)) - .ExecuteUpdate(e => e - .SetProperty(f => f.ItemId, item.Item.Id) - .SetProperty(f => f.RetentionDate, retentionDate)); - } - var itemValueMaps = tuples .Select(e => (e.Item, Values: GetItemValuesToSave(e.Item, e.InheritedTags))) .ToArray(); @@ -767,6 +753,29 @@ public sealed class BaseItemRepository } /// <inheritdoc /> + public async Task ReattachUserDataAsync(BaseItemDto item, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(item); + cancellationToken.ThrowIfCancellationRequested(); + + var dbContext = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); + + await using (dbContext.ConfigureAwait(false)) + { + var userKeys = item.GetUserDataKeys().ToArray(); + var retentionDate = (DateTime?)null; + await dbContext.UserData + .Where(e => e.ItemId == PlaceholderId) + .Where(e => userKeys.Contains(e.CustomDataKey)) + .ExecuteUpdateAsync( + e => e + .SetProperty(f => f.ItemId, item.Id) + .SetProperty(f => f.RetentionDate, retentionDate), + cancellationToken).ConfigureAwait(false); + } + } + + /// <inheritdoc /> public BaseItemDto? RetrieveItem(Guid id) { if (id.IsEmpty()) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index d9d2d0e3a..7586b99e7 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2053,6 +2053,9 @@ namespace MediaBrowser.Controller.Entities public virtual async Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken) => await LibraryManager.UpdateItemAsync(this, GetParent(), updateReason, cancellationToken).ConfigureAwait(false); + public async Task ReattachUserDataAsync(CancellationToken cancellationToken) => + await LibraryManager.ReattachUserDataAsync(this, cancellationToken).ConfigureAwait(false); + /// <summary> /// Validates that images within the item are still on the filesystem. /// </summary> diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index fcc5ed672..675812ac2 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -282,6 +282,14 @@ namespace MediaBrowser.Controller.Library Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> + /// Reattaches the user data to the item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>A task that represents the asynchronous reattachment operation.</returns> + Task ReattachUserDataAsync(BaseItem item, CancellationToken cancellationToken); + + /// <summary> /// Retrieves the item. /// </summary> /// <param name="id">The id.</param> diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 00c492742..bf80b7d0a 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -36,6 +36,14 @@ public interface IItemRepository Task SaveImagesAsync(BaseItem item, CancellationToken cancellationToken = default); /// <summary> + /// Reattaches the user data to the item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>A task that represents the asynchronous reattachment operation.</returns> + Task ReattachUserDataAsync(BaseItem item, CancellationToken cancellationToken); + + /// <summary> /// Retrieves the item. /// </summary> /// <param name="id">The id.</param> diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index a2102ca9c..e9cb46eab 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -153,7 +153,7 @@ namespace MediaBrowser.Providers.Manager if (isFirstRefresh) { - await SaveItemAsync(metadataResult, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + await SaveItemAsync(metadataResult, ItemUpdateType.MetadataImport, false, cancellationToken).ConfigureAwait(false); } // Next run metadata providers @@ -247,7 +247,7 @@ namespace MediaBrowser.Providers.Manager } // Save to database - await SaveItemAsync(metadataResult, updateType, cancellationToken).ConfigureAwait(false); + await SaveItemAsync(metadataResult, updateType, isFirstRefresh, cancellationToken).ConfigureAwait(false); } return updateType; @@ -275,9 +275,14 @@ namespace MediaBrowser.Providers.Manager } } - protected async Task SaveItemAsync(MetadataResult<TItemType> result, ItemUpdateType reason, CancellationToken cancellationToken) + protected async Task SaveItemAsync(MetadataResult<TItemType> result, ItemUpdateType reason, bool reattachUserData, CancellationToken cancellationToken) { await result.Item.UpdateToRepositoryAsync(reason, cancellationToken).ConfigureAwait(false); + if (reattachUserData) + { + await result.Item.ReattachUserDataAsync(cancellationToken).ConfigureAwait(false); + } + if (result.Item.SupportsPeople && result.People is not null) { var baseItem = result.Item; |
