// // Copyright (c) PlaceholderCompany. All rights reserved. // namespace Jellyfin.Server.Implementations.Item; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using Microsoft.EntityFrameworkCore; /// /// The Chapter manager. /// public class ChapterRepository : IChapterRepository { private readonly IDbContextFactory _dbProvider; private readonly IImageProcessor _imageProcessor; /// /// Initializes a new instance of the class. /// /// The EFCore provider. /// The Image Processor. public ChapterRepository(IDbContextFactory dbProvider, IImageProcessor imageProcessor) { _dbProvider = dbProvider; _imageProcessor = imageProcessor; } /// public async Task GetChapterAsync(Guid baseItemId, int index, CancellationToken cancellationToken = default) { await using var context = _dbProvider.CreateDbContext(); var chapter = await context.Chapters.AsNoTracking() .Select(e => new { chapter = e, baseItemPath = e.Item.Path }) .FirstOrDefaultAsync(e => e.chapter.ItemId.Equals(baseItemId) && e.chapter.ChapterIndex == index, cancellationToken) .ConfigureAwait(false); if (chapter is not null) { return Map(chapter.chapter, chapter.baseItemPath!); } return null; } /// public async Task> GetChaptersAsync(Guid baseItemId, CancellationToken cancellationToken = default) { await using var context = _dbProvider.CreateDbContext(); var chapters = await context.Chapters.AsNoTracking() .Where(e => e.ItemId.Equals(baseItemId)) .Select(e => new { chapter = e, baseItemPath = e.Item.Path }) .ToArrayAsync(cancellationToken) .ConfigureAwait(false); return chapters.Select(e => Map(e.chapter, e.baseItemPath!)).ToArray(); } /// public async Task SaveChaptersAsync(Guid itemId, IReadOnlyList chapters, CancellationToken cancellationToken = default) { await using var context = _dbProvider.CreateDbContext(); await using var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false); await context.Chapters .Where(e => e.ItemId.Equals(itemId)) .ExecuteDeleteAsync(cancellationToken) .ConfigureAwait(false); for (var i = 0; i < chapters.Count; i++) { var chapter = chapters[i]; await context.Chapters.AddAsync(Map(chapter, i, itemId), cancellationToken).ConfigureAwait(false); } await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } /// public async Task DeleteChaptersAsync(Guid itemId, CancellationToken cancellationToken) { var dbContext = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using (dbContext.ConfigureAwait(false)) { await dbContext.Chapters.Where(c => c.ItemId.Equals(itemId)).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false); await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } } private Chapter Map(ChapterInfo chapterInfo, int index, Guid itemId) { return new Chapter() { ChapterIndex = index, StartPositionTicks = chapterInfo.StartPositionTicks, ImageDateModified = chapterInfo.ImageDateModified, ImagePath = chapterInfo.ImagePath, ItemId = itemId, Name = chapterInfo.Name, Item = null! }; } private ChapterInfo Map(Chapter chapterInfo, string baseItemPath) { var chapterEntity = new ChapterInfo() { StartPositionTicks = chapterInfo.StartPositionTicks, ImageDateModified = chapterInfo.ImageDateModified.GetValueOrDefault(), ImagePath = chapterInfo.ImagePath, Name = chapterInfo.Name, }; if (!string.IsNullOrEmpty(chapterInfo.ImagePath)) { chapterEntity.ImageTag = _imageProcessor.GetImageCacheTag(baseItemPath, chapterEntity.ImageDateModified); } return chapterEntity; } }