diff --git a/CHANGELOG.md b/CHANGELOG.md index 4026878fa..4b2db1f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs b/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs index e02bfae6c..e223e29fd 100644 --- a/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs @@ -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 _logger; private readonly ISearchIndex _searchIndex; - private readonly ISearchRepository _searchRepository; + private readonly ICachingSearchRepository _searchRepository; public MoveLocalLibraryPathHandler( ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IDbContextFactory dbContextFactory, ILogger logger) diff --git a/ErsatzTV.Application/MediaCollections/Commands/AddTraktListHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/AddTraktListHandler.cs index 4ae9cd25c..3d71e2d70 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/AddTraktListHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/AddTraktListHandler.cs @@ -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 dbContextFactory, diff --git a/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs index 4e9577e4b..eb7fcb3ab 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/DeleteTraktListHandler.cs @@ -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 dbContextFactory, diff --git a/ErsatzTV.Application/MediaCollections/Commands/MatchTraktListItemsHandler.cs b/ErsatzTV.Application/MediaCollections/Commands/MatchTraktListItemsHandler.cs index fad2d2f19..eb1ec6f0b 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/MatchTraktListItemsHandler.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/MatchTraktListItemsHandler.cs @@ -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, public MatchTraktListItemsHandler( ITraktApiClient traktApiClient, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, ISearchIndex searchIndex, IFallbackMetadataProvider fallbackMetadataProvider, IDbContextFactory dbContextFactory, diff --git a/ErsatzTV.Application/MediaCollections/Commands/TraktCommandBase.cs b/ErsatzTV.Application/MediaCollections/Commands/TraktCommandBase.cs index 5e4078084..6ed15b3db 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/TraktCommandBase.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/TraktCommandBase.cs @@ -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 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) diff --git a/ErsatzTV.Application/Search/Commands/RebuildSearchIndexHandler.cs b/ErsatzTV.Application/Search/Commands/RebuildSearchIndexHandler.cs index 9637cf686..74abc4b46 100644 --- a/ErsatzTV.Application/Search/Commands/RebuildSearchIndexHandler.cs +++ b/ErsatzTV.Application/Search/Commands/RebuildSearchIndexHandler.cs @@ -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 _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, diff --git a/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs b/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs index 84d40d75b..d13da9f93 100644 --- a/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs +++ b/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs @@ -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 new Mock().Object, _imageCache.Object, new Mock().Object, - new Mock().Object, + new Mock().Object, new Mock().Object, new Mock().Object, _mediaItemRepository.Object, @@ -643,7 +644,7 @@ public class MovieFolderScannerTests new Mock().Object, _imageCache.Object, new Mock().Object, - new Mock().Object, + new Mock().Object, new Mock().Object, new Mock().Object, _mediaItemRepository.Object, diff --git a/ErsatzTV.Core/Emby/EmbyCollectionScanner.cs b/ErsatzTV.Core/Emby/EmbyCollectionScanner.cs index 85ed6c6d3..af3be79eb 100644 --- a/ErsatzTV.Core/Emby/EmbyCollectionScanner.cs +++ b/ErsatzTV.Core/Emby/EmbyCollectionScanner.cs @@ -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 private readonly IFallbackMetadataProvider _fallbackMetadataProvider; private readonly ILogger _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 logger) diff --git a/ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs b/ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs index 4f6ffaa68..98758960d 100644 --- a/ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs +++ b/ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs @@ -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 : IMediator mediator, IMediaSourceRepository mediaSourceRepository, IEmbyMovieRepository embyMovieRepository, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IEmbyPathReplacementService pathReplacementService, ILocalFileSystem localFileSystem, diff --git a/ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs b/ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs index 614dd7d2e..3c9a1777e 100644 --- a/ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs +++ b/ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs @@ -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< IMediaSourceRepository mediaSourceRepository, IEmbyTelevisionRepository televisionRepository, ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IEmbyPathReplacementService pathReplacementService, ILocalFileSystem localFileSystem, diff --git a/ErsatzTV.Core/Interfaces/Repositories/Caching/ICachingSearchRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/Caching/ICachingSearchRepository.cs new file mode 100644 index 000000000..6122b21d2 --- /dev/null +++ b/ErsatzTV.Core/Interfaces/Repositories/Caching/ICachingSearchRepository.cs @@ -0,0 +1,5 @@ +namespace ErsatzTV.Core.Interfaces.Repositories.Caching; + +public interface ICachingSearchRepository : ISearchRepository +{ +} diff --git a/ErsatzTV.Core/Interfaces/Search/ISearchIndex.cs b/ErsatzTV.Core/Interfaces/Search/ISearchIndex.cs index 94550300f..9b76fdd32 100644 --- a/ErsatzTV.Core/Interfaces/Search/ISearchIndex.cs +++ b/ErsatzTV.Core/Interfaces/Search/ISearchIndex.cs @@ -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 { public int Version { get; } Task Initialize(ILocalFileSystem localFileSystem, IConfigElementRepository configElementRepository); - Task Rebuild(ISearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider); + Task Rebuild(ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider); Task RebuildItems( - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, List itemIds); Task UpdateItems( - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, List items); diff --git a/ErsatzTV.Core/Jellyfin/JellyfinCollectionScanner.cs b/ErsatzTV.Core/Jellyfin/JellyfinCollectionScanner.cs index d7776f663..0ef2a2b63 100644 --- a/ErsatzTV.Core/Jellyfin/JellyfinCollectionScanner.cs +++ b/ErsatzTV.Core/Jellyfin/JellyfinCollectionScanner.cs @@ -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 private readonly IJellyfinCollectionRepository _jellyfinCollectionRepository; private readonly ILogger _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 logger) diff --git a/ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs b/ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs index cc873443a..559933245 100644 --- a/ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs +++ b/ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs @@ -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 : ISearchIndex searchIndex, IMediator mediator, IJellyfinMovieRepository jellyfinMovieRepository, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IJellyfinPathReplacementService pathReplacementService, IMediaSourceRepository mediaSourceRepository, diff --git a/ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs b/ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs index efc96d5f7..d6d77c004 100644 --- a/ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs +++ b/ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs @@ -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 IMediaSourceRepository mediaSourceRepository, IJellyfinTelevisionRepository televisionRepository, ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IJellyfinPathReplacementService pathReplacementService, ILocalFileSystem localFileSystem, diff --git a/ErsatzTV.Core/Metadata/MediaServerMovieLibraryScanner.cs b/ErsatzTV.Core/Metadata/MediaServerMovieLibraryScanner.cs index 5cf31c87d..1dc93695f 100644 --- a/ErsatzTV.Core/Metadata/MediaServerMovieLibraryScanner.cs +++ b/ErsatzTV.Core/Metadata/MediaServerMovieLibraryScanner.cs @@ -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 _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 IImageCache imageCache, IMediator mediator, ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, ISongRepository songRepository, ILibraryRepository libraryRepository, diff --git a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs index 5670ed992..753bd43ad 100644 --- a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs +++ b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs @@ -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 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 IMetadataRepository metadataRepository, IImageCache imageCache, ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, ILibraryRepository libraryRepository, IMediaItemRepository mediaItemRepository, IMediator mediator, diff --git a/ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs b/ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs index 92bf69d15..bd6aef8c3 100644 --- a/ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs +++ b/ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs @@ -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 : IMovieRepository movieRepository, IMetadataRepository metadataRepository, ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IMediator mediator, IMediaSourceRepository mediaSourceRepository, diff --git a/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs b/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs index 51b792c34..957872d97 100644 --- a/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs +++ b/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs @@ -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 : ITelevisionRepository televisionRepository, IMetadataRepository metadataRepository, ISearchIndex searchIndex, - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, IMediator mediator, IMediaSourceRepository mediaSourceRepository, diff --git a/ErsatzTV.Infrastructure.Tests/Data/Repositories/Caching/CachingSearchRepositoryTests.cs b/ErsatzTV.Infrastructure.Tests/Data/Repositories/Caching/CachingSearchRepositoryTests.cs new file mode 100644 index 000000000..8117f46ea --- /dev/null +++ b/ErsatzTV.Infrastructure.Tests/Data/Repositories/Caching/CachingSearchRepositoryTests.cs @@ -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 { "eng" }; + var frenchMediaCodes = new List { "fre" }; + var englishResult = new List { "english_result" }; + var frenchResult = new List { "french_result" }; + + var searchRepo = new Mock(); + 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 result1 = await repo.GetAllLanguageCodes(englishMediaCodes); + result1.Should().BeEquivalentTo(englishResult); + + List result2 = await repo.GetAllLanguageCodes(frenchMediaCodes); + result2.Should().BeEquivalentTo(frenchResult); + } +} diff --git a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj new file mode 100644 index 000000000..bbbceff16 --- /dev/null +++ b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + + + + diff --git a/ErsatzTV.Infrastructure/Data/Repositories/Caching/CachingSearchRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/Caching/CachingSearchRepository.cs new file mode 100644 index 000000000..5a21fc187 --- /dev/null +++ b/ErsatzTV.Infrastructure/Data/Repositories/Caching/CachingSearchRepository.cs @@ -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> _cache = new(); + private readonly ISearchRepository _searchRepository; + private readonly SemaphoreSlim _slim = new(1, 1); + + public CachingSearchRepository(ISearchRepository searchRepository) => _searchRepository = searchRepository; + + public Task> GetItemToIndex(int id) => _searchRepository.GetItemToIndex(id); + + public Task> GetLanguagesForShow(Show show) => _searchRepository.GetLanguagesForShow(show); + + public Task> GetLanguagesForSeason(Season season) => _searchRepository.GetLanguagesForSeason(season); + + public Task> GetLanguagesForArtist(Artist artist) => _searchRepository.GetLanguagesForArtist(artist); + + public async Task> GetAllLanguageCodes(List mediaCodes) + { + if (!_cache.ContainsKey(mediaCodes)) + { + await _slim.WaitAsync(); + try + { + _cache.TryAdd(mediaCodes, await _searchRepository.GetAllLanguageCodes(mediaCodes)); + } + finally + { + _slim.Release(); + } + } + + return _cache[mediaCodes]; + } + + public IAsyncEnumerable GetAllMediaItems() => _searchRepository.GetAllMediaItems(); +} diff --git a/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs index dfa8eb471..67c434e4c 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs @@ -9,8 +9,6 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; public class SearchRepository : ISearchRepository { private readonly IDbContextFactory _dbContextFactory; - private readonly SemaphoreSlim _slim = new(1, 1); - private List _allLanguageCodes; public SearchRepository(IDbContextFactory dbContextFactory) => _dbContextFactory = dbContextFactory; @@ -164,26 +162,10 @@ public class SearchRepository : ISearchRepository new { ArtistId = artist.Id }).Map(result => result.ToList()); } - public async Task> GetAllLanguageCodes(List mediaCodes) + public virtual async Task> GetAllLanguageCodes(List 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 GetAllMediaItems() diff --git a/ErsatzTV.Infrastructure/Search/SearchIndex.cs b/ErsatzTV.Infrastructure/Search/SearchIndex.cs index 03c9b3a8c..a5bec001b 100644 --- a/ErsatzTV.Infrastructure/Search/SearchIndex.cs +++ b/ErsatzTV.Infrastructure/Search/SearchIndex.cs @@ -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 _initialized = false; } - public int Version => 28; + public int Version => 29; public async Task Initialize( ILocalFileSystem localFileSystem, @@ -118,7 +119,7 @@ public sealed class SearchIndex : ISearchIndex } public async Task UpdateItems( - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, List items) { @@ -219,7 +220,7 @@ public sealed class SearchIndex : ISearchIndex } public async Task Rebuild( - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider) { _writer.DeleteAll(); @@ -235,7 +236,7 @@ public sealed class SearchIndex : ISearchIndex } public async Task RebuildItems( - ISearchRepository searchRepository, + ICachingSearchRepository searchRepository, IFallbackMetadataProvider fallbackMetadataProvider, List itemIds) { diff --git a/ErsatzTV.sln b/ErsatzTV.sln index 5f6f47f6c..2b4ae94e8 100644 --- a/ErsatzTV.sln +++ b/ErsatzTV.sln @@ -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 {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 diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj index aaeb0aac4..245d4a687 100644 --- a/ErsatzTV/ErsatzTV.csproj +++ b/ErsatzTV/ErsatzTV.csproj @@ -74,7 +74,7 @@ - + diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index 32aaf757a..2e121c39f 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -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; 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 services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped();