From d9d2cfa8be98016314a72c42f7a28d1744c81ac2 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Thu, 6 Jan 2022 10:28:53 -0600 Subject: [PATCH] search index fixes (#559) * add music video artist to search index * properly index minutes field when adding from scan * bump search index version --- CHANGELOG.md | 3 ++ .../FFmpeg/TranscodingTests.cs | 4 +- .../Repositories/IMetadataRepository.cs | 2 +- .../Metadata/LocalStatisticsProvider.cs | 2 +- .../Data/Repositories/MetadataRepository.cs | 38 ++++++++++++++++++- .../Data/Repositories/MusicVideoRepository.cs | 6 ++- .../Data/Repositories/SearchRepository.cs | 2 + ErsatzTV.Infrastructure/Search/SearchIndex.cs | 10 ++++- docs/user-guide/search.md | 1 + 9 files changed, 60 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f16dea4a..47e7227a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Fixed +- Properly index `minutes` field when adding new items during scan (vs when rebuilding index) + ### Changed - Remove `HLS Hybrid` streaming mode; all channels have been reconfigured to use the superior `HLS Segmenter` streaming mode - Update `MPEG-TS` streaming mode to internally use the HLS segmenter diff --git a/ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs b/ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs index b8675c493..ea986db7a 100644 --- a/ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs +++ b/ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs @@ -146,8 +146,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg var metadataRepository = new Mock(); metadataRepository - .Setup(r => r.UpdateLocalStatistics(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((_, version, _) => v = version); + .Setup(r => r.UpdateLocalStatistics(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((_, version, _) => v = version); var localStatisticsProvider = new LocalStatisticsProvider( metadataRepository.Object, diff --git a/ErsatzTV.Core/Interfaces/Repositories/IMetadataRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IMetadataRepository.cs index e274b93cd..8ae010412 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IMetadataRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IMetadataRepository.cs @@ -15,7 +15,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories Task RemoveActor(Actor actor); Task Update(Domain.Metadata metadata); Task Add(Domain.Metadata metadata); - Task UpdateLocalStatistics(int mediaVersionId, MediaVersion incoming, bool updateVersion = true); + Task UpdateLocalStatistics(MediaItem mediaItem, MediaVersion incoming, bool updateVersion = true); Task UpdatePlexStatistics(int mediaVersionId, MediaVersion incoming); Task UpdateArtworkPath(Artwork artwork); Task AddArtwork(Domain.Metadata metadata, Artwork artwork); diff --git a/ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs b/ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs index 5cb9084fd..11d9dfa61 100644 --- a/ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs +++ b/ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs @@ -132,7 +132,7 @@ namespace ErsatzTV.Core.Metadata version.DateUpdated = _localFileSystem.GetLastWriteTime(filePath); - return await _metadataRepository.UpdateLocalStatistics(mediaItemVersion.Id, version) && durationChange; + return await _metadataRepository.UpdateLocalStatistics(mediaItem, version) && durationChange; } private Task> GetProbeOutput(string ffprobePath, string filePath) diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs index ad2f190b6..b691d4c63 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Dapper; using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Extensions; using ErsatzTV.Core.Interfaces.Repositories; using LanguageExt; using Microsoft.EntityFrameworkCore; @@ -110,14 +111,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories } public async Task UpdateLocalStatistics( - int mediaVersionId, + MediaItem mediaItem, MediaVersion incoming, bool updateVersion = true) { + int mediaVersionId = mediaItem.GetHeadVersion().Id; + await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); Option maybeVersion = await dbContext.MediaVersions .Include(v => v.Streams) .Include(v => v.Chapters) + .Include(v => v.MediaFiles) .OrderBy(v => v.Id) .SingleOrDefaultAsync(v => v.Id == mediaVersionId) .Map(Optional); @@ -191,7 +195,37 @@ namespace ErsatzTV.Infrastructure.Data.Repositories existingChapter.Title = incomingChapter.Title; } - return await dbContext.SaveChangesAsync() > 0; + if (await dbContext.SaveChangesAsync() <= 0) + { + return false; + } + + // reload the media versions so we can properly index the duration + switch (mediaItem) + { + case Movie movie: + movie.MediaVersions.Clear(); + movie.MediaVersions.Add(existing); + break; + case Episode episode: + episode.MediaVersions.Clear(); + episode.MediaVersions.Add(existing); + break; + case MusicVideo musicVideo: + musicVideo.MediaVersions.Clear(); + musicVideo.MediaVersions.Add(existing); + break; + case OtherVideo otherVideo: + otherVideo.MediaVersions.Clear(); + otherVideo.MediaVersions.Add(existing); + break; + case Song song: + song.MediaVersions.Clear(); + song.MediaVersions.Add(existing); + break; + } + + return true; }, () => Task.FromResult(false)); } diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs index b02dd0375..809fff6cf 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs @@ -30,9 +30,11 @@ namespace ErsatzTV.Infrastructure.Data.Repositories LibraryPath libraryPath, string path) { - await using TvContext dbContext = _dbContextFactory.CreateDbContext(); + await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); Option maybeExisting = await dbContext.MusicVideos .AsNoTracking() + .Include(mv => mv.Artist) + .ThenInclude(a => a.ArtistMetadata) .Include(mv => mv.MusicVideoMetadata) .ThenInclude(mvm => mvm.Artwork) .Include(mv => mv.MusicVideoMetadata) @@ -196,6 +198,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories await dbContext.MusicVideos.AddAsync(musicVideo); await dbContext.SaveChangesAsync(); + await dbContext.Entry(musicVideo).Reference(m => m.Artist).LoadAsync(); + await dbContext.Entry(musicVideo.Artist).Collection(a => a.ArtistMetadata).LoadAsync(); await dbContext.Entry(musicVideo).Reference(m => m.LibraryPath).LoadAsync(); await dbContext.Entry(musicVideo.LibraryPath).Reference(lp => lp.Library).LoadAsync(); return new MediaItemScanResult(musicVideo) { IsAdded = true }; diff --git a/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs index 02d5b95a2..5334af33c 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs @@ -83,6 +83,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories .ThenInclude(mm => mm.Studios) .Include(mi => (mi as Show).ShowMetadata) .ThenInclude(mm => mm.Actors) + .Include(mi => (mi as MusicVideo).Artist) + .ThenInclude(mm => mm.ArtistMetadata) .Include(mi => (mi as MusicVideo).MusicVideoMetadata) .ThenInclude(mm => mm.Genres) .Include(mi => (mi as MusicVideo).MusicVideoMetadata) diff --git a/ErsatzTV.Infrastructure/Search/SearchIndex.cs b/ErsatzTV.Infrastructure/Search/SearchIndex.cs index c09d1cf73..ce6e0f1f9 100644 --- a/ErsatzTV.Infrastructure/Search/SearchIndex.cs +++ b/ErsatzTV.Infrastructure/Search/SearchIndex.cs @@ -79,7 +79,7 @@ namespace ErsatzTV.Infrastructure.Search _initialized = false; } - public int Version => 18; + public int Version => 19; public Task Initialize(ILocalFileSystem localFileSystem) { @@ -675,6 +675,14 @@ namespace ErsatzTV.Infrastructure.Search { doc.Add(new TextField(StudioField, studio.Name, Field.Store.NO)); } + + if (musicVideo.Artist != null) + { + foreach (ArtistMetadata artistMetadata in musicVideo.Artist.ArtistMetadata) + { + doc.Add(new TextField(ArtistField, artistMetadata.Title, Field.Store.NO)); + } + } _writer.UpdateDocument(new Term(IdField, musicVideo.Id.ToString()), doc); } diff --git a/docs/user-guide/search.md b/docs/user-guide/search.md index 82664ed2b..968be5d00 100644 --- a/docs/user-guide/search.md +++ b/docs/user-guide/search.md @@ -73,6 +73,7 @@ The following fields are available for searching artists: The following fields are available for searching music videos: - `title`: The music video title +- `artist`: The music video artist - `album`: The music video album - `genre`: The music video genre - `library_name`: The name of the library that contains the music video