using ErsatzTV.Application.MediaCards; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Extensions; using ErsatzTV.Core.Interfaces.Emby; using ErsatzTV.Core.Interfaces.Jellyfin; using ErsatzTV.Core.Interfaces.Plex; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Search; using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using static ErsatzTV.Application.MediaCards.Mapper; namespace ErsatzTV.Application.Search; public class QuerySearchIndexMusicVideosHandler( ISearchIndex searchIndex, IPlexPathReplacementService plexPathReplacementService, IJellyfinPathReplacementService jellyfinPathReplacementService, IEmbyPathReplacementService embyPathReplacementService, IDbContextFactory dbContextFactory) : IRequestHandler { public async Task Handle( QuerySearchIndexMusicVideos request, CancellationToken cancellationToken) { SearchResult searchResult = await searchIndex.Search( request.Query, string.Empty, (request.PageNumber - 1) * request.PageSize, request.PageSize, cancellationToken); await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); var ids = searchResult.Items.Map(i => i.Id).ToHashSet(); List musicVideos = await dbContext.MusicVideoMetadata .AsNoTracking() .Filter(mvm => ids.Contains(mvm.MusicVideoId)) .Include(mvm => mvm.MusicVideo) .ThenInclude(mv => mv.Artist) .ThenInclude(a => a.ArtistMetadata) .Include(mvm => mvm.MusicVideo) .ThenInclude(e => e.MediaVersions) .ThenInclude(mv => mv.MediaFiles) .Include(mvm => mvm.Artwork) .OrderBy(mvm => mvm.SortTitle) .ToListAsync(cancellationToken); var items = new List(); foreach (MusicVideoMetadata musicVideoMetadata in musicVideos) { string localPath = await musicVideoMetadata.MusicVideo.GetLocalPath( plexPathReplacementService, jellyfinPathReplacementService, embyPathReplacementService, cancellationToken, false); items.Add(ProjectToViewModel(musicVideoMetadata, localPath)); } return new MusicVideoCardResultsViewModel(searchResult.TotalCount, items, searchResult.PageMap); } }