diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-03-07 20:12:42 +0100 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-03-07 20:12:42 +0100 |
| commit | 077fa89717957f871b172ca4b2dc4a178efd3bc5 (patch) | |
| tree | 1c2be0089b3c33cda1ed96bde4b76a715a845df7 /Jellyfin.Server.Implementations/Item/LinkedChildrenService.cs | |
| parent | 268f23f39ac18e783156b91b575ee6a105b6937c (diff) | |
Split BaseItemRepository and IItemRepository
Diffstat (limited to 'Jellyfin.Server.Implementations/Item/LinkedChildrenService.cs')
| -rw-r--r-- | Jellyfin.Server.Implementations/Item/LinkedChildrenService.cs | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/Jellyfin.Server.Implementations/Item/LinkedChildrenService.cs b/Jellyfin.Server.Implementations/Item/LinkedChildrenService.cs new file mode 100644 index 0000000000..19afe04f01 --- /dev/null +++ b/Jellyfin.Server.Implementations/Item/LinkedChildrenService.cs @@ -0,0 +1,160 @@ +#pragma warning disable RS0030 // Do not use banned APIs + +using System; +using System.Collections.Generic; +using System.Linq; +using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Persistence; +using Microsoft.EntityFrameworkCore; +using DbLinkedChildType = Jellyfin.Database.Implementations.Entities.LinkedChildType; +using LinkedChildType = MediaBrowser.Controller.Entities.LinkedChildType; + +namespace Jellyfin.Server.Implementations.Item; + +/// <summary> +/// Provides linked children query and manipulation operations. +/// </summary> +public class LinkedChildrenService : ILinkedChildrenService +{ + private readonly IDbContextFactory<JellyfinDbContext> _dbProvider; + private readonly IItemTypeLookup _itemTypeLookup; + private readonly IItemQueryHelpers _queryHelpers; + + /// <summary> + /// Initializes a new instance of the <see cref="LinkedChildrenService"/> class. + /// </summary> + /// <param name="dbProvider">The database context factory.</param> + /// <param name="itemTypeLookup">The item type lookup.</param> + /// <param name="queryHelpers">The shared query helpers.</param> + public LinkedChildrenService( + IDbContextFactory<JellyfinDbContext> dbProvider, + IItemTypeLookup itemTypeLookup, + IItemQueryHelpers queryHelpers) + { + _dbProvider = dbProvider; + _itemTypeLookup = itemTypeLookup; + _queryHelpers = queryHelpers; + } + + /// <inheritdoc/> + public IReadOnlyList<Guid> GetLinkedChildrenIds(Guid parentId, int? childType = null) + { + using var dbContext = _dbProvider.CreateDbContext(); + + var query = dbContext.LinkedChildren + .Where(lc => lc.ParentId.Equals(parentId)); + + if (childType.HasValue) + { + query = query.Where(lc => (int)lc.ChildType == childType.Value); + } + + return query + .OrderBy(lc => lc.SortOrder) + .Select(lc => lc.ChildId) + .ToList(); + } + + /// <inheritdoc/> + public IReadOnlyDictionary<string, MusicArtist[]> FindArtists(IReadOnlyList<string> artistNames) + { + using var dbContext = _dbProvider.CreateDbContext(); + + var artists = dbContext.BaseItems.Where(e => e.Type == _itemTypeLookup.BaseItemKindNames[BaseItemKind.MusicArtist]!) + .Where(e => artistNames.Contains(e.Name)) + .ToArray(); + + var lookup = artists + .GroupBy(e => e.Name!) + .ToDictionary( + g => g.Key, + g => g.Select(f => _queryHelpers.DeserializeBaseItem(f)).Where(dto => dto is not null).Cast<MusicArtist>().ToArray()); + + var result = new Dictionary<string, MusicArtist[]>(artistNames.Count); + foreach (var name in artistNames) + { + if (lookup.TryGetValue(name, out var artistArray)) + { + result[name] = artistArray; + } + } + + return result; + } + + /// <inheritdoc/> + public IReadOnlyList<Guid> GetManualLinkedParentIds(Guid childId) + { + using var context = _dbProvider.CreateDbContext(); + return context.LinkedChildren + .Where(lc => lc.ChildId == childId && lc.ChildType == DbLinkedChildType.Manual) + .Select(lc => lc.ParentId) + .Distinct() + .ToList(); + } + + /// <inheritdoc/> + public IReadOnlyList<Guid> RerouteLinkedChildren(Guid fromChildId, Guid toChildId) + { + using var context = _dbProvider.CreateDbContext(); + + var affectedParentIds = context.LinkedChildren + .Where(lc => lc.ChildId == fromChildId && lc.ChildType == DbLinkedChildType.Manual) + .Select(lc => lc.ParentId) + .Distinct() + .ToList(); + + if (affectedParentIds.Count == 0) + { + return affectedParentIds; + } + + var parentsWithTarget = context.LinkedChildren + .Where(lc => lc.ChildId == toChildId && lc.ChildType == DbLinkedChildType.Manual) + .Select(lc => lc.ParentId) + .ToHashSet(); + + context.LinkedChildren + .Where(lc => lc.ChildId == fromChildId + && lc.ChildType == DbLinkedChildType.Manual + && !parentsWithTarget.Contains(lc.ParentId)) + .ExecuteUpdate(s => s.SetProperty(e => e.ChildId, toChildId)); + + context.LinkedChildren + .Where(lc => lc.ChildId == fromChildId + && lc.ChildType == DbLinkedChildType.Manual + && parentsWithTarget.Contains(lc.ParentId)) + .ExecuteDelete(); + + return affectedParentIds; + } + + /// <inheritdoc/> + public void UpsertLinkedChild(Guid parentId, Guid childId, LinkedChildType childType) + { + using var context = _dbProvider.CreateDbContext(); + + var dbChildType = (DbLinkedChildType)childType; + var existingLink = context.LinkedChildren + .FirstOrDefault(lc => lc.ParentId == parentId && lc.ChildId == childId); + + if (existingLink is null) + { + context.LinkedChildren.Add(new Jellyfin.Database.Implementations.Entities.LinkedChildEntity + { + ParentId = parentId, + ChildId = childId, + ChildType = dbChildType, + SortOrder = null + }); + } + else + { + existingLink.ChildType = dbChildType; + } + + context.SaveChanges(); + } +} |
