fix missing trashed episodes (#881)

* fix episodes missing from trash

* cleanup
This commit is contained in:
Jason Dove
2022-06-29 15:01:49 -05:00
committed by GitHub
parent 5ed0184bca
commit 9c02a6738b
29 changed files with 272 additions and 56 deletions
@@ -1,6 +1,7 @@
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
@@ -13,6 +14,7 @@ namespace ErsatzTV.Application.Libraries;
public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILogger<MoveLocalLibraryPathHandler> _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
@@ -20,11 +22,13 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
public MoveLocalLibraryPathHandler(
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,
ILogger<MoveLocalLibraryPathHandler> logger)
{
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_dbContextFactory = dbContextFactory;
_logger = logger;
}
@@ -35,7 +39,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Parameters> validation = await Validate(dbContext, request);
return await LanguageExtensions.Apply(validation, parameters => MovePath(dbContext, parameters));
return await validation.Apply(parameters => MovePath(dbContext, parameters));
}
private async Task<Unit> MovePath(TvContext dbContext, Parameters parameters)
@@ -57,7 +61,10 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
foreach (MediaItem mediaItem in maybeMediaItem)
{
_logger.LogInformation("Moving item at {Path}", await GetPath(dbContext, mediaItem));
await _searchIndex.UpdateItems(_searchRepository, new List<MediaItem> { mediaItem });
await _searchIndex.UpdateItems(
_searchRepository,
_fallbackMetadataProvider,
new List<MediaItem> { mediaItem });
}
}
}
@@ -1,6 +1,7 @@
using System.Text.RegularExpressions;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
@@ -19,10 +20,11 @@ public class AddTraktListHandler : TraktCommandBase, IRequestHandler<AddTraktLis
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,
ILogger<AddTraktListHandler> logger,
IEntityLocker entityLocker)
: base(traktApiClient, searchRepository, searchIndex, logger)
: base(traktApiClient, searchRepository, searchIndex, fallbackMetadataProvider, logger)
{
_dbContextFactory = dbContextFactory;
_entityLocker = entityLocker;
@@ -1,6 +1,7 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
@@ -14,6 +15,7 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler<DeleteTr
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IEntityLocker _entityLocker;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
@@ -21,13 +23,15 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler<DeleteTr
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,
ILogger<DeleteTraktListHandler> logger,
IEntityLocker entityLocker)
: base(traktApiClient, searchRepository, searchIndex, logger)
: base(traktApiClient, searchRepository, searchIndex, fallbackMetadataProvider, logger)
{
_searchRepository = searchRepository;
_searchIndex = searchIndex;
_fallbackMetadataProvider = fallbackMetadataProvider;
_dbContextFactory = dbContextFactory;
_entityLocker = entityLocker;
}
@@ -38,8 +42,7 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler<DeleteTr
{
try
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, TraktList> validation = await TraktListMustExist(dbContext, request.TraktListId);
return await LanguageExtensions.Apply(validation, c => DoDeletion(dbContext, c));
}
@@ -56,7 +59,7 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler<DeleteTr
dbContext.TraktLists.Remove(traktList);
if (await dbContext.SaveChangesAsync() > 0)
{
await _searchIndex.RebuildItems(_searchRepository, mediaItemIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, mediaItemIds);
}
_searchIndex.Commit();
@@ -1,6 +1,7 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
@@ -20,9 +21,15 @@ public class MatchTraktListItemsHandler : TraktCommandBase,
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,
ILogger<MatchTraktListItemsHandler> logger,
IEntityLocker entityLocker) : base(traktApiClient, searchRepository, searchIndex, logger)
IEntityLocker entityLocker) : base(
traktApiClient,
searchRepository,
searchIndex,
fallbackMetadataProvider,
logger)
{
_dbContextFactory = dbContextFactory;
_entityLocker = entityLocker;
@@ -1,5 +1,6 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
@@ -13,6 +14,7 @@ namespace ErsatzTV.Application.MediaCollections;
public abstract class TraktCommandBase
{
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILogger _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
@@ -21,10 +23,12 @@ public abstract class TraktCommandBase
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger logger)
{
_searchRepository = searchRepository;
_searchIndex = searchIndex;
_fallbackMetadataProvider = fallbackMetadataProvider;
_logger = logger;
TraktApiClient = traktApiClient;
}
@@ -158,7 +162,7 @@ public abstract class TraktCommandBase
if (await dbContext.SaveChangesAsync() > 0)
{
await _searchIndex.RebuildItems(_searchRepository, ids.ToList());
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, ids.ToList());
}
_searchIndex.Commit();
@@ -12,6 +12,7 @@ namespace ErsatzTV.Application.Search;
public class RebuildSearchIndexHandler : IRequestHandler<RebuildSearchIndex, Unit>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<RebuildSearchIndexHandler> _logger;
private readonly ISearchIndex _searchIndex;
@@ -22,6 +23,7 @@ public class RebuildSearchIndexHandler : IRequestHandler<RebuildSearchIndex, Uni
ISearchRepository searchRepository,
IConfigElementRepository configElementRepository,
ILocalFileSystem localFileSystem,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger<RebuildSearchIndexHandler> logger)
{
_searchIndex = searchIndex;
@@ -29,6 +31,7 @@ public class RebuildSearchIndexHandler : IRequestHandler<RebuildSearchIndex, Uni
_searchRepository = searchRepository;
_configElementRepository = configElementRepository;
_localFileSystem = localFileSystem;
_fallbackMetadataProvider = fallbackMetadataProvider;
}
public async Task<Unit> Handle(RebuildSearchIndex request, CancellationToken cancellationToken)
@@ -48,7 +51,7 @@ public class RebuildSearchIndexHandler : IRequestHandler<RebuildSearchIndex, Uni
_logger.LogInformation("Migrating search index to version {Version}", _searchIndex.Version);
var sw = Stopwatch.StartNew();
await _searchIndex.Rebuild(_searchRepository);
await _searchIndex.Rebuild(_searchRepository, _fallbackMetadataProvider);
await _configElementRepository.Upsert(ConfigElementKey.SearchIndexVersion, _searchIndex.Version);
sw.Stop();
@@ -3,10 +3,14 @@ using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCards.Mapper;
namespace ErsatzTV.Application.Search;
@@ -14,7 +18,9 @@ namespace ErsatzTV.Application.Search;
public class
QuerySearchIndexEpisodesHandler : IRequestHandler<QuerySearchIndexEpisodes, TelevisionEpisodeCardResultsViewModel>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IEmbyPathReplacementService _embyPathReplacementService;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IPlexPathReplacementService _plexPathReplacementService;
@@ -27,7 +33,9 @@ public class
IMediaSourceRepository mediaSourceRepository,
IPlexPathReplacementService plexPathReplacementService,
IJellyfinPathReplacementService jellyfinPathReplacementService,
IEmbyPathReplacementService embyPathReplacementService)
IEmbyPathReplacementService embyPathReplacementService,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory)
{
_searchIndex = searchIndex;
_televisionRepository = televisionRepository;
@@ -35,6 +43,8 @@ public class
_plexPathReplacementService = plexPathReplacementService;
_jellyfinPathReplacementService = jellyfinPathReplacementService;
_embyPathReplacementService = embyPathReplacementService;
_fallbackMetadataProvider = fallbackMetadataProvider;
_dbContextFactory = dbContextFactory;
}
public async Task<TelevisionEpisodeCardResultsViewModel> Handle(
@@ -52,8 +62,40 @@ public class
Option<EmbyMediaSource> maybeEmby = await _mediaSourceRepository.GetAllEmby()
.Map(list => list.HeadOrNone());
List<EpisodeMetadata> episodes = await _televisionRepository
.GetEpisodesForCards(searchResult.Items.Map(i => i.Id).ToList());
var episodeIds = searchResult.Items.Map(i => i.Id).ToList();
List<EpisodeMetadata> episodes = await _televisionRepository.GetEpisodesForCards(episodeIds);
// try to load fallback metadata for episodes that have none
// this handles an edge case of trashed items with no saved metadata
var missingEpisodes = episodeIds.Except(episodes.Map(e => e.EpisodeId)).ToList();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
foreach (int missingEpisodeId in missingEpisodes)
{
Option<Episode> maybeEpisode = await dbContext.Episodes
.AsNoTracking()
.Include(e => e.MediaVersions)
.ThenInclude(e => e.MediaFiles)
.Include(e => e.Season)
.ThenInclude(s => s.SeasonMetadata)
.ThenInclude(sm => sm.Artwork)
.Include(e => e.Season)
.ThenInclude(s => s.Show)
.ThenInclude(s => s.ShowMetadata)
.ThenInclude(sm => sm.Artwork)
.SelectOneAsync(e => e.Id, e => e.Id == missingEpisodeId);
foreach (Episode episode in maybeEpisode)
{
foreach (EpisodeMetadata headMetadata in _fallbackMetadataProvider.GetFallbackMetadata(episode)
.HeadOrNone())
{
headMetadata.Episode = episode;
episode.EpisodeMetadata = new List<EpisodeMetadata> { headMetadata };
episodes.Add(headMetadata);
}
}
}
var items = new List<TelevisionEpisodeCardViewModel>();
@@ -40,6 +40,13 @@ public class FallbackMetadataProviderTests
"Awesome.Show.S01E02.Description.more.Description.QUAlity.codec.CODEC-GROUP.mkv",
1,
2)]
[TestCase("Awesome Show - s01.e02.mkv", 1, 2)]
[TestCase("Awesome Show - S01.E02.mkv", 1, 2)]
[TestCase("Awesome Show - s01_e02.mkv", 1, 2)]
[TestCase("Awesome Show - S01_E02.mkv", 1, 2)]
[TestCase("Awesome Show - s01xe02.mkv", 1, 2)]
[TestCase("Awesome Show - S01XE02.mkv", 1, 2)]
[TestCase("Awesome Show - 1x02.mkv", 1, 2)]
public void GetFallbackMetadata_ShouldHandleVariousFormats(string path, int season, int episode)
{
List<EpisodeMetadata> metadata = _fallbackMetadataProvider.GetFallbackMetadata(
@@ -623,6 +623,7 @@ public class MovieFolderScannerTests
_imageCache.Object,
new Mock<ISearchIndex>().Object,
new Mock<ISearchRepository>().Object,
new Mock<IFallbackMetadataProvider>().Object,
new Mock<ILibraryRepository>().Object,
_mediaItemRepository.Object,
new Mock<IMediator>().Object,
@@ -643,6 +644,7 @@ public class MovieFolderScannerTests
_imageCache.Object,
new Mock<ISearchIndex>().Object,
new Mock<ISearchRepository>().Object,
new Mock<IFallbackMetadataProvider>().Object,
new Mock<ILibraryRepository>().Object,
_mediaItemRepository.Object,
new Mock<IMediator>().Object,
+5 -1
View File
@@ -1,5 +1,6 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using Microsoft.Extensions.Logging;
@@ -10,6 +11,7 @@ public class EmbyCollectionScanner : IEmbyCollectionScanner
{
private readonly IEmbyApiClient _embyApiClient;
private readonly IEmbyCollectionRepository _embyCollectionRepository;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILogger<EmbyCollectionScanner> _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
@@ -19,12 +21,14 @@ public class EmbyCollectionScanner : IEmbyCollectionScanner
IEmbyApiClient embyApiClient,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger<EmbyCollectionScanner> logger)
{
_embyCollectionRepository = embyCollectionRepository;
_embyApiClient = embyApiClient;
_searchRepository = searchRepository;
_searchIndex = searchIndex;
_fallbackMetadataProvider = fallbackMetadataProvider;
_logger = logger;
}
@@ -107,7 +111,7 @@ public class EmbyCollectionScanner : IEmbyCollectionScanner
var changedIds = removedIds.Except(addedIds).ToList();
changedIds.AddRange(addedIds.Except(removedIds));
await _searchIndex.RebuildItems(_searchRepository, changedIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, changedIds);
_searchIndex.Commit();
}
catch (Exception ex)
@@ -26,6 +26,7 @@ public class EmbyMovieLibraryScanner :
IMediaSourceRepository mediaSourceRepository,
IEmbyMovieRepository embyMovieRepository,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IEmbyPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
@@ -38,6 +39,7 @@ public class EmbyMovieLibraryScanner :
mediator,
searchIndex,
searchRepository,
fallbackMetadataProvider,
logger)
{
_embyApiClient = embyApiClient;
@@ -25,6 +25,7 @@ public class EmbyTelevisionLibraryScanner : MediaServerTelevisionLibraryScanner<
IEmbyTelevisionRepository televisionRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IEmbyPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
@@ -37,6 +38,7 @@ public class EmbyTelevisionLibraryScanner : MediaServerTelevisionLibraryScanner<
localFileSystem,
searchRepository,
searchIndex,
fallbackMetadataProvider,
mediator,
logger)
{
@@ -9,9 +9,18 @@ public interface ISearchIndex : IDisposable
{
public int Version { get; }
Task<bool> Initialize(ILocalFileSystem localFileSystem, IConfigElementRepository configElementRepository);
Task<Unit> Rebuild(ISearchRepository searchRepository);
Task<Unit> RebuildItems(ISearchRepository searchRepository, List<int> itemIds);
Task<Unit> UpdateItems(ISearchRepository searchRepository, List<MediaItem> items);
Task<Unit> Rebuild(ISearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider);
Task<Unit> RebuildItems(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<int> itemIds);
Task<Unit> UpdateItems(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<MediaItem> items);
Task<Unit> RemoveItems(List<int> ids);
Task<SearchResult> Search(string query, int skip, int limit, string searchField = "");
void Commit();
@@ -1,5 +1,6 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using Microsoft.Extensions.Logging;
@@ -8,6 +9,7 @@ namespace ErsatzTV.Core.Jellyfin;
public class JellyfinCollectionScanner : IJellyfinCollectionScanner
{
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly IJellyfinApiClient _jellyfinApiClient;
private readonly IJellyfinCollectionRepository _jellyfinCollectionRepository;
private readonly ILogger<JellyfinCollectionScanner> _logger;
@@ -19,12 +21,14 @@ public class JellyfinCollectionScanner : IJellyfinCollectionScanner
IJellyfinApiClient jellyfinApiClient,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger<JellyfinCollectionScanner> logger)
{
_jellyfinCollectionRepository = jellyfinCollectionRepository;
_jellyfinApiClient = jellyfinApiClient;
_searchRepository = searchRepository;
_searchIndex = searchIndex;
_fallbackMetadataProvider = fallbackMetadataProvider;
_logger = logger;
}
@@ -116,7 +120,7 @@ public class JellyfinCollectionScanner : IJellyfinCollectionScanner
var changedIds = removedIds.Except(addedIds).ToList();
changedIds.AddRange(addedIds.Except(removedIds));
await _searchIndex.RebuildItems(_searchRepository, changedIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, changedIds);
_searchIndex.Commit();
}
catch (Exception ex)
@@ -25,6 +25,7 @@ public class JellyfinMovieLibraryScanner :
IMediator mediator,
IJellyfinMovieRepository jellyfinMovieRepository,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IJellyfinPathReplacementService pathReplacementService,
IMediaSourceRepository mediaSourceRepository,
ILocalFileSystem localFileSystem,
@@ -38,6 +39,7 @@ public class JellyfinMovieLibraryScanner :
mediator,
searchIndex,
searchRepository,
fallbackMetadataProvider,
logger)
{
_jellyfinApiClient = jellyfinApiClient;
@@ -26,6 +26,7 @@ public class JellyfinTelevisionLibraryScanner : MediaServerTelevisionLibraryScan
IJellyfinTelevisionRepository televisionRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IJellyfinPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
@@ -38,6 +39,7 @@ public class JellyfinTelevisionLibraryScanner : MediaServerTelevisionLibraryScan
localFileSystem,
searchRepository,
searchIndex,
fallbackMetadataProvider,
mediator,
logger)
{
@@ -161,8 +161,14 @@ public class FallbackMetadataProvider : IFallbackMetadataProvider
try
{
const string PATTERN = @"[sS]\d+[eE]([e\-\d{1,2}]+)";
const string PATTERN = @"[sS]\d+[\._xX]?[eE]([e\-\d{1,2}]+)";
const string PATTERN_2 = @"\d+[\._xX]([e\-\d{1,2}]+)";
MatchCollection matches = Regex.Matches(fileName, PATTERN);
if (matches.Count == 0)
{
matches = Regex.Matches(fileName, PATTERN_2);
}
if (matches.Count > 0)
{
foreach (Match match in matches)
@@ -15,6 +15,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
where TMovie : Movie
where TEtag : MediaServerItemEtag
{
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalStatisticsProvider _localStatisticsProvider;
private readonly ILocalSubtitlesProvider _localSubtitlesProvider;
@@ -30,6 +31,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
IMediator mediator,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger logger)
{
_localStatisticsProvider = localStatisticsProvider;
@@ -38,6 +40,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
_mediator = mediator;
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_logger = logger;
}
@@ -168,7 +171,10 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -176,7 +182,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
// trash movies that are no longer present on the media server
var fileNotFoundItemIds = existingMovies.Map(m => m.MediaServerItemId).Except(incomingItemIds).ToList();
List<int> ids = await movieRepository.FlagFileNotFound(library, fileNotFoundItemIds);
await _searchIndex.RebuildItems(_searchRepository, ids);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, ids);
await _mediator.Publish(new LibraryScanProgress(library.Id, 0), cancellationToken);
@@ -241,7 +247,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
{
foreach (int id in await movieRepository.FlagUnavailable(library, incoming))
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { id });
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, new List<int> { id });
}
}
@@ -18,6 +18,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
where TEpisode : Episode
where TEtag : MediaServerItemEtag
{
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalStatisticsProvider _localStatisticsProvider;
private readonly ILocalSubtitlesProvider _localSubtitlesProvider;
@@ -32,6 +33,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
ILocalFileSystem localFileSystem,
ISearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IMediator mediator,
ILogger logger)
{
@@ -40,6 +42,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
_localFileSystem = localFileSystem;
_searchRepository = searchRepository;
_searchIndex = searchIndex;
_fallbackMetadataProvider = fallbackMetadataProvider;
_mediator = mediator;
_logger = logger;
}
@@ -196,7 +199,10 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -204,7 +210,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
// trash shows that are no longer present on the media server
var fileNotFoundItemIds = existingShows.Map(s => s.MediaServerItemId).Except(incomingItemIds).ToList();
List<int> ids = await televisionRepository.FlagFileNotFoundShows(library, fileNotFoundItemIds);
await _searchIndex.RebuildItems(_searchRepository, ids);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, ids);
await _mediator.Publish(new LibraryScanProgress(library.Id, 0), cancellationToken);
@@ -358,7 +364,10 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -366,7 +375,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
// trash seasons that are no longer present on the media server
var fileNotFoundItemIds = existingSeasons.Map(s => s.MediaServerItemId).Except(incomingItemIds).ToList();
List<int> ids = await televisionRepository.FlagFileNotFoundSeasons(library, fileNotFoundItemIds);
await _searchIndex.RebuildItems(_searchRepository, ids);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, ids);
return Unit.Default;
}
@@ -461,7 +470,10 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -469,7 +481,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
// trash episodes that are no longer present on the media server
var fileNotFoundItemIds = existingEpisodes.Map(m => m.MediaServerItemId).Except(incomingItemIds).ToList();
List<int> ids = await televisionRepository.FlagFileNotFoundEpisodes(library, fileNotFoundItemIds);
await _searchIndex.RebuildItems(_searchRepository, ids);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, ids);
return Unit.Default;
}
@@ -511,7 +523,7 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
{
foreach (int id in await televisionRepository.FlagUnavailable(library, incoming))
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { id });
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, new List<int> { id });
}
}
+8 -2
View File
@@ -15,6 +15,7 @@ namespace ErsatzTV.Core.Metadata;
public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
{
private readonly IClient _client;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
@@ -35,6 +36,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
IImageCache imageCache,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
ILibraryRepository libraryRepository,
IMediaItemRepository mediaItemRepository,
IMediator mediator,
@@ -59,6 +61,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
_localMetadataProvider = localMetadataProvider;
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_libraryRepository = libraryRepository;
_mediator = mediator;
_client = client;
@@ -160,7 +163,10 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
{
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
await _libraryRepository.SetEtag(libraryPath, knownFolder, movieFolder, etag);
@@ -174,7 +180,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
{
_logger.LogInformation("Flagging missing movie at {Path}", path);
List<int> ids = await FlagFileNotFound(libraryPath, path);
await _searchIndex.RebuildItems(_searchRepository, ids);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, ids);
}
else if (Path.GetFileName(path).StartsWith("._"))
{
@@ -15,6 +15,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
{
private readonly IArtistRepository _artistRepository;
private readonly IClient _client;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
@@ -34,6 +35,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
IImageCache imageCache,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IArtistRepository artistRepository,
IMusicVideoRepository musicVideoRepository,
ILibraryRepository libraryRepository,
@@ -58,6 +60,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
_localSubtitlesProvider = localSubtitlesProvider;
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_artistRepository = artistRepository;
_musicVideoRepository = musicVideoRepository;
_libraryRepository = libraryRepository;
@@ -137,7 +140,10 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -155,7 +161,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
{
_logger.LogInformation("Flagging missing music video at {Path}", path);
List<int> musicVideoIds = await FlagFileNotFound(libraryPath, path);
await _searchIndex.RebuildItems(_searchRepository, musicVideoIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, musicVideoIds);
}
else if (Path.GetFileName(path).StartsWith("._"))
{
@@ -330,7 +336,10 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
{
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -14,6 +14,7 @@ namespace ErsatzTV.Core.Metadata;
public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScanner
{
private readonly IClient _client;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
@@ -34,6 +35,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
IMediator mediator,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IOtherVideoRepository otherVideoRepository,
ILibraryRepository libraryRepository,
IMediaItemRepository mediaItemRepository,
@@ -57,6 +59,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
_mediator = mediator;
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_otherVideoRepository = otherVideoRepository;
_libraryRepository = libraryRepository;
_client = client;
@@ -160,7 +163,10 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
{
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -178,7 +184,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
{
_logger.LogInformation("Flagging missing other video at {Path}", path);
List<int> otherVideoIds = await FlagFileNotFound(libraryPath, path);
await _searchIndex.RebuildItems(_searchRepository, otherVideoIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, otherVideoIds);
}
else if (Path.GetFileName(path).StartsWith("._"))
{
+8 -2
View File
@@ -15,6 +15,7 @@ namespace ErsatzTV.Core.Metadata;
public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
{
private readonly IClient _client;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
@@ -33,6 +34,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
IMediator mediator,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
ISongRepository songRepository,
ILibraryRepository libraryRepository,
IMediaItemRepository mediaItemRepository,
@@ -55,6 +57,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
_mediator = mediator;
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_fallbackMetadataProvider = fallbackMetadataProvider;
_songRepository = songRepository;
_libraryRepository = libraryRepository;
_client = client;
@@ -155,7 +158,10 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
{
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -173,7 +179,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
{
_logger.LogInformation("Flagging missing song at {Path}", path);
List<int> songIds = await FlagFileNotFound(libraryPath, path);
await _searchIndex.RebuildItems(_searchRepository, songIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, songIds);
}
else if (Path.GetFileName(path).StartsWith("._"))
{
@@ -14,6 +14,7 @@ namespace ErsatzTV.Core.Metadata;
public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScanner
{
private readonly IClient _client;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILibraryRepository _libraryRepository;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILocalMetadataProvider _localMetadataProvider;
@@ -30,6 +31,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
ITelevisionRepository televisionRepository,
ILocalStatisticsProvider localStatisticsProvider,
ILocalMetadataProvider localMetadataProvider,
IFallbackMetadataProvider fallbackMetadataProvider,
ILocalSubtitlesProvider localSubtitlesProvider,
IMetadataRepository metadataRepository,
IImageCache imageCache,
@@ -55,6 +57,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
_localFileSystem = localFileSystem;
_televisionRepository = televisionRepository;
_localMetadataProvider = localMetadataProvider;
_fallbackMetadataProvider = fallbackMetadataProvider;
_localSubtitlesProvider = localSubtitlesProvider;
_metadataRepository = metadataRepository;
_searchIndex = searchIndex;
@@ -127,7 +130,10 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
if (result.IsAdded || result.IsUpdated)
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { result.Item.Id });
}
}
}
@@ -137,8 +143,9 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
if (!_localFileSystem.FileExists(path))
{
_logger.LogInformation("Flagging missing episode at {Path}", path);
List<int> episodeIds = await FlagFileNotFound(libraryPath, path);
await _searchIndex.RebuildItems(_searchRepository, episodeIds);
await _searchIndex.RebuildItems(_searchRepository, _fallbackMetadataProvider, episodeIds);
}
else if (Path.GetFileName(path).StartsWith("._"))
{
@@ -241,7 +248,10 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
await _libraryRepository.SetEtag(libraryPath, knownFolder, seasonFolder, etag);
season.Show = show;
await _searchIndex.RebuildItems(_searchRepository, new List<int> { season.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { season.Id });
}
}
}
@@ -287,7 +297,10 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
foreach (Episode episode in maybeEpisode.RightToSeq())
{
await _searchIndex.RebuildItems(_searchRepository, new List<int> { episode.Id });
await _searchIndex.RebuildItems(
_searchRepository,
_fallbackMetadataProvider,
new List<int> { episode.Id });
}
}
@@ -28,6 +28,7 @@ public class PlexMovieLibraryScanner :
IMetadataRepository metadataRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IMediator mediator,
IMediaSourceRepository mediaSourceRepository,
IPlexMovieRepository plexMovieRepository,
@@ -43,6 +44,7 @@ public class PlexMovieLibraryScanner :
mediator,
searchIndex,
searchRepository,
fallbackMetadataProvider,
logger)
{
_plexServerApiClient = plexServerApiClient;
@@ -28,6 +28,7 @@ public class PlexTelevisionLibraryScanner :
IMetadataRepository metadataRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IMediator mediator,
IMediaSourceRepository mediaSourceRepository,
IPlexPathReplacementService plexPathReplacementService,
@@ -42,6 +43,7 @@ public class PlexTelevisionLibraryScanner :
localFileSystem,
searchRepository,
searchIndex,
fallbackMetadataProvider,
mediator,
logger)
{
@@ -1,4 +1,3 @@
using System.Numerics;
using ErsatzTV.FFmpeg.Format;
namespace ErsatzTV.FFmpeg.Capabilities;
@@ -9,6 +9,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class SearchRepository : ISearchRepository
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly SemaphoreSlim _slim = new(1, 1);
private List<string> _allLanguageCodes;
public SearchRepository(IDbContextFactory<TvContext> dbContextFactory) => _dbContextFactory = dbContextFactory;
@@ -49,6 +51,8 @@ public class SearchRepository : ISearchRepository
.ThenInclude(em => em.Guids)
.Include(mi => (mi as Episode).MediaVersions)
.ThenInclude(em => em.Streams)
.Include(mi => (mi as Episode).MediaVersions)
.ThenInclude(em => em.MediaFiles)
.Include(mi => (mi as Episode).Season)
.ThenInclude(s => s.Show)
.ThenInclude(s => s.ShowMetadata)
@@ -161,9 +165,25 @@ public class SearchRepository : ISearchRepository
}
public async Task<List<string>> GetAllLanguageCodes(List<string> mediaCodes)
{
if (_allLanguageCodes == null)
{
await _slim.WaitAsync();
try
{
if (_allLanguageCodes == null)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.LanguageCodes.GetAllLanguageCodes(mediaCodes);
_allLanguageCodes = await dbContext.LanguageCodes.GetAllLanguageCodes(mediaCodes);
}
}
finally
{
_slim.Release();
}
}
return _allLanguageCodes;
}
public IAsyncEnumerable<MediaItem> GetAllMediaItems()
@@ -203,6 +223,8 @@ public class SearchRepository : ISearchRepository
.ThenInclude(em => em.Guids)
.Include(mi => (mi as Episode).MediaVersions)
.ThenInclude(em => em.Streams)
.Include(mi => (mi as Episode).MediaVersions)
.ThenInclude(em => em.MediaFiles)
.Include(mi => (mi as Episode).Season)
.ThenInclude(s => s.Show)
.ThenInclude(s => s.ShowMetadata)
+35 -10
View File
@@ -88,7 +88,7 @@ public sealed class SearchIndex : ISearchIndex
_initialized = false;
}
public int Version => 27;
public int Version => 28;
public async Task<bool> Initialize(
ILocalFileSystem localFileSystem,
@@ -117,7 +117,10 @@ public sealed class SearchIndex : ISearchIndex
return _initialized;
}
public async Task<Unit> UpdateItems(ISearchRepository searchRepository, List<MediaItem> items)
public async Task<Unit> UpdateItems(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<MediaItem> items)
{
foreach (MediaItem item in items)
{
@@ -139,7 +142,7 @@ public sealed class SearchIndex : ISearchIndex
await UpdateMusicVideo(searchRepository, musicVideo);
break;
case Episode episode:
await UpdateEpisode(searchRepository, episode);
await UpdateEpisode(searchRepository, fallbackMetadataProvider, episode);
break;
case OtherVideo otherVideo:
await UpdateOtherVideo(searchRepository, otherVideo);
@@ -215,27 +218,32 @@ public sealed class SearchIndex : ISearchIndex
_directory?.Dispose();
}
public async Task<Unit> Rebuild(ISearchRepository searchRepository)
public async Task<Unit> Rebuild(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider)
{
_writer.DeleteAll();
_writer.Commit();
await foreach (MediaItem mediaItem in searchRepository.GetAllMediaItems())
{
await RebuildItem(searchRepository, mediaItem);
await RebuildItem(searchRepository, fallbackMetadataProvider, mediaItem);
}
_writer.Commit();
return Unit.Default;
}
public async Task<Unit> RebuildItems(ISearchRepository searchRepository, List<int> itemIds)
public async Task<Unit> RebuildItems(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<int> itemIds)
{
foreach (int id in itemIds)
{
foreach (MediaItem mediaItem in await searchRepository.GetItemToIndex(id))
{
await RebuildItem(searchRepository, mediaItem);
await RebuildItem(searchRepository, fallbackMetadataProvider, mediaItem);
}
}
@@ -268,7 +276,10 @@ public sealed class SearchIndex : ISearchIndex
}
}
private async Task RebuildItem(ISearchRepository searchRepository, MediaItem mediaItem)
private async Task RebuildItem(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
MediaItem mediaItem)
{
switch (mediaItem)
{
@@ -288,7 +299,7 @@ public sealed class SearchIndex : ISearchIndex
await UpdateMusicVideo(searchRepository, musicVideo);
break;
case Episode episode:
await UpdateEpisode(searchRepository, episode);
await UpdateEpisode(searchRepository, fallbackMetadataProvider, episode);
break;
case OtherVideo otherVideo:
await UpdateOtherVideo(searchRepository, otherVideo);
@@ -807,8 +818,22 @@ public sealed class SearchIndex : ISearchIndex
}
}
private async Task UpdateEpisode(ISearchRepository searchRepository, Episode episode)
private async Task UpdateEpisode(
ISearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
Episode episode)
{
// try to load metadata here, since episodes without metadata won't index
if (episode.EpisodeMetadata.Count == 0)
{
episode.EpisodeMetadata ??= new List<EpisodeMetadata>();
episode.EpisodeMetadata = fallbackMetadataProvider.GetFallbackMetadata(episode);
foreach (EpisodeMetadata metadata in episode.EpisodeMetadata)
{
metadata.Episode = episode;
}
}
foreach (EpisodeMetadata metadata in episode.EpisodeMetadata)
{
try