Browse Source

fix search repo caching bug (#886)

* add failing test

* fix search repo bug

* update dependencies
pull/888/head
Jason Dove 4 years ago committed by GitHub
parent
commit
6895b9cc6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 6
      ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs
  3. 4
      ErsatzTV.Application/MediaCollections/Commands/AddTraktListHandler.cs
  4. 6
      ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs
  5. 4
      ErsatzTV.Application/MediaCollections/Commands/MatchTraktListItemsHandler.cs
  6. 6
      ErsatzTV.Application/MediaCollections/Commands/TraktCommandBase.cs
  7. 5
      ErsatzTV.Application/Search/Commands/RebuildSearchIndexHandler.cs
  8. 5
      ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs
  9. 5
      ErsatzTV.Core/Emby/EmbyCollectionScanner.cs
  10. 3
      ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs
  11. 3
      ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs
  12. 5
      ErsatzTV.Core/Interfaces/Repositories/Caching/ICachingSearchRepository.cs
  13. 7
      ErsatzTV.Core/Interfaces/Search/ISearchIndex.cs
  14. 5
      ErsatzTV.Core/Jellyfin/JellyfinCollectionScanner.cs
  15. 3
      ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs
  16. 3
      ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs
  17. 5
      ErsatzTV.Core/Metadata/MediaServerMovieLibraryScanner.cs
  18. 5
      ErsatzTV.Core/Metadata/MediaServerTelevisionLibraryScanner.cs
  19. 5
      ErsatzTV.Core/Metadata/MovieFolderScanner.cs
  20. 5
      ErsatzTV.Core/Metadata/MusicVideoFolderScanner.cs
  21. 5
      ErsatzTV.Core/Metadata/OtherVideoFolderScanner.cs
  22. 5
      ErsatzTV.Core/Metadata/SongFolderScanner.cs
  23. 5
      ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs
  24. 3
      ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs
  25. 3
      ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs
  26. 33
      ErsatzTV.Infrastructure.Tests/Data/Repositories/Caching/CachingSearchRepositoryTests.cs
  27. 25
      ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj
  28. 43
      ErsatzTV.Infrastructure/Data/Repositories/Caching/CachingSearchRepository.cs
  29. 24
      ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs
  30. 9
      ErsatzTV.Infrastructure/Search/SearchIndex.cs
  31. 6
      ErsatzTV.sln
  32. 2
      ErsatzTV/ErsatzTV.csproj
  33. 3
      ErsatzTV/Startup.cs

2
CHANGELOG.md

@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. @@ -4,6 +4,8 @@ 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
- Fix subtitle stream selection when subtitle language is different than audio language
## [0.6.3-beta] - 2022-07-04
### Fixed

6
ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
@ -17,11 +17,11 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -17,11 +17,11 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILogger<MoveLocalLibraryPathHandler> _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public MoveLocalLibraryPathHandler(
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,
ILogger<MoveLocalLibraryPathHandler> logger)

4
ErsatzTV.Application/MediaCollections/Commands/AddTraktListHandler.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
using ErsatzTV.Infrastructure.Data;
@ -18,7 +18,7 @@ public class AddTraktListHandler : TraktCommandBase, IRequestHandler<AddTraktLis @@ -18,7 +18,7 @@ public class AddTraktListHandler : TraktCommandBase, IRequestHandler<AddTraktLis
public AddTraktListHandler(
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,

6
ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
using ErsatzTV.Infrastructure.Data;
@ -17,11 +17,11 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler<DeleteTr @@ -17,11 +17,11 @@ public class DeleteTraktListHandler : TraktCommandBase, IRequestHandler<DeleteTr
private readonly IEntityLocker _entityLocker;
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public DeleteTraktListHandler(
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,

4
ErsatzTV.Application/MediaCollections/Commands/MatchTraktListItemsHandler.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
using ErsatzTV.Infrastructure.Data;
@ -19,7 +19,7 @@ public class MatchTraktListItemsHandler : TraktCommandBase, @@ -19,7 +19,7 @@ public class MatchTraktListItemsHandler : TraktCommandBase,
public MatchTraktListItemsHandler(
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IDbContextFactory<TvContext> dbContextFactory,

6
ErsatzTV.Application/MediaCollections/Commands/TraktCommandBase.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Interfaces.Trakt;
using ErsatzTV.Core.Trakt;
@ -17,11 +17,11 @@ public abstract class TraktCommandBase @@ -17,11 +17,11 @@ public abstract class TraktCommandBase
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILogger _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
protected TraktCommandBase(
ITraktApiClient traktApiClient,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger logger)

5
ErsatzTV.Application/Search/Commands/RebuildSearchIndexHandler.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core; @@ -3,6 +3,7 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using Humanizer;
using Microsoft.Extensions.Logging;
@ -16,11 +17,11 @@ public class RebuildSearchIndexHandler : IRequestHandler<RebuildSearchIndex, Uni @@ -16,11 +17,11 @@ public class RebuildSearchIndexHandler : IRequestHandler<RebuildSearchIndex, Uni
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<RebuildSearchIndexHandler> _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public RebuildSearchIndexHandler(
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IConfigElementRepository configElementRepository,
ILocalFileSystem localFileSystem,
IFallbackMetadataProvider fallbackMetadataProvider,

5
ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using ErsatzTV.Core.Tests.Fakes;
@ -622,7 +623,7 @@ public class MovieFolderScannerTests @@ -622,7 +623,7 @@ public class MovieFolderScannerTests
new Mock<IMetadataRepository>().Object,
_imageCache.Object,
new Mock<ISearchIndex>().Object,
new Mock<ISearchRepository>().Object,
new Mock<ICachingSearchRepository>().Object,
new Mock<IFallbackMetadataProvider>().Object,
new Mock<ILibraryRepository>().Object,
_mediaItemRepository.Object,
@ -643,7 +644,7 @@ public class MovieFolderScannerTests @@ -643,7 +644,7 @@ public class MovieFolderScannerTests
new Mock<IMetadataRepository>().Object,
_imageCache.Object,
new Mock<ISearchIndex>().Object,
new Mock<ISearchRepository>().Object,
new Mock<ICachingSearchRepository>().Object,
new Mock<IFallbackMetadataProvider>().Object,
new Mock<ILibraryRepository>().Object,
_mediaItemRepository.Object,

5
ErsatzTV.Core/Emby/EmbyCollectionScanner.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using Microsoft.Extensions.Logging;
@ -14,12 +15,12 @@ public class EmbyCollectionScanner : IEmbyCollectionScanner @@ -14,12 +15,12 @@ public class EmbyCollectionScanner : IEmbyCollectionScanner
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
private readonly ILogger<EmbyCollectionScanner> _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public EmbyCollectionScanner(
IEmbyCollectionRepository embyCollectionRepository,
IEmbyApiClient embyApiClient,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger<EmbyCollectionScanner> logger)

3
ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using MediatR;
@ -25,7 +26,7 @@ public class EmbyMovieLibraryScanner : @@ -25,7 +26,7 @@ public class EmbyMovieLibraryScanner :
IMediator mediator,
IMediaSourceRepository mediaSourceRepository,
IEmbyMovieRepository embyMovieRepository,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IEmbyPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,

3
ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using MediatR;
@ -24,7 +25,7 @@ public class EmbyTelevisionLibraryScanner : MediaServerTelevisionLibraryScanner< @@ -24,7 +25,7 @@ public class EmbyTelevisionLibraryScanner : MediaServerTelevisionLibraryScanner<
IMediaSourceRepository mediaSourceRepository,
IEmbyTelevisionRepository televisionRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IEmbyPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,

5
ErsatzTV.Core/Interfaces/Repositories/Caching/ICachingSearchRepository.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
namespace ErsatzTV.Core.Interfaces.Repositories.Caching;
public interface ICachingSearchRepository : ISearchRepository
{
}

7
ErsatzTV.Core/Interfaces/Search/ISearchIndex.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Search;
namespace ErsatzTV.Core.Interfaces.Search;
@ -9,15 +10,15 @@ public interface ISearchIndex : IDisposable @@ -9,15 +10,15 @@ public interface ISearchIndex : IDisposable
{
public int Version { get; }
Task<bool> Initialize(ILocalFileSystem localFileSystem, IConfigElementRepository configElementRepository);
Task<Unit> Rebuild(ISearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider);
Task<Unit> Rebuild(ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider);
Task<Unit> RebuildItems(
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<int> itemIds);
Task<Unit> UpdateItems(
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<MediaItem> items);

5
ErsatzTV.Core/Jellyfin/JellyfinCollectionScanner.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using Microsoft.Extensions.Logging;
@ -14,12 +15,12 @@ public class JellyfinCollectionScanner : IJellyfinCollectionScanner @@ -14,12 +15,12 @@ public class JellyfinCollectionScanner : IJellyfinCollectionScanner
private readonly IJellyfinCollectionRepository _jellyfinCollectionRepository;
private readonly ILogger<JellyfinCollectionScanner> _logger;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public JellyfinCollectionScanner(
IJellyfinCollectionRepository jellyfinCollectionRepository,
IJellyfinApiClient jellyfinApiClient,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger<JellyfinCollectionScanner> logger)

3
ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using MediatR;
@ -24,7 +25,7 @@ public class JellyfinMovieLibraryScanner : @@ -24,7 +25,7 @@ public class JellyfinMovieLibraryScanner :
ISearchIndex searchIndex,
IMediator mediator,
IJellyfinMovieRepository jellyfinMovieRepository,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IJellyfinPathReplacementService pathReplacementService,
IMediaSourceRepository mediaSourceRepository,

3
ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using MediatR;
@ -25,7 +26,7 @@ public class JellyfinTelevisionLibraryScanner : MediaServerTelevisionLibraryScan @@ -25,7 +26,7 @@ public class JellyfinTelevisionLibraryScanner : MediaServerTelevisionLibraryScan
IMediaSourceRepository mediaSourceRepository,
IJellyfinTelevisionRepository televisionRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IJellyfinPathReplacementService pathReplacementService,
ILocalFileSystem localFileSystem,

5
ErsatzTV.Core/Metadata/MediaServerMovieLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Domain.MediaServer; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Domain.MediaServer;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -22,7 +23,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -22,7 +23,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
private readonly ILogger _logger;
private readonly IMediator _mediator;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
protected MediaServerMovieLibraryScanner(
ILocalStatisticsProvider localStatisticsProvider,
@ -30,7 +31,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -30,7 +31,7 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
ILocalFileSystem localFileSystem,
IMediator mediator,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
ILogger logger)
{

5
ErsatzTV.Core/Metadata/MediaServerTelevisionLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Domain.MediaServer; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Domain.MediaServer;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -25,13 +26,13 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters, @@ -25,13 +26,13 @@ public abstract class MediaServerTelevisionLibraryScanner<TConnectionParameters,
private readonly ILogger _logger;
private readonly IMediator _mediator;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
protected MediaServerTelevisionLibraryScanner(
ILocalStatisticsProvider localStatisticsProvider,
ILocalSubtitlesProvider localSubtitlesProvider,
ILocalFileSystem localFileSystem,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ISearchIndex searchIndex,
IFallbackMetadataProvider fallbackMetadataProvider,
IMediator mediator,

5
ErsatzTV.Core/Metadata/MovieFolderScanner.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -24,7 +25,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -24,7 +25,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
private readonly IMediator _mediator;
private readonly IMovieRepository _movieRepository;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public MovieFolderScanner(
ILocalFileSystem localFileSystem,
@ -35,7 +36,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner @@ -35,7 +36,7 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
IMetadataRepository metadataRepository,
IImageCache imageCache,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
ILibraryRepository libraryRepository,
IMediaItemRepository mediaItemRepository,

5
ErsatzTV.Core/Metadata/MusicVideoFolderScanner.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -24,7 +25,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -24,7 +25,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
private readonly IMediator _mediator;
private readonly IMusicVideoRepository _musicVideoRepository;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public MusicVideoFolderScanner(
ILocalFileSystem localFileSystem,
@ -34,7 +35,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan @@ -34,7 +35,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
IMetadataRepository metadataRepository,
IImageCache imageCache,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IArtistRepository artistRepository,
IMusicVideoRepository musicVideoRepository,

5
ErsatzTV.Core/Metadata/OtherVideoFolderScanner.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -23,7 +24,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -23,7 +24,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
private readonly IMediator _mediator;
private readonly IOtherVideoRepository _otherVideoRepository;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
public OtherVideoFolderScanner(
ILocalFileSystem localFileSystem,
@ -34,7 +35,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan @@ -34,7 +35,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
IImageCache imageCache,
IMediator mediator,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IOtherVideoRepository otherVideoRepository,
ILibraryRepository libraryRepository,

5
ErsatzTV.Core/Metadata/SongFolderScanner.cs

@ -6,6 +6,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg; @@ -6,6 +6,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -22,7 +23,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -22,7 +23,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
private readonly ILogger<SongFolderScanner> _logger;
private readonly IMediator _mediator;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
private readonly ISongRepository _songRepository;
public SongFolderScanner(
@ -33,7 +34,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner @@ -33,7 +34,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
IImageCache imageCache,
IMediator mediator,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
ISongRepository songRepository,
ILibraryRepository libraryRepository,

5
ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs

@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg; @@ -5,6 +5,7 @@ using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using MediatR;
using Microsoft.Extensions.Logging;
@ -23,7 +24,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -23,7 +24,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
private readonly IMediator _mediator;
private readonly IMetadataRepository _metadataRepository;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly ICachingSearchRepository _searchRepository;
private readonly ITelevisionRepository _televisionRepository;
public TelevisionFolderScanner(
@ -36,7 +37,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan @@ -36,7 +37,7 @@ public class TelevisionFolderScanner : LocalFolderScanner, ITelevisionFolderScan
IMetadataRepository metadataRepository,
IImageCache imageCache,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
ILibraryRepository libraryRepository,
IMediaItemRepository mediaItemRepository,
IMediator mediator,

3
ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using MediatR;
@ -27,7 +28,7 @@ public class PlexMovieLibraryScanner : @@ -27,7 +28,7 @@ public class PlexMovieLibraryScanner :
IMovieRepository movieRepository,
IMetadataRepository metadataRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IMediator mediator,
IMediaSourceRepository mediaSourceRepository,

3
ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions; @@ -3,6 +3,7 @@ using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Metadata;
using MediatR;
@ -27,7 +28,7 @@ public class PlexTelevisionLibraryScanner : @@ -27,7 +28,7 @@ public class PlexTelevisionLibraryScanner :
ITelevisionRepository televisionRepository,
IMetadataRepository metadataRepository,
ISearchIndex searchIndex,
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
IMediator mediator,
IMediaSourceRepository mediaSourceRepository,

33
ErsatzTV.Infrastructure.Tests/Data/Repositories/Caching/CachingSearchRepositoryTests.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Data.Repositories.Caching;
using FluentAssertions;
using LanguageExt;
using Moq;
using NUnit.Framework;
namespace ErsatzTV.Infrastructure.Tests.Data.Repositories.Caching;
[TestFixture]
public class CachingSearchRepositoryTests
{
[Test]
public async Task GetAllLanguageCodes_Should_Cache_Languages_Separately()
{
var englishMediaCodes = new List<string> { "eng" };
var frenchMediaCodes = new List<string> { "fre" };
var englishResult = new List<string> { "english_result" };
var frenchResult = new List<string> { "french_result" };
var searchRepo = new Mock<ISearchRepository>();
searchRepo.Setup(x => x.GetAllLanguageCodes(englishMediaCodes)).Returns(englishResult.AsTask());
searchRepo.Setup(x => x.GetAllLanguageCodes(frenchMediaCodes)).Returns(frenchResult.AsTask());
var repo = new CachingSearchRepository(searchRepo.Object);
List<string> result1 = await repo.GetAllLanguageCodes(englishMediaCodes);
result1.Should().BeEquivalentTo(englishResult);
List<string> result2 = await repo.GetAllLanguageCodes(frenchMediaCodes);
result2.Should().BeEquivalentTo(frenchResult);
}
}

25
ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ErsatzTV.Infrastructure\ErsatzTV.Infrastructure.csproj" />
</ItemGroup>
</Project>

43
ErsatzTV.Infrastructure/Data/Repositories/Caching/CachingSearchRepository.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
using System.Collections.Concurrent;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
namespace ErsatzTV.Infrastructure.Data.Repositories.Caching;
public class CachingSearchRepository : ICachingSearchRepository
{
private readonly ConcurrentDictionary<List<string>, List<string>> _cache = new();
private readonly ISearchRepository _searchRepository;
private readonly SemaphoreSlim _slim = new(1, 1);
public CachingSearchRepository(ISearchRepository searchRepository) => _searchRepository = searchRepository;
public Task<Option<MediaItem>> GetItemToIndex(int id) => _searchRepository.GetItemToIndex(id);
public Task<List<string>> GetLanguagesForShow(Show show) => _searchRepository.GetLanguagesForShow(show);
public Task<List<string>> GetLanguagesForSeason(Season season) => _searchRepository.GetLanguagesForSeason(season);
public Task<List<string>> GetLanguagesForArtist(Artist artist) => _searchRepository.GetLanguagesForArtist(artist);
public async Task<List<string>> GetAllLanguageCodes(List<string> mediaCodes)
{
if (!_cache.ContainsKey(mediaCodes))
{
await _slim.WaitAsync();
try
{
_cache.TryAdd(mediaCodes, await _searchRepository.GetAllLanguageCodes(mediaCodes));
}
finally
{
_slim.Release();
}
}
return _cache[mediaCodes];
}
public IAsyncEnumerable<MediaItem> GetAllMediaItems() => _searchRepository.GetAllMediaItems();
}

24
ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs

@ -9,8 +9,6 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -9,8 +9,6 @@ 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;
@ -164,26 +162,10 @@ public class SearchRepository : ISearchRepository @@ -164,26 +162,10 @@ public class SearchRepository : ISearchRepository
new { ArtistId = artist.Id }).Map(result => result.ToList());
}
public async Task<List<string>> GetAllLanguageCodes(List<string> mediaCodes)
public virtual 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();
_allLanguageCodes = await dbContext.LanguageCodes.GetAllLanguageCodes(mediaCodes);
}
}
finally
{
_slim.Release();
}
}
return _allLanguageCodes;
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.LanguageCodes.GetAllLanguageCodes(mediaCodes);
}
public IAsyncEnumerable<MediaItem> GetAllMediaItems()

9
ErsatzTV.Infrastructure/Search/SearchIndex.cs

@ -3,6 +3,7 @@ using ErsatzTV.Core; @@ -3,6 +3,7 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Search;
using LanguageExt.UnsafeValueAccess;
@ -88,7 +89,7 @@ public sealed class SearchIndex : ISearchIndex @@ -88,7 +89,7 @@ public sealed class SearchIndex : ISearchIndex
_initialized = false;
}
public int Version => 28;
public int Version => 29;
public async Task<bool> Initialize(
ILocalFileSystem localFileSystem,
@ -118,7 +119,7 @@ public sealed class SearchIndex : ISearchIndex @@ -118,7 +119,7 @@ public sealed class SearchIndex : ISearchIndex
}
public async Task<Unit> UpdateItems(
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<MediaItem> items)
{
@ -219,7 +220,7 @@ public sealed class SearchIndex : ISearchIndex @@ -219,7 +220,7 @@ public sealed class SearchIndex : ISearchIndex
}
public async Task<Unit> Rebuild(
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider)
{
_writer.DeleteAll();
@ -235,7 +236,7 @@ public sealed class SearchIndex : ISearchIndex @@ -235,7 +236,7 @@ public sealed class SearchIndex : ISearchIndex
}
public async Task<Unit> RebuildItems(
ISearchRepository searchRepository,
ICachingSearchRepository searchRepository,
IFallbackMetadataProvider fallbackMetadataProvider,
List<int> itemIds)
{

6
ErsatzTV.sln

@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErsatzTV.FFmpeg", "ErsatzTV @@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErsatzTV.FFmpeg", "ErsatzTV
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErsatzTV.FFmpeg.Tests", "ErsatzTV.FFmpeg.Tests\ErsatzTV.FFmpeg.Tests.csproj", "{1C892530-CF92-4F43-8C64-BCEEF958D726}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErsatzTV.Infrastructure.Tests", "ErsatzTV.Infrastructure.Tests\ErsatzTV.Infrastructure.Tests.csproj", "{591FB3F4-4DD8-441B-B7C8-F2A42BF69992}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -48,6 +50,10 @@ Global @@ -48,6 +50,10 @@ Global
{1C892530-CF92-4F43-8C64-BCEEF958D726}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C892530-CF92-4F43-8C64-BCEEF958D726}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C892530-CF92-4F43-8C64-BCEEF958D726}.Release|Any CPU.Build.0 = Release|Any CPU
{591FB3F4-4DD8-441B-B7C8-F2A42BF69992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{591FB3F4-4DD8-441B-B7C8-F2A42BF69992}.Debug|Any CPU.Build.0 = Debug|Any CPU
{591FB3F4-4DD8-441B-B7C8-F2A42BF69992}.Release|Any CPU.ActiveCfg = Release|Any CPU
{591FB3F4-4DD8-441B-B7C8-F2A42BF69992}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
EndGlobalSection

2
ErsatzTV/ErsatzTV.csproj

@ -74,7 +74,7 @@ @@ -74,7 +74,7 @@
</PackageReference>
<PackageReference Include="MudBlazor" Version="6.0.11" />
<PackageReference Include="NaturalSort.Extension" Version="3.2.0" />
<PackageReference Include="PPioli.FluentValidation.Blazor" Version="5.0.0" />
<PackageReference Include="PPioli.FluentValidation.Blazor" Version="11.1.0" />
<PackageReference Include="Refit.HttpClientFactory" Version="6.3.2" />
<PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />

3
ErsatzTV/Startup.cs

@ -22,6 +22,7 @@ using ErsatzTV.Core.Interfaces.Metadata; @@ -22,6 +22,7 @@ using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Metadata.Nfo;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Repositories.Caching;
using ErsatzTV.Core.Interfaces.Runtime;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Interfaces.Search;
@ -36,6 +37,7 @@ using ErsatzTV.FFmpeg.Capabilities; @@ -36,6 +37,7 @@ using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.Formatters;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Data.Repositories;
using ErsatzTV.Infrastructure.Data.Repositories.Caching;
using ErsatzTV.Infrastructure.Emby;
using ErsatzTV.Infrastructure.GitHub;
using ErsatzTV.Infrastructure.Health;
@ -352,6 +354,7 @@ public class Startup @@ -352,6 +354,7 @@ public class Startup
services.AddScoped<IConfigElementRepository, ConfigElementRepository>();
services.AddScoped<ITelevisionRepository, TelevisionRepository>();
services.AddScoped<ISearchRepository, SearchRepository>();
services.AddScoped<ICachingSearchRepository, CachingSearchRepository>();
services.AddScoped<IMovieRepository, MovieRepository>();
services.AddScoped<IArtistRepository, ArtistRepository>();
services.AddScoped<IMusicVideoRepository, MusicVideoRepository>();

Loading…
Cancel
Save