Browse Source

remove transient IDbConnection (#678)

pull/679/head
Jason Dove 4 years ago committed by GitHub
parent
commit
dcc8f19a6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      ErsatzTV.Application/Filler/Queries/GetPagedFillerPresetsHandler.cs
  2. 12
      ErsatzTV.Application/Libraries/Commands/DeleteLocalLibraryHandler.cs
  3. 31
      ErsatzTV.Application/Libraries/Commands/MoveLocalLibraryPathHandler.cs
  4. 18
      ErsatzTV.Application/Libraries/Queries/CountMediaItemsByLibraryHandler.cs
  5. 12
      ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs
  6. 12
      ErsatzTV.Application/MediaCollections/Queries/GetPagedMultiCollectionsHandler.cs
  7. 12
      ErsatzTV.Application/MediaCollections/Queries/GetPagedSmartCollectionsHandler.cs
  8. 12
      ErsatzTV.Application/MediaCollections/Queries/GetPagedTraktListsHandler.cs
  9. 38
      ErsatzTV.Infrastructure/Data/Repositories/ArtistRepository.cs
  10. 21
      ErsatzTV.Infrastructure/Data/Repositories/ArtworkRepository.cs
  11. 69
      ErsatzTV.Infrastructure/Data/Repositories/EmbyTelevisionRepository.cs
  12. 67
      ErsatzTV.Infrastructure/Data/Repositories/JellyfinTelevisionRepository.cs
  13. 112
      ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs
  14. 84
      ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs
  15. 32
      ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs
  16. 325
      ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs
  17. 214
      ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs
  18. 126
      ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs
  19. 55
      ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs
  20. 35
      ErsatzTV.Infrastructure/Data/Repositories/OtherVideoRepository.cs
  21. 37
      ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs
  22. 33
      ErsatzTV.Infrastructure/Data/Repositories/SongRepository.cs
  23. 128
      ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs
  24. 5
      ErsatzTV.Infrastructure/Data/TvContext.cs
  25. 3
      ErsatzTV/Startup.cs

12
ErsatzTV.Application/Filler/Queries/GetPagedFillerPresetsHandler.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.Filler.Mapper;
@ -8,22 +7,19 @@ namespace ErsatzTV.Application.Filler; @@ -8,22 +7,19 @@ namespace ErsatzTV.Application.Filler;
public class GetPagedFillerPresetsHandler : IRequestHandler<GetPagedFillerPresets, PagedFillerPresetsViewModel>
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedFillerPresetsHandler(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public GetPagedFillerPresetsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<PagedFillerPresetsViewModel> Handle(
GetPagedFillerPresets request,
CancellationToken cancellationToken)
{
int count = await _dbConnection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM FillerPreset");
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Connection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM FillerPreset");
List<FillerPresetViewModel> page = await dbContext.FillerPresets.FromSqlRaw(
@"SELECT * FROM FillerPreset
ORDER BY Name

12
ErsatzTV.Application/Libraries/Commands/DeleteLocalLibraryHandler.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Search;
@ -13,16 +12,13 @@ public class DeleteLocalLibraryHandler : LocalLibraryHandlerBase, @@ -13,16 +12,13 @@ public class DeleteLocalLibraryHandler : LocalLibraryHandlerBase,
IRequestHandler<DeleteLocalLibrary, Either<BaseError, Unit>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IDbConnection _dbConnection;
private readonly ISearchIndex _searchIndex;
public DeleteLocalLibraryHandler(
IDbContextFactory<TvContext> dbContextFactory,
IDbConnection dbConnection,
ISearchIndex searchIndex)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
_searchIndex = searchIndex;
}
@ -30,14 +26,14 @@ public class DeleteLocalLibraryHandler : LocalLibraryHandlerBase, @@ -30,14 +26,14 @@ public class DeleteLocalLibraryHandler : LocalLibraryHandlerBase,
DeleteLocalLibrary request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, LocalLibrary> validation = await LocalLibraryMustExist(dbContext, request);
return await LanguageExtensions.Apply(validation, localLibrary => DoDeletion(dbContext, localLibrary));
return await validation.Apply(localLibrary => DoDeletion(dbContext, localLibrary));
}
private async Task<Unit> DoDeletion(TvContext dbContext, LocalLibrary localLibrary)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT MediaItem.Id FROM MediaItem
INNER JOIN LibraryPath LP on MediaItem.LibraryPathId = LP.Id
WHERE LP.LibraryId = @LibraryId",

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

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -16,20 +15,17 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -16,20 +15,17 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IDbConnection _dbConnection;
private readonly ILogger<MoveLocalLibraryPathHandler> _logger;
public MoveLocalLibraryPathHandler(
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IDbContextFactory<TvContext> dbContextFactory,
IDbConnection dbConnection,
ILogger<MoveLocalLibraryPathHandler> logger)
{
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
_logger = logger;
}
@ -37,9 +33,9 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -37,9 +33,9 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
MoveLocalLibraryPath request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
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)
@ -50,7 +46,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -50,7 +46,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
path.LibraryId = newLibrary.Id;
if (await dbContext.SaveChangesAsync() > 0)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT MediaItem.Id FROM MediaItem WHERE LibraryPathId = @LibraryPathId",
new { LibraryPathId = path.Id })
.Map(result => result.ToList());
@ -60,7 +56,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -60,7 +56,7 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
Option<MediaItem> maybeMediaItem = await _searchRepository.GetItemToIndex(id);
foreach (MediaItem mediaItem in maybeMediaItem)
{
_logger.LogInformation("Moving item at {Path}", await GetPath(mediaItem));
_logger.LogInformation("Moving item at {Path}", await GetPath(dbContext, mediaItem));
await _searchIndex.UpdateItems(_searchRepository, new List<MediaItem> { mediaItem });
}
}
@ -91,21 +87,24 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath, @@ -91,21 +87,24 @@ public class MoveLocalLibraryPathHandler : IRequestHandler<MoveLocalLibraryPath,
.SelectOneAsync(a => a.Id, a => a.Id == request.TargetLibraryId)
.Map(o => o.ToValidation<BaseError>("LocalLibrary does not exist"));
private async Task<string> GetPath(MediaItem mediaItem) =>
private async Task<string> GetPath(TvContext dbContext, MediaItem mediaItem) =>
mediaItem switch
{
Movie => await _dbConnection.QuerySingleAsync<string>(
Movie => await dbContext.Connection.QuerySingleAsync<string>(
@"SELECT Path FROM MediaFile
INNER JOIN MediaVersion MV on MediaFile.MediaVersionId = MV.Id
WHERE MV.MovieId = @Id", new { mediaItem.Id }),
Episode => await _dbConnection.QuerySingleAsync<string>(
WHERE MV.MovieId = @Id",
new { mediaItem.Id }),
Episode => await dbContext.Connection.QuerySingleAsync<string>(
@"SELECT Path FROM MediaFile
INNER JOIN MediaVersion MV on MediaFile.MediaVersionId = MV.Id
WHERE MV.EpisodeId = @Id", new { mediaItem.Id }),
MusicVideo => await _dbConnection.QuerySingleAsync<string>(
WHERE MV.EpisodeId = @Id",
new { mediaItem.Id }),
MusicVideo => await dbContext.Connection.QuerySingleAsync<string>(
@"SELECT Path FROM MediaFile
INNER JOIN MediaVersion MV on MediaFile.MediaVersionId = MV.Id
WHERE MV.MusicVideoId = @Id", new { mediaItem.Id }),
WHERE MV.MusicVideoId = @Id",
new { mediaItem.Id }),
_ => null
};

18
ErsatzTV.Application/Libraries/Queries/CountMediaItemsByLibraryHandler.cs

@ -1,21 +1,25 @@ @@ -1,21 +1,25 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Libraries;
public class CountMediaItemsByLibraryHandler : IRequestHandler<CountMediaItemsByLibrary, int>
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public CountMediaItemsByLibraryHandler(IDbConnection dbConnection)
public CountMediaItemsByLibraryHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbConnection = dbConnection;
_dbContextFactory = dbContextFactory;
}
public Task<int> Handle(CountMediaItemsByLibrary request, CancellationToken cancellationToken) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<int> Handle(CountMediaItemsByLibrary request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Connection.QuerySingleAsync<int>(
@"SELECT COUNT(*) FROM MediaItem
INNER JOIN LibraryPath LP on MediaItem.LibraryPathId = LP.Id
WHERE LP.LibraryId = @LibraryId",
new { request.LibraryId });
}
}

12
ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections; @@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections;
public class GetPagedCollectionsHandler : IRequestHandler<GetPagedCollections, PagedMediaCollectionsViewModel>
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public GetPagedCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<PagedMediaCollectionsViewModel> Handle(
GetPagedCollections request,
CancellationToken cancellationToken)
{
int count = await _dbConnection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM Collection");
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Connection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM Collection");
List<MediaCollectionViewModel> page = await dbContext.Collections.FromSqlRaw(
@"SELECT * FROM Collection
ORDER BY Name

12
ErsatzTV.Application/MediaCollections/Queries/GetPagedMultiCollectionsHandler.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections; @@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections;
public class GetPagedMultiCollectionsHandler : IRequestHandler<GetPagedMultiCollections, PagedMultiCollectionsViewModel>
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public GetPagedMultiCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<PagedMultiCollectionsViewModel> Handle(
GetPagedMultiCollections request,
CancellationToken cancellationToken)
{
int count = await _dbConnection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM MultiCollection");
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Connection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM MultiCollection");
List<MultiCollectionViewModel> page = await dbContext.MultiCollections.FromSqlRaw(
@"SELECT * FROM MultiCollection
ORDER BY Name

12
ErsatzTV.Application/MediaCollections/Queries/GetPagedSmartCollectionsHandler.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections; @@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections;
public class GetPagedSmartCollectionsHandler : IRequestHandler<GetPagedSmartCollections, PagedSmartCollectionsViewModel>
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<PagedSmartCollectionsViewModel> Handle(
GetPagedSmartCollections request,
CancellationToken cancellationToken)
{
int count = await _dbConnection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM SmartCollection");
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Connection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM SmartCollection");
List<SmartCollectionViewModel> page = await dbContext.SmartCollections.FromSqlRaw(
@"SELECT * FROM SmartCollection
ORDER BY Name

12
ErsatzTV.Application/MediaCollections/Queries/GetPagedTraktListsHandler.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaCollections.Mapper;
@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections; @@ -8,22 +7,19 @@ namespace ErsatzTV.Application.MediaCollections;
public class GetPagedTraktListsHandler : IRequestHandler<GetPagedTraktLists, PagedTraktListsViewModel>
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetPagedTraktListsHandler(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public GetPagedTraktListsHandler(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<PagedTraktListsViewModel> Handle(
GetPagedTraktLists request,
CancellationToken cancellationToken)
{
int count = await _dbConnection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM TraktList");
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
int count = await dbContext.Connection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM TraktList");
List<TraktListViewModel> page = await dbContext.TraktLists.FromSqlRaw(
@"SELECT * FROM TraktList
ORDER BY Name

38
ErsatzTV.Infrastructure/Data/Repositories/ArtistRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -10,18 +9,16 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,18 +9,16 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class ArtistRepository : IArtistRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public ArtistRepository(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public ArtistRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<Option<Artist>> GetArtistByMetadata(int libraryPathId, ArtistMetadata metadata)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<int> maybeId = await dbContext.ArtistMetadata
.Where(
s => s.Title == metadata.Title && (metadata.MetadataKind == MetadataKind.Fallback ||
@ -58,7 +55,7 @@ public class ArtistRepository : IArtistRepository @@ -58,7 +55,7 @@ public class ArtistRepository : IArtistRepository
string artistFolder,
ArtistMetadata metadata)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
try
{
@ -87,7 +84,7 @@ public class ArtistRepository : IArtistRepository @@ -87,7 +84,7 @@ public class ArtistRepository : IArtistRepository
public async Task<List<int>> DeleteEmptyArtists(LibraryPath libraryPath)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<Artist> artists = await dbContext.Artists
.Filter(a => a.LibraryPathId == libraryPath.Id)
.Filter(a => a.MusicVideos.Count == 0)
@ -100,7 +97,7 @@ public class ArtistRepository : IArtistRepository @@ -100,7 +97,7 @@ public class ArtistRepository : IArtistRepository
public async Task<Option<Artist>> GetArtist(int artistId)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Artists
.Include(m => m.ArtistMetadata)
.ThenInclude(m => m.Artwork)
@ -127,20 +124,29 @@ public class ArtistRepository : IArtistRepository @@ -127,20 +124,29 @@ public class ArtistRepository : IArtistRepository
.ToListAsync();
}
public Task<bool> AddGenre(ArtistMetadata metadata, Genre genre) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddGenre(ArtistMetadata metadata, Genre genre)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Genre (Name, ArtistMetadataId) VALUES (@Name, @MetadataId)",
new { genre.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddStyle(ArtistMetadata metadata, Style style) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddStyle(ArtistMetadata metadata, Style style)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Style (Name, ArtistMetadataId) VALUES (@Name, @MetadataId)",
new { style.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddMood(ArtistMetadata metadata, Mood mood) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddMood(ArtistMetadata metadata, Mood mood)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Mood (Name, ArtistMetadataId) VALUES (@Name, @MetadataId)",
new { mood.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<List<MusicVideo>> GetArtistItems(int artistId)
{
@ -160,7 +166,7 @@ public class ArtistRepository : IArtistRepository @@ -160,7 +166,7 @@ public class ArtistRepository : IArtistRepository
public async Task<List<Artist>> GetAllArtists()
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Artists
.AsNoTracking()
.Include(a => a.ArtistMetadata)

21
ErsatzTV.Infrastructure/Data/Repositories/ArtworkRepository.cs

@ -1,18 +1,23 @@ @@ -1,18 +1,23 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Infrastructure.Data.Repositories;
public class ArtworkRepository : IArtworkRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public ArtworkRepository(IDbConnection dbConnection) => _dbConnection = dbConnection;
public ArtworkRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public Task<List<Artwork>> GetOrphanedArtwork() =>
_dbConnection.QueryAsync<Artwork>(
public async Task<List<Artwork>> GetOrphanedArtwork()
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<Artwork>(
@"SELECT A.Id, A.Path FROM Artwork A
WHERE A.ArtistMetadataId IS NULL AND A.EpisodeMetadataId IS NULL
AND A.SeasonMetadataId IS NULL AND A.ShowMetadataId IS NULL
@ -20,13 +25,15 @@ public class ArtworkRepository : IArtworkRepository @@ -20,13 +25,15 @@ public class ArtworkRepository : IArtworkRepository
AND A.SongMetadataId IS NULL AND A.ChannelId IS NULL
AND NOT EXISTS (SELECT * FROM Actor WHERE Actor.ArtworkId = A.Id)")
.Map(result => result.ToList());
}
public async Task<Unit> Delete(List<Artwork> artwork)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
IEnumerable<List<int>> chunks = Chunk(artwork.Map(a => a.Id), 100);
foreach (List<int> chunk in chunks)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM Artwork WHERE Id IN @Ids",
new { Ids = chunk });
}

69
ErsatzTV.Infrastructure/Data/Repositories/EmbyTelevisionRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Emby;
using ErsatzTV.Core.Interfaces.Repositories;
@ -10,17 +9,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,17 +9,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class EmbyTelevisionRepository : IEmbyTelevisionRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public EmbyTelevisionRepository(IDbConnection dbConnection, IDbContextFactory<TvContext> dbContextFactory)
public EmbyTelevisionRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbConnection = dbConnection;
_dbContextFactory = dbContextFactory;
}
public Task<List<EmbyItemEtag>> GetExistingShows(EmbyLibrary library) =>
_dbConnection.QueryAsync<EmbyItemEtag>(
public async Task<List<EmbyItemEtag>> GetExistingShows(EmbyLibrary library)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<EmbyItemEtag>(
@"SELECT ItemId, Etag FROM EmbyShow
INNER JOIN Show S on EmbyShow.Id = S.Id
INNER JOIN MediaItem MI on S.Id = MI.Id
@ -28,9 +27,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -28,9 +27,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
WHERE LP.LibraryId = @LibraryId",
new { LibraryId = library.Id })
.Map(result => result.ToList());
}
public Task<List<EmbyItemEtag>> GetExistingSeasons(EmbyLibrary library, string showItemId) =>
_dbConnection.QueryAsync<EmbyItemEtag>(
public async Task<List<EmbyItemEtag>> GetExistingSeasons(EmbyLibrary library, string showItemId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<EmbyItemEtag>(
@"SELECT EmbySeason.ItemId, EmbySeason.Etag FROM EmbySeason
INNER JOIN Season S on EmbySeason.Id = S.Id
INNER JOIN MediaItem MI on S.Id = MI.Id
@ -40,9 +42,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -40,9 +42,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
WHERE LP.LibraryId = @LibraryId AND JS.ItemId = @ShowItemId",
new { LibraryId = library.Id, ShowItemId = showItemId })
.Map(result => result.ToList());
}
public Task<List<EmbyItemEtag>> GetExistingEpisodes(EmbyLibrary library, string seasonItemId) =>
_dbConnection.QueryAsync<EmbyItemEtag>(
public async Task<List<EmbyItemEtag>> GetExistingEpisodes(EmbyLibrary library, string seasonItemId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<EmbyItemEtag>(
@"SELECT EmbyEpisode.ItemId, EmbyEpisode.Etag FROM EmbyEpisode
INNER JOIN Episode E on EmbyEpisode.Id = E.Id
INNER JOIN MediaItem MI on E.Id = MI.Id
@ -52,10 +57,11 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -52,10 +57,11 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
WHERE LP.LibraryId = @LibraryId AND JS.ItemId = @SeasonItemId",
new { LibraryId = library.Id, SeasonItemId = seasonItemId })
.Map(result => result.ToList());
}
public async Task<bool> AddShow(EmbyShow show)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.AddAsync(show);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -69,7 +75,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -69,7 +75,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
public async Task<Option<EmbyShow>> Update(EmbyShow show)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<EmbyShow> maybeExisting = await dbContext.EmbyShows
.Include(m => m.LibraryPath)
.ThenInclude(lp => lp.Library)
@ -245,11 +251,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -245,11 +251,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
{
try
{
season.ShowId = await _dbConnection.ExecuteScalarAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
season.ShowId = await dbContext.Connection.ExecuteScalarAsync<int>(
@"SELECT Id FROM EmbyShow WHERE ItemId = @ItemId",
new { show.ItemId });
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await dbContext.AddAsync(season);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -268,7 +275,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -268,7 +275,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
public async Task<Option<EmbySeason>> Update(EmbySeason season)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<EmbySeason> maybeExisting = await dbContext.EmbySeasons
.Include(m => m.LibraryPath)
.Include(m => m.SeasonMetadata)
@ -384,11 +391,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -384,11 +391,12 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
{
try
{
episode.SeasonId = await _dbConnection.ExecuteScalarAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
episode.SeasonId = await dbContext.Connection.ExecuteScalarAsync<int>(
@"SELECT Id FROM EmbySeason WHERE ItemId = @ItemId",
new { season.ItemId });
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await dbContext.AddAsync(episode);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -408,7 +416,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -408,7 +416,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
public async Task<Option<EmbyEpisode>> Update(EmbyEpisode episode)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<EmbyEpisode> maybeExisting = await dbContext.EmbyEpisodes
.Include(m => m.LibraryPath)
.ThenInclude(lp => lp.Library)
@ -551,39 +559,46 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -551,39 +559,46 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
public async Task<List<int>> RemoveMissingShows(EmbyLibrary library, List<string> showIds)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN EmbyShow js ON js.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
WHERE lp.LibraryId = @LibraryId AND js.ItemId IN @ShowIds",
new { LibraryId = library.Id, ShowIds = showIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
return ids;
}
public Task<Unit> RemoveMissingSeasons(EmbyLibrary library, List<string> seasonIds) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> RemoveMissingSeasons(EmbyLibrary library, List<string> seasonIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN EmbySeason js ON js.Id = m.Id
INNER JOIN LibraryPath LP on m.LibraryPathId = LP.Id
WHERE LP.LibraryId = @LibraryId AND js.ItemId IN @SeasonIds)",
new { LibraryId = library.Id, SeasonIds = seasonIds }).ToUnit();
}
public async Task<List<int>> RemoveMissingEpisodes(EmbyLibrary library, List<string> episodeIds)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN EmbyEpisode ee ON ee.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
WHERE lp.LibraryId = @LibraryId AND ee.ItemId IN @EpisodeIds",
new { LibraryId = library.Id, EpisodeIds = episodeIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
@ -592,7 +607,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -592,7 +607,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
public async Task<Unit> DeleteEmptySeasons(EmbyLibrary library)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<EmbySeason> seasons = await dbContext.EmbySeasons
.Filter(s => s.LibraryPath.LibraryId == library.Id)
.Filter(s => s.Episodes.Count == 0)
@ -604,7 +619,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository @@ -604,7 +619,7 @@ public class EmbyTelevisionRepository : IEmbyTelevisionRepository
public async Task<List<int>> DeleteEmptyShows(EmbyLibrary library)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<EmbyShow> shows = await dbContext.EmbyShows
.Filter(s => s.LibraryPath.LibraryId == library.Id)
.Filter(s => s.Seasons.Count == 0)

67
ErsatzTV.Infrastructure/Data/Repositories/JellyfinTelevisionRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Jellyfin;
@ -10,17 +9,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,17 +9,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public JellyfinTelevisionRepository(IDbConnection dbConnection, IDbContextFactory<TvContext> dbContextFactory)
public JellyfinTelevisionRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbConnection = dbConnection;
_dbContextFactory = dbContextFactory;
}
public Task<List<JellyfinItemEtag>> GetExistingShows(JellyfinLibrary library) =>
_dbConnection.QueryAsync<JellyfinItemEtag>(
public async Task<List<JellyfinItemEtag>> GetExistingShows(JellyfinLibrary library)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<JellyfinItemEtag>(
@"SELECT ItemId, Etag FROM JellyfinShow
INNER JOIN Show S on JellyfinShow.Id = S.Id
INNER JOIN MediaItem MI on S.Id = MI.Id
@ -28,9 +27,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -28,9 +27,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
WHERE LP.LibraryId = @LibraryId",
new { LibraryId = library.Id })
.Map(result => result.ToList());
}
public Task<List<JellyfinItemEtag>> GetExistingSeasons(JellyfinLibrary library, string showItemId) =>
_dbConnection.QueryAsync<JellyfinItemEtag>(
public async Task<List<JellyfinItemEtag>> GetExistingSeasons(JellyfinLibrary library, string showItemId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<JellyfinItemEtag>(
@"SELECT JellyfinSeason.ItemId, JellyfinSeason.Etag FROM JellyfinSeason
INNER JOIN Season S on JellyfinSeason.Id = S.Id
INNER JOIN MediaItem MI on S.Id = MI.Id
@ -40,9 +42,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -40,9 +42,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
WHERE LP.LibraryId = @LibraryId AND JS.ItemId = @ShowItemId",
new { LibraryId = library.Id, ShowItemId = showItemId })
.Map(result => result.ToList());
}
public Task<List<JellyfinItemEtag>> GetExistingEpisodes(JellyfinLibrary library, string seasonItemId) =>
_dbConnection.QueryAsync<JellyfinItemEtag>(
public async Task<List<JellyfinItemEtag>> GetExistingEpisodes(JellyfinLibrary library, string seasonItemId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<JellyfinItemEtag>(
@"SELECT JellyfinEpisode.ItemId, JellyfinEpisode.Etag FROM JellyfinEpisode
INNER JOIN Episode E on JellyfinEpisode.Id = E.Id
INNER JOIN MediaItem MI on E.Id = MI.Id
@ -52,10 +57,11 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -52,10 +57,11 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
WHERE LP.LibraryId = @LibraryId AND JS.ItemId = @SeasonItemId",
new { LibraryId = library.Id, SeasonItemId = seasonItemId })
.Map(result => result.ToList());
}
public async Task<bool> AddShow(JellyfinShow show)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.AddAsync(show);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -69,7 +75,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -69,7 +75,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
public async Task<Option<JellyfinShow>> Update(JellyfinShow show)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<JellyfinShow> maybeExisting = await dbContext.JellyfinShows
.Include(m => m.LibraryPath)
.ThenInclude(lp => lp.Library)
@ -262,11 +268,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -262,11 +268,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
{
try
{
season.ShowId = await _dbConnection.ExecuteScalarAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
season.ShowId = await dbContext.Connection.ExecuteScalarAsync<int>(
@"SELECT Id FROM JellyfinShow WHERE ItemId = @ItemId",
new { show.ItemId });
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await dbContext.AddAsync(season);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -285,7 +292,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -285,7 +292,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
public async Task<Option<JellyfinSeason>> Update(JellyfinSeason season)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<JellyfinSeason> maybeExisting = await dbContext.JellyfinSeasons
.Include(m => m.LibraryPath)
.Include(m => m.SeasonMetadata)
@ -385,11 +392,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -385,11 +392,12 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
{
try
{
episode.SeasonId = await _dbConnection.ExecuteScalarAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
episode.SeasonId = await dbContext.Connection.ExecuteScalarAsync<int>(
@"SELECT Id FROM JellyfinSeason WHERE ItemId = @ItemId",
new { season.ItemId });
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await dbContext.AddAsync(episode);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -409,7 +417,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -409,7 +417,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
public async Task<Option<JellyfinEpisode>> Update(JellyfinEpisode episode)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<JellyfinEpisode> maybeExisting = await dbContext.JellyfinEpisodes
.Include(m => m.LibraryPath)
.ThenInclude(lp => lp.Library)
@ -552,39 +560,44 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -552,39 +560,44 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
public async Task<List<int>> RemoveMissingShows(JellyfinLibrary library, List<string> showIds)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinShow js ON js.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
WHERE lp.LibraryId = @LibraryId AND js.ItemId IN @ShowIds",
new { LibraryId = library.Id, ShowIds = showIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
return ids;
}
public Task<Unit> RemoveMissingSeasons(JellyfinLibrary library, List<string> seasonIds) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> RemoveMissingSeasons(JellyfinLibrary library, List<string> seasonIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinSeason js ON js.Id = m.Id
INNER JOIN LibraryPath LP on m.LibraryPathId = LP.Id
WHERE LP.LibraryId = @LibraryId AND js.ItemId IN @SeasonIds)",
new { LibraryId = library.Id, SeasonIds = seasonIds }).ToUnit();
}
public async Task<List<int>> RemoveMissingEpisodes(JellyfinLibrary library, List<string> episodeIds)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinEpisode je ON je.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
WHERE lp.LibraryId = @LibraryId AND je.ItemId IN @EpisodeIds",
new { LibraryId = library.Id, EpisodeIds = episodeIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
@ -593,7 +606,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -593,7 +606,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
public async Task<Unit> DeleteEmptySeasons(JellyfinLibrary library)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<JellyfinSeason> seasons = await dbContext.JellyfinSeasons
.Filter(s => s.LibraryPath.LibraryId == library.Id)
.Filter(s => s.Episodes.Count == 0)
@ -605,7 +618,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository @@ -605,7 +618,7 @@ public class JellyfinTelevisionRepository : IJellyfinTelevisionRepository
public async Task<List<int>> DeleteEmptyShows(JellyfinLibrary library)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<JellyfinShow> shows = await dbContext.JellyfinShows
.Filter(s => s.LibraryPath.LibraryId == library.Id)
.Filter(s => s.Seasons.Count == 0)

112
ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
@ -9,32 +8,27 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -9,32 +8,27 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class LibraryRepository : ILibraryRepository
{
private readonly IDbConnection _dbConnection;
private readonly ILocalFileSystem _localFileSystem;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public LibraryRepository(
ILocalFileSystem localFileSystem,
IDbContextFactory<TvContext> dbContextFactory,
IDbConnection dbConnection)
public LibraryRepository(ILocalFileSystem localFileSystem, IDbContextFactory<TvContext> dbContextFactory)
{
_localFileSystem = localFileSystem;
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<LibraryPath> Add(LibraryPath libraryPath)
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await context.LibraryPaths.AddAsync(libraryPath);
await context.SaveChangesAsync();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.LibraryPaths.AddAsync(libraryPath);
await dbContext.SaveChangesAsync();
return libraryPath;
}
public Task<Option<Library>> Get(int libraryId)
public async Task<Option<Library>> Get(int libraryId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.Libraries
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Libraries
.Include(l => l.Paths)
.ThenInclude(p => p.LibraryFolders)
.OrderBy(l => l.Id)
@ -42,37 +36,45 @@ public class LibraryRepository : ILibraryRepository @@ -42,37 +36,45 @@ public class LibraryRepository : ILibraryRepository
.Map(Optional);
}
public Task<Option<LocalLibrary>> GetLocal(int libraryId)
public async Task<Option<LocalLibrary>> GetLocal(int libraryId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.LocalLibraries
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.LocalLibraries
.OrderBy(l => l.Id)
.SingleOrDefaultAsync(l => l.Id == libraryId)
.Map(Optional);
}
public Task<List<Library>> GetAll()
public async Task<List<Library>> GetAll()
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.Libraries
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Libraries
.AsNoTracking()
.Include(l => l.MediaSource)
.Include(l => l.Paths)
.ToListAsync();
}
public Task<Unit> UpdateLastScan(Library library) => _dbConnection.ExecuteAsync(
"UPDATE Library SET LastScan = @LastScan WHERE Id = @Id",
new { library.LastScan, library.Id }).ToUnit();
public async Task<Unit> UpdateLastScan(Library library)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE Library SET LastScan = @LastScan WHERE Id = @Id",
new { library.LastScan, library.Id }).ToUnit();
}
public Task<Unit> UpdateLastScan(LibraryPath libraryPath) => _dbConnection.ExecuteAsync(
"UPDATE LibraryPath SET LastScan = @LastScan WHERE Id = @Id",
new { libraryPath.LastScan, libraryPath.Id }).ToUnit();
public async Task<Unit> UpdateLastScan(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE LibraryPath SET LastScan = @LastScan WHERE Id = @Id",
new { libraryPath.LastScan, libraryPath.Id }).ToUnit();
}
public Task<List<LibraryPath>> GetLocalPaths(int libraryId)
public async Task<List<LibraryPath>> GetLocalPaths(int libraryId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.LocalLibraries
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.LocalLibraries
.Include(l => l.Paths)
.OrderBy(l => l.Id)
.SingleOrDefaultAsync(l => l.Id == libraryId)
@ -80,62 +82,76 @@ public class LibraryRepository : ILibraryRepository @@ -80,62 +82,76 @@ public class LibraryRepository : ILibraryRepository
.Match(l => l.Paths, () => new List<LibraryPath>());
}
public Task<Option<LibraryPath>> GetPath(int libraryPathId)
public async Task<Option<LibraryPath>> GetPath(int libraryPathId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.LibraryPaths
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.LibraryPaths
.OrderBy(lp => lp.Id)
.SingleOrDefaultAsync(lp => lp.Id == libraryPathId)
.Map(Optional);
}
public Task<int> CountMediaItemsByPath(int libraryPathId) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<int> CountMediaItemsByPath(int libraryPathId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<int>(
@"SELECT COUNT(*) FROM MediaItem WHERE LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPathId });
}
public Task<List<int>> GetMediaIdsByLocalPath(int libraryPathId) =>
_dbConnection.QueryAsync<int>(
public async Task<List<int>> GetMediaIdsByLocalPath(int libraryPathId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<int>(
@"SELECT Id FROM MediaItem WHERE LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPathId })
.Map(result => result.ToList());
}
public async Task DeleteLocalPath(int libraryPathId)
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
LibraryPath libraryPath = await context.LibraryPaths.FindAsync(libraryPathId);
context.LibraryPaths.Remove(libraryPath);
await context.SaveChangesAsync();
if (libraryPath != null)
{
context.LibraryPaths.Remove(libraryPath);
await context.SaveChangesAsync();
}
}
public Task<Unit> SetEtag(
public async Task<Unit> SetEtag(
LibraryPath libraryPath,
Option<LibraryFolder> knownFolder,
string path,
string etag) =>
knownFolder.Match(
string etag)
{
return await knownFolder.Match(
async folder =>
{
await _dbConnection.ExecuteAsync(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.Connection.ExecuteAsync(
"UPDATE LibraryFolder SET Etag = @Etag WHERE Id = @Id",
new { folder.Id, Etag = etag });
},
async () =>
{
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
await context.LibraryFolders.AddAsync(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.LibraryFolders.AddAsync(
new LibraryFolder
{
Path = path,
Etag = etag,
LibraryPathId = libraryPath.Id
});
await context.SaveChangesAsync();
await dbContext.SaveChangesAsync();
}).ToUnit();
}
public async Task<Unit> CleanEtagsForLibraryPath(LibraryPath libraryPath)
{
IEnumerable<string> folders = await _dbConnection.QueryAsync<string>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
IEnumerable<string> folders = await dbContext.Connection.QueryAsync<string>(
@"SELECT LF.Path
FROM LibraryFolder LF
WHERE LF.LibraryPathId = @LibraryPathId",
@ -143,7 +159,7 @@ public class LibraryRepository : ILibraryRepository @@ -143,7 +159,7 @@ public class LibraryRepository : ILibraryRepository
foreach (string folder in folders.Where(f => !_localFileSystem.FolderExists(f)))
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM LibraryFolder WHERE LibraryPathId = @LibraryPathId AND Path = @Path",
new { LibraryPathId = libraryPath.Id, Path = folder });
}

84
ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
@ -13,18 +12,15 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -13,18 +12,15 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MediaCollectionRepository : IMediaCollectionRepository
{
private readonly IDbConnection _dbConnection;
private readonly ISearchIndex _searchIndex;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MediaCollectionRepository(
ISearchIndex searchIndex,
IDbContextFactory<TvContext> dbContextFactory,
IDbConnection dbConnection)
IDbContextFactory<TvContext> dbContextFactory)
{
_searchIndex = searchIndex;
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<Option<Collection>> GetCollectionWithCollectionItemsUntracked(int id)
@ -85,7 +81,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -85,7 +81,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
result.AddRange(await GetSmartCollectionItems(smartCollectionId));
}
}
return result.Distinct().ToList();
}
@ -101,7 +97,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -101,7 +97,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
foreach (SmartCollection collection in maybeCollection)
{
SearchResult searchResults = await _searchIndex.Search(collection.Query, 0, 0);
var movieIds = searchResults.Items
.Filter(i => i.Type == SearchIndex.MovieType)
.Map(i => i.Id)
@ -130,7 +126,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -130,7 +126,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
.Map(i => i.Id)
.ToList();
result.AddRange(await GetMusicVideoItems(dbContext, musicVideoIds));
var episodeIds = searchResults.Items
.Filter(i => i.Type == SearchIndex.EpisodeType)
.Map(i => i.Id)
@ -283,7 +279,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -283,7 +279,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
PlaybackOrder.Chronological,
false));
}
var artistCollections = new Dictionary<int, List<MediaItem>>();
foreach (MusicVideo musicVideo in items.OfType<MusicVideo>())
{
@ -325,7 +321,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -325,7 +321,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
foreach (Song song in items.OfType<Song>())
{
int key = allArtists.IndexOf(song.SongMetadata.HeadOrNone().Match(sm => sm.AlbumArtist, string.Empty));
List<MediaItem> list = songArtistCollections.ContainsKey(key)
? songArtistCollections[key]
: new List<MediaItem>();
@ -360,34 +356,46 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -360,34 +356,46 @@ public class MediaCollectionRepository : IMediaCollectionRepository
return result;
}
public Task<List<int>> PlayoutIdsUsingCollection(int collectionId) =>
_dbConnection.QueryAsync<int>(
public async Task<List<int>> PlayoutIdsUsingCollection(int collectionId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<int>(
@"SELECT DISTINCT p.PlayoutId
FROM PlayoutProgramScheduleAnchor p
WHERE p.CollectionId = @CollectionId",
new { CollectionId = collectionId })
.Map(result => result.ToList());
}
public Task<List<int>> PlayoutIdsUsingMultiCollection(int multiCollectionId) =>
_dbConnection.QueryAsync<int>(
public async Task<List<int>> PlayoutIdsUsingMultiCollection(int multiCollectionId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<int>(
@"SELECT DISTINCT p.PlayoutId
FROM PlayoutProgramScheduleAnchor p
WHERE p.MultiCollectionId = @MultiCollectionId",
new { MultiCollectionId = multiCollectionId })
.Map(result => result.ToList());
}
public Task<List<int>> PlayoutIdsUsingSmartCollection(int smartCollectionId) =>
_dbConnection.QueryAsync<int>(
public async Task<List<int>> PlayoutIdsUsingSmartCollection(int smartCollectionId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<int>(
@"SELECT DISTINCT p.PlayoutId
FROM PlayoutProgramScheduleAnchor p
WHERE p.SmartCollectionId = @SmartCollectionId",
new { SmartCollectionId = smartCollectionId })
.Map(result => result.ToList());
}
public Task<bool> IsCustomPlaybackOrder(int collectionId) =>
_dbConnection.QuerySingleAsync<bool>(
public async Task<bool> IsCustomPlaybackOrder(int collectionId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<bool>(
@"SELECT IFNULL(MIN(UseCustomPlaybackOrder), 0) FROM Collection WHERE Id = @CollectionId",
new { CollectionId = collectionId });
}
public async Task<Option<string>> GetNameFromKey(CollectionKey emptyCollection)
{
@ -422,7 +430,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -422,7 +430,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<Movie>> GetMovieItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM CollectionItem ci
INNER JOIN Movie m ON m.Id = ci.MediaItemId
WHERE ci.CollectionId = @CollectionId",
@ -430,7 +438,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -430,7 +438,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
return await GetMovieItems(dbContext, ids);
}
private static Task<List<Movie>> GetMovieItems(TvContext dbContext, IEnumerable<int> movieIds) =>
dbContext.Movies
.Include(m => m.MovieMetadata)
@ -443,7 +451,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -443,7 +451,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<MusicVideo>> GetArtistItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT MusicVideo.Id FROM CollectionItem ci
INNER JOIN Artist on Artist.Id = ci.MediaItemId
INNER JOIN MusicVideo on Artist.Id = MusicVideo.ArtistId
@ -466,10 +474,10 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -466,10 +474,10 @@ public class MediaCollectionRepository : IMediaCollectionRepository
.ThenInclude(mv => mv.MediaFiles)
.Filter(m => musicVideoIds.Contains(m.Id))
.ToListAsync();
private async Task<List<MusicVideo>> GetArtistItemsFromArtistId(TvContext dbContext, int artistId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT MusicVideo.Id FROM Artist
INNER JOIN MusicVideo on Artist.Id = MusicVideo.ArtistId
WHERE Artist.Id = @ArtistId",
@ -480,7 +488,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -480,7 +488,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<MusicVideo>> GetMusicVideoItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM CollectionItem ci
INNER JOIN MusicVideo m ON m.Id = ci.MediaItemId
WHERE ci.CollectionId = @CollectionId",
@ -488,7 +496,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -488,7 +496,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
return await GetMusicVideoItems(dbContext, ids);
}
private static Task<List<MusicVideo>> GetMusicVideoItems(TvContext dbContext, IEnumerable<int> musicVideoIds) =>
dbContext.MusicVideos
.Include(m => m.Artist)
@ -500,10 +508,10 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -500,10 +508,10 @@ public class MediaCollectionRepository : IMediaCollectionRepository
.ThenInclude(mv => mv.MediaFiles)
.Filter(m => musicVideoIds.Contains(m.Id))
.ToListAsync();
private async Task<List<OtherVideo>> GetOtherVideoItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT o.Id FROM CollectionItem ci
INNER JOIN OtherVideo o ON o.Id = ci.MediaItemId
WHERE ci.CollectionId = @CollectionId",
@ -524,7 +532,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -524,7 +532,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<Song>> GetSongItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT s.Id FROM CollectionItem ci
INNER JOIN Song s ON s.Id = ci.MediaItemId
WHERE ci.CollectionId = @CollectionId",
@ -545,7 +553,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -545,7 +553,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<Episode>> GetShowItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT Episode.Id FROM CollectionItem ci
INNER JOIN Show ON Show.Id = ci.MediaItemId
INNER JOIN Season ON Season.ShowId = Show.Id
@ -555,7 +563,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -555,7 +563,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
return await GetShowItemsFromEpisodeIds(dbContext, ids);
}
private static Task<List<Episode>> GetShowItemsFromEpisodeIds(TvContext dbContext, IEnumerable<int> episodeIds) =>
dbContext.Episodes
.Include(e => e.EpisodeMetadata)
@ -571,7 +579,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -571,7 +579,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<Episode>> GetShowItemsFromShowId(TvContext dbContext, int showId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT Episode.Id FROM Show
INNER JOIN Season ON Season.ShowId = Show.Id
INNER JOIN Episode ON Episode.SeasonId = Season.Id
@ -583,7 +591,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -583,7 +591,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<Episode>> GetSeasonItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT Episode.Id FROM CollectionItem ci
INNER JOIN Season ON Season.Id = ci.MediaItemId
INNER JOIN Episode ON Episode.SeasonId = Season.Id
@ -592,7 +600,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -592,7 +600,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
return await GetSeasonItemsFromEpisodeIds(dbContext, ids);
}
private static Task<List<Episode>> GetSeasonItemsFromEpisodeIds(TvContext dbContext, IEnumerable<int> episodeIds) =>
dbContext.Episodes
.Include(e => e.EpisodeMetadata)
@ -605,10 +613,10 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -605,10 +613,10 @@ public class MediaCollectionRepository : IMediaCollectionRepository
.ThenInclude(s => s.ShowMetadata)
.Filter(e => episodeIds.Contains(e.Id))
.ToListAsync();
private async Task<List<Episode>> GetSeasonItemsFromSeasonId(TvContext dbContext, int seasonId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT Episode.Id FROM Season
INNER JOIN Episode ON Episode.SeasonId = Season.Id
WHERE Season.Id = @SeasonId",
@ -619,7 +627,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -619,7 +627,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
private async Task<List<Episode>> GetEpisodeItems(TvContext dbContext, int collectionId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT Episode.Id FROM CollectionItem ci
INNER JOIN Episode ON Episode.Id = ci.MediaItemId
WHERE ci.CollectionId = @CollectionId",
@ -627,7 +635,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -627,7 +635,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
return await GetEpisodeItems(dbContext, ids);
}
private static Task<List<Episode>> GetEpisodeItems(TvContext dbContext, IEnumerable<int> episodeIds) =>
dbContext.Episodes
.Include(e => e.EpisodeMetadata)

32
ErsatzTV.Infrastructure/Data/Repositories/MediaItemRepository.cs

@ -1,19 +1,24 @@ @@ -1,19 +1,24 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MediaItemRepository : IMediaItemRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MediaItemRepository(IDbConnection dbConnection) => _dbConnection = dbConnection;
public MediaItemRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public Task<List<string>> GetAllLanguageCodes() =>
_dbConnection.QueryAsync<string>(
public async Task<List<string>> GetAllLanguageCodes()
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT LanguageCode FROM
(SELECT Language AS LanguageCode
FROM MediaStream WHERE Language IS NOT NULL
@ -22,10 +27,13 @@ public class MediaItemRepository : IMediaItemRepository @@ -22,10 +27,13 @@ public class MediaItemRepository : IMediaItemRepository
GROUP BY LanguageCode
ORDER BY COUNT(LanguageCode) DESC")
.Map(result => result.ToList());
}
public async Task<List<int>> FlagFileNotFound(LibraryPath libraryPath, string path)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT M.Id
FROM MediaItem M
INNER JOIN MediaVersion MV on M.Id = COALESCE(MovieId, MusicVideoId, OtherVideoId, SongId, EpisodeId)
@ -34,7 +42,7 @@ public class MediaItemRepository : IMediaItemRepository @@ -34,7 +42,7 @@ public class MediaItemRepository : IMediaItemRepository
new { LibraryPathId = libraryPath.Id, Path = path })
.Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"UPDATE MediaItem SET State = 1 WHERE Id IN @Ids",
new { Ids = ids });
@ -43,18 +51,22 @@ public class MediaItemRepository : IMediaItemRepository @@ -43,18 +51,22 @@ public class MediaItemRepository : IMediaItemRepository
public async Task<Unit> FlagNormal(MediaItem mediaItem)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
mediaItem.State = MediaItemState.Normal;
return await _dbConnection.ExecuteAsync(
return await dbContext.Connection.ExecuteAsync(
@"UPDATE MediaItem SET State = 0 WHERE Id = @Id",
new { mediaItem.Id }).ToUnit();
}
public async Task<Either<BaseError, Unit>> DeleteItems(List<int> mediaItemIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (int mediaItemId in mediaItemIds)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id = @Id",
new { Id = mediaItemId });
}

325
ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using Microsoft.EntityFrameworkCore;
@ -8,64 +7,60 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -8,64 +7,60 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MediaSourceRepository : IMediaSourceRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MediaSourceRepository(
IDbContextFactory<TvContext> dbContextFactory,
IDbConnection dbConnection)
public MediaSourceRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<PlexMediaSource> Add(PlexMediaSource plexMediaSource)
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
await context.PlexMediaSources.AddAsync(plexMediaSource);
await context.SaveChangesAsync();
return plexMediaSource;
}
public Task<List<PlexMediaSource>> GetAllPlex()
public async Task<List<PlexMediaSource>> GetAllPlex()
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.PlexMediaSources
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.PlexMediaSources
.Include(p => p.Connections)
.ToListAsync();
}
public Task<List<PlexLibrary>> GetPlexLibraries(int plexMediaSourceId)
public async Task<List<PlexLibrary>> GetPlexLibraries(int plexMediaSourceId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.PlexLibraries
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.PlexLibraries
.Filter(l => l.MediaSourceId == plexMediaSourceId)
.ToListAsync();
}
public Task<List<PlexPathReplacement>> GetPlexPathReplacements(int plexMediaSourceId)
public async Task<List<PlexPathReplacement>> GetPlexPathReplacements(int plexMediaSourceId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.PlexPathReplacements
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.PlexPathReplacements
.Include(ppr => ppr.PlexMediaSource)
.Filter(r => r.PlexMediaSourceId == plexMediaSourceId)
.ToListAsync();
}
public Task<Option<PlexLibrary>> GetPlexLibrary(int plexLibraryId)
public async Task<Option<PlexLibrary>> GetPlexLibrary(int plexLibraryId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.PlexLibraries
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.PlexLibraries
.Include(l => l.Paths)
.OrderBy(l => l.Id) // https://github.com/dotnet/efcore/issues/22579
.SingleOrDefaultAsync(l => l.Id == plexLibraryId)
.Map(Optional);
}
public Task<Option<PlexMediaSource>> GetPlex(int id)
public async Task<Option<PlexMediaSource>> GetPlex(int id)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.PlexMediaSources
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.PlexMediaSources
.Include(p => p.Connections)
.Include(p => p.Libraries)
.Include(p => p.PathReplacements)
@ -76,14 +71,15 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -76,14 +71,15 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<Option<PlexMediaSource>> GetPlexByLibraryId(int plexLibraryId)
{
int? id = await _dbConnection.QuerySingleOrDefaultAsync<int?>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
int? id = await dbContext.Connection.QuerySingleOrDefaultAsync<int?>(
@"SELECT L.MediaSourceId FROM Library L
INNER JOIN PlexLibrary PL on L.Id = PL.Id
WHERE L.Id = @PlexLibraryId",
new { PlexLibraryId = plexLibraryId });
await using TvContext context = _dbContextFactory.CreateDbContext();
return await context.PlexMediaSources
return await dbContext.PlexMediaSources
.Include(p => p.Connections)
.Include(p => p.Libraries)
.OrderBy(p => p.Id)
@ -91,10 +87,10 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -91,10 +87,10 @@ public class MediaSourceRepository : IMediaSourceRepository
.Map(Optional);
}
public Task<List<PlexPathReplacement>> GetPlexPathReplacementsByLibraryId(int plexLibraryPathId)
public async Task<List<PlexPathReplacement>> GetPlexPathReplacementsByLibraryId(int plexLibraryPathId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.PlexPathReplacements
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.PlexPathReplacements
.FromSqlRaw(
@"select ppr.* from LibraryPath lp
inner join PlexLibrary pl ON pl.Id = lp.LibraryId
@ -111,7 +107,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -111,7 +107,7 @@ public class MediaSourceRepository : IMediaSourceRepository
List<PlexConnection> toAdd,
List<PlexConnection> toDelete)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
dbContext.Entry(plexMediaSource).State = EntityState.Modified;
@ -139,7 +135,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -139,7 +135,7 @@ public class MediaSourceRepository : IMediaSourceRepository
List<PlexLibrary> toAdd,
List<PlexLibrary> toDelete)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (PlexLibrary add in toAdd)
{
@ -168,7 +164,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -168,7 +164,7 @@ public class MediaSourceRepository : IMediaSourceRepository
List<JellyfinLibrary> toAdd,
List<JellyfinLibrary> toDelete)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (JellyfinLibrary add in toAdd)
{
@ -197,7 +193,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -197,7 +193,7 @@ public class MediaSourceRepository : IMediaSourceRepository
List<EmbyLibrary> toAdd,
List<EmbyLibrary> toDelete)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (EmbyLibrary add in toAdd)
{
@ -227,9 +223,11 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -227,9 +223,11 @@ public class MediaSourceRepository : IMediaSourceRepository
List<PlexPathReplacement> toUpdate,
List<PlexPathReplacement> toDelete)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (PlexPathReplacement add in toAdd)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"INSERT INTO PlexPathReplacement
(PlexPath, LocalPath, PlexMediaSourceId)
VALUES (@PlexPath, @LocalPath, @PlexMediaSourceId)",
@ -238,7 +236,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -238,7 +236,7 @@ public class MediaSourceRepository : IMediaSourceRepository
foreach (PlexPathReplacement update in toUpdate)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"UPDATE PlexPathReplacement
SET PlexPath = @PlexPath, LocalPath = @LocalPath
WHERE Id = @Id",
@ -247,7 +245,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -247,7 +245,7 @@ public class MediaSourceRepository : IMediaSourceRepository
foreach (PlexPathReplacement delete in toDelete)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM PlexPathReplacement WHERE Id = @Id",
new { delete.Id });
}
@ -257,26 +255,28 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -257,26 +255,28 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<List<int>> DeleteAllPlex()
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<PlexMediaSource> allMediaSources = await context.PlexMediaSources.ToListAsync();
context.PlexMediaSources.RemoveRange(allMediaSources);
List<PlexMediaSource> allMediaSources = await dbContext.PlexMediaSources.ToListAsync();
dbContext.PlexMediaSources.RemoveRange(allMediaSources);
List<PlexLibrary> allPlexLibraries = await context.PlexLibraries.ToListAsync();
context.PlexLibraries.RemoveRange(allPlexLibraries);
List<PlexLibrary> allPlexLibraries = await dbContext.PlexLibraries.ToListAsync();
dbContext.PlexLibraries.RemoveRange(allPlexLibraries);
List<int> movieIds = await context.PlexMovies.Map(pm => pm.Id).ToListAsync();
List<int> showIds = await context.PlexShows.Map(ps => ps.Id).ToListAsync();
List<int> episodeIds = await context.PlexEpisodes.Map(pe => pe.Id).ToListAsync();
List<int> movieIds = await dbContext.PlexMovies.Map(pm => pm.Id).ToListAsync();
List<int> showIds = await dbContext.PlexShows.Map(ps => ps.Id).ToListAsync();
List<int> episodeIds = await dbContext.PlexEpisodes.Map(pe => pe.Id).ToListAsync();
await context.SaveChangesAsync();
await dbContext.SaveChangesAsync();
return movieIds.Append(showIds).Append(episodeIds).ToList();
}
public async Task<List<int>> DeletePlex(PlexMediaSource plexMediaSource)
{
List<int> mediaItemIds = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> mediaItemIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT MediaItem.Id FROM MediaItem
INNER JOIN LibraryPath LP on MediaItem.LibraryPathId = LP.Id
INNER JOIN Library L on LP.LibraryId = L.Id
@ -284,7 +284,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -284,7 +284,7 @@ public class MediaSourceRepository : IMediaSourceRepository
new { PlexMediaSourceId = plexMediaSource.Id })
.Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaSource WHERE Id = @PlexMediaSourceId",
new { PlexMediaSourceId = plexMediaSource.Id });
@ -293,15 +293,17 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -293,15 +293,17 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<List<int>> DisablePlexLibrarySync(List<int> libraryIds)
{
await _dbConnection.ExecuteAsync(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.Connection.ExecuteAsync(
"UPDATE PlexLibrary SET ShouldSyncItems = 0 WHERE Id IN @ids",
new { ids = libraryIds });
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"UPDATE Library SET LastScan = null WHERE Id IN @ids",
new { ids = libraryIds });
List<int> movieIds = await _dbConnection.QueryAsync<int>(
List<int> movieIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN PlexMovie pm ON pm.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -309,7 +311,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -309,7 +311,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN PlexMovie pm ON pm.Id = m.Id
@ -318,7 +320,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -318,7 +320,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> episodeIds = await _dbConnection.QueryAsync<int>(
List<int> episodeIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN PlexEpisode pe ON pe.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -326,7 +328,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -326,7 +328,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN PlexEpisode pe ON pe.Id = m.Id
@ -335,7 +337,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -335,7 +337,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> seasonIds = await _dbConnection.QueryAsync<int>(
List<int> seasonIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN PlexSeason ps ON ps.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -343,7 +345,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -343,7 +345,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN PlexSeason ps ON ps.Id = m.Id
@ -352,7 +354,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -352,7 +354,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> showIds = await _dbConnection.QueryAsync<int>(
List<int> showIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN PlexShow ps ON ps.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -360,7 +362,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -360,7 +362,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN PlexShow ps ON ps.Id = m.Id
@ -372,14 +374,17 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -372,14 +374,17 @@ public class MediaSourceRepository : IMediaSourceRepository
return movieIds.Append(showIds).Append(seasonIds).Append(episodeIds).ToList();
}
public Task EnablePlexLibrarySync(IEnumerable<int> libraryIds) =>
_dbConnection.ExecuteAsync(
public async Task EnablePlexLibrarySync(IEnumerable<int> libraryIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.Connection.ExecuteAsync(
"UPDATE PlexLibrary SET ShouldSyncItems = 1 WHERE Id IN @ids",
new { ids = libraryIds });
}
public async Task<Unit> UpsertJellyfin(string address, string serverName, string operatingSystem)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<JellyfinMediaSource> maybeExisting = dbContext.JellyfinMediaSources
.Include(ms => ms.Connections)
.OrderBy(ms => ms.Id)
@ -431,18 +436,18 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -431,18 +436,18 @@ public class MediaSourceRepository : IMediaSourceRepository
});
}
public Task<List<JellyfinMediaSource>> GetAllJellyfin()
public async Task<List<JellyfinMediaSource>> GetAllJellyfin()
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.JellyfinMediaSources
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.JellyfinMediaSources
.Include(p => p.Connections)
.ToListAsync();
}
public Task<Option<JellyfinMediaSource>> GetJellyfin(int id)
public async Task<Option<JellyfinMediaSource>> GetJellyfin(int id)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.JellyfinMediaSources
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.JellyfinMediaSources
.Include(p => p.Connections)
.Include(p => p.Libraries)
.Include(p => p.PathReplacements)
@ -451,30 +456,35 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -451,30 +456,35 @@ public class MediaSourceRepository : IMediaSourceRepository
.Map(Optional);
}
public Task<List<JellyfinLibrary>> GetJellyfinLibraries(int jellyfinMediaSourceId)
public async Task<List<JellyfinLibrary>> GetJellyfinLibraries(int jellyfinMediaSourceId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.JellyfinLibraries
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.JellyfinLibraries
.Filter(l => l.MediaSourceId == jellyfinMediaSourceId)
.ToListAsync();
}
public Task<Unit> EnableJellyfinLibrarySync(IEnumerable<int> libraryIds) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> EnableJellyfinLibrarySync(IEnumerable<int> libraryIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE JellyfinLibrary SET ShouldSyncItems = 1 WHERE Id IN @ids",
new { ids = libraryIds }).Map(_ => Unit.Default);
new { ids = libraryIds }).ToUnit();
}
public async Task<List<int>> DisableJellyfinLibrarySync(List<int> libraryIds)
{
await _dbConnection.ExecuteAsync(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.Connection.ExecuteAsync(
"UPDATE JellyfinLibrary SET ShouldSyncItems = 0 WHERE Id IN @ids",
new { ids = libraryIds });
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"UPDATE Library SET LastScan = null WHERE Id IN @ids",
new { ids = libraryIds });
List<int> movieIds = await _dbConnection.QueryAsync<int>(
List<int> movieIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinMovie pm ON pm.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -482,7 +492,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -482,7 +492,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinMovie pm ON pm.Id = m.Id
@ -491,7 +501,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -491,7 +501,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> episodeIds = await _dbConnection.QueryAsync<int>(
List<int> episodeIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinEpisode pe ON pe.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -499,7 +509,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -499,7 +509,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinEpisode pe ON pe.Id = m.Id
@ -508,7 +518,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -508,7 +518,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> seasonIds = await _dbConnection.QueryAsync<int>(
List<int> seasonIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinSeason js ON js.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -516,7 +526,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -516,7 +526,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinSeason ps ON ps.Id = m.Id
@ -525,7 +535,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -525,7 +535,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> showIds = await _dbConnection.QueryAsync<int>(
List<int> showIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinShow ps ON ps.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -533,7 +543,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -533,7 +543,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN JellyfinShow ps ON ps.Id = m.Id
@ -545,10 +555,10 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -545,10 +555,10 @@ public class MediaSourceRepository : IMediaSourceRepository
return movieIds.Append(showIds).Append(seasonIds).Append(episodeIds).ToList();
}
public Task<Option<JellyfinLibrary>> GetJellyfinLibrary(int jellyfinLibraryId)
public async Task<Option<JellyfinLibrary>> GetJellyfinLibrary(int jellyfinLibraryId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.JellyfinLibraries
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.JellyfinLibraries
.Include(l => l.Paths)
.OrderBy(l => l.Id) // https://github.com/dotnet/efcore/issues/22579
.SingleOrDefaultAsync(l => l.Id == jellyfinLibraryId)
@ -557,14 +567,15 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -557,14 +567,15 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<Option<JellyfinMediaSource>> GetJellyfinByLibraryId(int jellyfinLibraryId)
{
int? id = await _dbConnection.QuerySingleOrDefaultAsync<int?>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
int? id = await dbContext.Connection.QuerySingleOrDefaultAsync<int?>(
@"SELECT L.MediaSourceId FROM Library L
INNER JOIN JellyfinLibrary PL on L.Id = PL.Id
WHERE L.Id = @JellyfinLibraryId",
new { JellyfinLibraryId = jellyfinLibraryId });
await using TvContext context = _dbContextFactory.CreateDbContext();
return await context.JellyfinMediaSources
return await dbContext.JellyfinMediaSources
.Include(p => p.Connections)
.Include(p => p.Libraries)
.OrderBy(p => p.Id)
@ -572,19 +583,19 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -572,19 +583,19 @@ public class MediaSourceRepository : IMediaSourceRepository
.Map(Optional);
}
public Task<List<JellyfinPathReplacement>> GetJellyfinPathReplacements(int jellyfinMediaSourceId)
public async Task<List<JellyfinPathReplacement>> GetJellyfinPathReplacements(int jellyfinMediaSourceId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.JellyfinPathReplacements
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.JellyfinPathReplacements
.Filter(r => r.JellyfinMediaSourceId == jellyfinMediaSourceId)
.Include(jpr => jpr.JellyfinMediaSource)
.ToListAsync();
}
public Task<List<JellyfinPathReplacement>> GetJellyfinPathReplacementsByLibraryId(int jellyfinLibraryPathId)
public async Task<List<JellyfinPathReplacement>> GetJellyfinPathReplacementsByLibraryId(int jellyfinLibraryPathId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.JellyfinPathReplacements
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.JellyfinPathReplacements
.FromSqlRaw(
@"select jpr.* from LibraryPath lp
inner join JellyfinLibrary jl ON jl.Id = lp.LibraryId
@ -602,9 +613,11 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -602,9 +613,11 @@ public class MediaSourceRepository : IMediaSourceRepository
List<JellyfinPathReplacement> toUpdate,
List<JellyfinPathReplacement> toDelete)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (JellyfinPathReplacement add in toAdd)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"INSERT INTO JellyfinPathReplacement
(JellyfinPath, LocalPath, JellyfinMediaSourceId)
VALUES (@JellyfinPath, @LocalPath, @JellyfinMediaSourceId)",
@ -613,7 +626,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -613,7 +626,7 @@ public class MediaSourceRepository : IMediaSourceRepository
foreach (JellyfinPathReplacement update in toUpdate)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"UPDATE JellyfinPathReplacement
SET JellyfinPath = @JellyfinPath, LocalPath = @LocalPath
WHERE Id = @Id",
@ -622,7 +635,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -622,7 +635,7 @@ public class MediaSourceRepository : IMediaSourceRepository
foreach (JellyfinPathReplacement delete in toDelete)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM JellyfinPathReplacement WHERE Id = @Id",
new { delete.Id });
}
@ -632,41 +645,41 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -632,41 +645,41 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<List<int>> DeleteAllJellyfin()
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<JellyfinMediaSource> allMediaSources = await context.JellyfinMediaSources.ToListAsync();
List<JellyfinMediaSource> allMediaSources = await dbContext.JellyfinMediaSources.ToListAsync();
var mediaSourceIds = allMediaSources.Map(ms => ms.Id).ToList();
context.JellyfinMediaSources.RemoveRange(allMediaSources);
dbContext.JellyfinMediaSources.RemoveRange(allMediaSources);
List<JellyfinLibrary> allJellyfinLibraries = await context.JellyfinLibraries
List<JellyfinLibrary> allJellyfinLibraries = await dbContext.JellyfinLibraries
.Where(l => mediaSourceIds.Contains(l.MediaSourceId))
.ToListAsync();
var libraryIds = allJellyfinLibraries.Map(l => l.Id).ToList();
context.JellyfinLibraries.RemoveRange(allJellyfinLibraries);
dbContext.JellyfinLibraries.RemoveRange(allJellyfinLibraries);
List<int> movieIds = await context.JellyfinMovies
List<int> movieIds = await dbContext.JellyfinMovies
.Where(m => libraryIds.Contains(m.LibraryPath.LibraryId))
.Map(pm => pm.Id)
.ToListAsync();
List<int> showIds = await context.JellyfinShows
List<int> showIds = await dbContext.JellyfinShows
.Where(m => libraryIds.Contains(m.LibraryPath.LibraryId))
.Map(ps => ps.Id)
.ToListAsync();
List<int> episodeIds = await context.JellyfinEpisodes
List<int> episodeIds = await dbContext.JellyfinEpisodes
.Where(m => libraryIds.Contains(m.LibraryPath.LibraryId))
.Map(ps => ps.Id)
.ToListAsync();
await context.SaveChangesAsync();
await dbContext.SaveChangesAsync();
return movieIds.Append(showIds).Append(episodeIds).ToList();
}
public async Task<Unit> UpsertEmby(string address, string serverName, string operatingSystem)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<EmbyMediaSource> maybeExisting = dbContext.EmbyMediaSources
.Include(ms => ms.Connections)
.OrderBy(ms => ms.Id)
@ -718,18 +731,18 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -718,18 +731,18 @@ public class MediaSourceRepository : IMediaSourceRepository
});
}
public Task<List<EmbyMediaSource>> GetAllEmby()
public async Task<List<EmbyMediaSource>> GetAllEmby()
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.EmbyMediaSources
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.EmbyMediaSources
.Include(p => p.Connections)
.ToListAsync();
}
public Task<Option<EmbyMediaSource>> GetEmby(int id)
public async Task<Option<EmbyMediaSource>> GetEmby(int id)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.EmbyMediaSources
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
return await context.EmbyMediaSources
.Include(p => p.Connections)
.Include(p => p.Libraries)
.Include(p => p.PathReplacements)
@ -740,14 +753,15 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -740,14 +753,15 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<Option<EmbyMediaSource>> GetEmbyByLibraryId(int embyLibraryId)
{
int? id = await _dbConnection.QuerySingleOrDefaultAsync<int?>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
int? id = await dbContext.Connection.QuerySingleOrDefaultAsync<int?>(
@"SELECT L.MediaSourceId FROM Library L
INNER JOIN EmbyLibrary PL on L.Id = PL.Id
WHERE L.Id = @EmbyLibraryId",
new { EmbyLibraryId = embyLibraryId });
await using TvContext context = _dbContextFactory.CreateDbContext();
return await context.EmbyMediaSources
return await dbContext.EmbyMediaSources
.Include(p => p.Connections)
.Include(p => p.Libraries)
.OrderBy(p => p.Id)
@ -755,37 +769,37 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -755,37 +769,37 @@ public class MediaSourceRepository : IMediaSourceRepository
.Map(Optional);
}
public Task<Option<EmbyLibrary>> GetEmbyLibrary(int embyLibraryId)
public async Task<Option<EmbyLibrary>> GetEmbyLibrary(int embyLibraryId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.EmbyLibraries
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.EmbyLibraries
.Include(l => l.Paths)
.OrderBy(l => l.Id) // https://github.com/dotnet/efcore/issues/22579
.SingleOrDefaultAsync(l => l.Id == embyLibraryId)
.Map(Optional);
}
public Task<List<EmbyLibrary>> GetEmbyLibraries(int embyMediaSourceId)
public async Task<List<EmbyLibrary>> GetEmbyLibraries(int embyMediaSourceId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.EmbyLibraries
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.EmbyLibraries
.Filter(l => l.MediaSourceId == embyMediaSourceId)
.ToListAsync();
}
public Task<List<EmbyPathReplacement>> GetEmbyPathReplacements(int embyMediaSourceId)
public async Task<List<EmbyPathReplacement>> GetEmbyPathReplacements(int embyMediaSourceId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.EmbyPathReplacements
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.EmbyPathReplacements
.Filter(r => r.EmbyMediaSourceId == embyMediaSourceId)
.Include(jpr => jpr.EmbyMediaSource)
.ToListAsync();
}
public Task<List<EmbyPathReplacement>> GetEmbyPathReplacementsByLibraryId(int embyLibraryPathId)
public async Task<List<EmbyPathReplacement>> GetEmbyPathReplacementsByLibraryId(int embyLibraryPathId)
{
using TvContext context = _dbContextFactory.CreateDbContext();
return context.EmbyPathReplacements
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.EmbyPathReplacements
.FromSqlRaw(
@"select epr.* from LibraryPath lp
inner join EmbyLibrary el ON el.Id = lp.LibraryId
@ -803,9 +817,11 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -803,9 +817,11 @@ public class MediaSourceRepository : IMediaSourceRepository
List<EmbyPathReplacement> toUpdate,
List<EmbyPathReplacement> toDelete)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (EmbyPathReplacement add in toAdd)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"INSERT INTO EmbyPathReplacement
(EmbyPath, LocalPath, EmbyMediaSourceId)
VALUES (@EmbyPath, @LocalPath, @EmbyMediaSourceId)",
@ -814,7 +830,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -814,7 +830,7 @@ public class MediaSourceRepository : IMediaSourceRepository
foreach (EmbyPathReplacement update in toUpdate)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"UPDATE EmbyPathReplacement
SET EmbyPath = @EmbyPath, LocalPath = @LocalPath
WHERE Id = @Id",
@ -823,7 +839,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -823,7 +839,7 @@ public class MediaSourceRepository : IMediaSourceRepository
foreach (EmbyPathReplacement delete in toDelete)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM EmbyPathReplacement WHERE Id = @Id",
new { delete.Id });
}
@ -833,54 +849,59 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -833,54 +849,59 @@ public class MediaSourceRepository : IMediaSourceRepository
public async Task<List<int>> DeleteAllEmby()
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<EmbyMediaSource> allMediaSources = await context.EmbyMediaSources.ToListAsync();
List<EmbyMediaSource> allMediaSources = await dbContext.EmbyMediaSources.ToListAsync();
var mediaSourceIds = allMediaSources.Map(ms => ms.Id).ToList();
context.EmbyMediaSources.RemoveRange(allMediaSources);
dbContext.EmbyMediaSources.RemoveRange(allMediaSources);
List<EmbyLibrary> allEmbyLibraries = await context.EmbyLibraries
List<EmbyLibrary> allEmbyLibraries = await dbContext.EmbyLibraries
.Where(l => mediaSourceIds.Contains(l.MediaSourceId))
.ToListAsync();
var libraryIds = allEmbyLibraries.Map(l => l.Id).ToList();
context.EmbyLibraries.RemoveRange(allEmbyLibraries);
dbContext.EmbyLibraries.RemoveRange(allEmbyLibraries);
List<int> movieIds = await context.EmbyMovies
List<int> movieIds = await dbContext.EmbyMovies
.Where(m => libraryIds.Contains(m.LibraryPath.LibraryId))
.Map(pm => pm.Id)
.ToListAsync();
List<int> showIds = await context.EmbyShows
List<int> showIds = await dbContext.EmbyShows
.Where(m => libraryIds.Contains(m.LibraryPath.LibraryId))
.Map(ps => ps.Id)
.ToListAsync();
List<int> episodeIds = await context.EmbyEpisodes
List<int> episodeIds = await dbContext.EmbyEpisodes
.Where(m => libraryIds.Contains(m.LibraryPath.LibraryId))
.Map(ps => ps.Id)
.ToListAsync();
await context.SaveChangesAsync();
await dbContext.SaveChangesAsync();
return movieIds.Append(showIds).Append(episodeIds).ToList();
}
public Task<Unit> EnableEmbyLibrarySync(IEnumerable<int> libraryIds) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> EnableEmbyLibrarySync(IEnumerable<int> libraryIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE EmbyLibrary SET ShouldSyncItems = 1 WHERE Id IN @ids",
new { ids = libraryIds }).Map(_ => Unit.Default);
}
public async Task<List<int>> DisableEmbyLibrarySync(List<int> libraryIds)
{
await _dbConnection.ExecuteAsync(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.Connection.ExecuteAsync(
"UPDATE EmbyLibrary SET ShouldSyncItems = 0 WHERE Id IN @ids",
new { ids = libraryIds });
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"UPDATE Library SET LastScan = null WHERE Id IN @ids",
new { ids = libraryIds });
List<int> movieIds = await _dbConnection.QueryAsync<int>(
List<int> movieIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN EmbyMovie pm ON pm.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -888,7 +909,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -888,7 +909,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN EmbyMovie pm ON pm.Id = m.Id
@ -897,7 +918,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -897,7 +918,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> episodeIds = await _dbConnection.QueryAsync<int>(
List<int> episodeIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN EmbyEpisode pe ON pe.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -905,7 +926,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -905,7 +926,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN EmbyEpisode pe ON pe.Id = m.Id
@ -914,7 +935,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -914,7 +935,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> seasonIds = await _dbConnection.QueryAsync<int>(
List<int> seasonIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN EmbySeason es ON es.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -922,7 +943,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -922,7 +943,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN EmbySeason ps ON ps.Id = m.Id
@ -931,7 +952,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -931,7 +952,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids)",
new { ids = libraryIds });
List<int> showIds = await _dbConnection.QueryAsync<int>(
List<int> showIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN EmbyShow ps ON ps.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
@ -939,7 +960,7 @@ public class MediaSourceRepository : IMediaSourceRepository @@ -939,7 +960,7 @@ public class MediaSourceRepository : IMediaSourceRepository
WHERE l.Id IN @ids",
new { ids = libraryIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN EmbyShow ps ON ps.Id = m.Id

214
ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Repositories;
@ -9,18 +8,21 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -9,18 +8,21 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MetadataRepository : IMetadataRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MetadataRepository(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public MetadataRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public Task<bool> RemoveActor(Actor actor) =>
_dbConnection.ExecuteAsync("DELETE FROM Actor WHERE Id = @ActorId", new { ActorId = actor.Id })
public async Task<bool> RemoveActor(Actor actor)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM Actor WHERE Id = @ActorId",
new { ActorId = actor.Id })
.Map(result => result > 0);
}
public async Task<bool> Update(Metadata metadata)
{
@ -31,7 +33,7 @@ public class MetadataRepository : IMetadataRepository @@ -31,7 +33,7 @@ public class MetadataRepository : IMetadataRepository
public async Task<bool> Add(Metadata metadata)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
dbContext.Entry(metadata).State = EntityState.Added;
foreach (Genre genre in Optional(metadata.Genres).Flatten())
@ -111,7 +113,7 @@ public class MetadataRepository : IMetadataRepository @@ -111,7 +113,7 @@ public class MetadataRepository : IMetadataRepository
bool updateVersion = true)
{
int mediaVersionId = mediaItem.GetHeadVersion().Id;
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<MediaVersion> maybeVersion = await dbContext.MediaVersions
.Include(v => v.Streams)
@ -164,7 +166,7 @@ public class MetadataRepository : IMetadataRepository @@ -164,7 +166,7 @@ public class MetadataRepository : IMetadataRepository
existingStream.PixelFormat = incomingStream.PixelFormat;
existingStream.BitsPerRawSample = incomingStream.BitsPerRawSample;
}
var chaptersToAdd = incoming.Chapters
.Filter(s => existing.Chapters.All(es => es.ChapterId != s.ChapterId))
.ToList();
@ -225,8 +227,10 @@ public class MetadataRepository : IMetadataRepository @@ -225,8 +227,10 @@ public class MetadataRepository : IMetadataRepository
() => Task.FromResult(false));
}
public Task<bool> UpdatePlexStatistics(int mediaVersionId, MediaVersion incoming) =>
_dbConnection.ExecuteAsync(
public async Task<bool> UpdatePlexStatistics(int mediaVersionId, MediaVersion incoming)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE MediaVersion SET
DateUpdated = @DateUpdated
WHERE Id = @MediaVersionId",
@ -235,14 +239,24 @@ public class MetadataRepository : IMetadataRepository @@ -235,14 +239,24 @@ public class MetadataRepository : IMetadataRepository
incoming.DateUpdated,
MediaVersionId = mediaVersionId
}).Map(result => result > 0);
}
public Task<Unit> UpdateArtworkPath(Artwork artwork) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> UpdateArtworkPath(Artwork artwork)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE Artwork SET Path = @Path, SourcePath = @SourcePath, DateUpdated = @DateUpdated, BlurHash43 = @BlurHash43, BlurHash54 = @BlurHash54, BlurHash64 = @BlurHash64 WHERE Id = @Id",
new { artwork.Path, artwork.SourcePath, artwork.DateUpdated, artwork.BlurHash43, artwork.BlurHash54, artwork.BlurHash64, artwork.Id }).ToUnit();
new
{
artwork.Path, artwork.SourcePath, artwork.DateUpdated, artwork.BlurHash43, artwork.BlurHash54,
artwork.BlurHash64, artwork.Id
}).ToUnit();
}
public Task<Unit> AddArtwork(Metadata metadata, Artwork artwork)
public async Task<Unit> AddArtwork(Metadata metadata, Artwork artwork)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
var parameters = new
{
artwork.ArtworkKind, metadata.Id, artwork.DateAdded, artwork.DateUpdated, artwork.Path,
@ -251,50 +265,53 @@ public class MetadataRepository : IMetadataRepository @@ -251,50 +265,53 @@ public class MetadataRepository : IMetadataRepository
return metadata switch
{
MovieMetadata => _dbConnection.ExecuteAsync(
MovieMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, MovieMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
VALUES (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
ShowMetadata => _dbConnection.ExecuteAsync(
ShowMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, ShowMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
VALUES (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
SeasonMetadata => _dbConnection.ExecuteAsync(
SeasonMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, SeasonMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
VALUES (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
EpisodeMetadata => _dbConnection.ExecuteAsync(
EpisodeMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, EpisodeMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
VALUES (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
ArtistMetadata => _dbConnection.ExecuteAsync(
ArtistMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, ArtistMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
Values (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
MusicVideoMetadata => _dbConnection.ExecuteAsync(
MusicVideoMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, MusicVideoMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
VALUES (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
SongMetadata => _dbConnection.ExecuteAsync(
SongMetadata => await dbContext.Connection.ExecuteAsync(
@"INSERT INTO Artwork (ArtworkKind, SongMetadataId, DateAdded, DateUpdated, Path, SourcePath, BlurHash43, BlurHash54, BlurHash64)
VALUES (@ArtworkKind, @Id, @DateAdded, @DateUpdated, @Path, @SourcePath, @BlurHash43, @BlurHash54, @BlurHash64)",
parameters)
.ToUnit(),
_ => Task.FromResult(Unit.Default)
_ => Unit.Default
};
}
public Task<Unit> RemoveArtwork(Metadata metadata, ArtworkKind artworkKind) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> RemoveArtwork(Metadata metadata, ArtworkKind artworkKind)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"DELETE FROM Artwork WHERE ArtworkKind = @ArtworkKind AND (MovieMetadataId = @Id
OR ShowMetadataId = @Id OR SeasonMetadataId = @Id OR EpisodeMetadataId = @Id)",
new { ArtworkKind = artworkKind, metadata.Id }).ToUnit();
}
public async Task<bool> CloneArtwork(
Metadata metadata,
@ -342,101 +359,164 @@ public class MetadataRepository : IMetadataRepository @@ -342,101 +359,164 @@ public class MetadataRepository : IMetadataRepository
return false;
}
public Task<Unit> MarkAsUpdated(ShowMetadata metadata, DateTime dateUpdated) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> MarkAsUpdated(ShowMetadata metadata, DateTime dateUpdated)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE ShowMetadata SET DateUpdated = @DateUpdated WHERE Id = @Id",
new { DateUpdated = dateUpdated, metadata.Id }).ToUnit();
}
public Task<Unit> MarkAsUpdated(SeasonMetadata metadata, DateTime dateUpdated) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> MarkAsUpdated(SeasonMetadata metadata, DateTime dateUpdated)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE SeasonMetadata SET DateUpdated = @DateUpdated WHERE Id = @Id",
new { DateUpdated = dateUpdated, metadata.Id }).ToUnit();
}
public Task<Unit> MarkAsUpdated(MovieMetadata metadata, DateTime dateUpdated) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> MarkAsUpdated(MovieMetadata metadata, DateTime dateUpdated)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE MovieMetadata SET DateUpdated = @DateUpdated WHERE Id = @Id",
new { DateUpdated = dateUpdated, metadata.Id }).ToUnit();
}
public Task<Unit> MarkAsUpdated(EpisodeMetadata metadata, DateTime dateUpdated) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> MarkAsUpdated(EpisodeMetadata metadata, DateTime dateUpdated)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE EpisodeMetadata SET DateUpdated = @DateUpdated WHERE Id = @Id",
new { DateUpdated = dateUpdated, metadata.Id }).ToUnit();
}
public Task<Unit> MarkAsExternal(ShowMetadata metadata) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> MarkAsExternal(ShowMetadata metadata)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE ShowMetadata SET MetadataKind = @Kind WHERE Id = @Id",
new { metadata.Id, Kind = (int) MetadataKind.External }).ToUnit();
new { metadata.Id, Kind = (int)MetadataKind.External }).ToUnit();
}
public Task<Unit> SetContentRating(ShowMetadata metadata, string contentRating) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> SetContentRating(ShowMetadata metadata, string contentRating)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE ShowMetadata SET ContentRating = @ContentRating WHERE Id = @Id",
new { metadata.Id, ContentRating = contentRating }).ToUnit();
}
public Task<Unit> MarkAsExternal(MovieMetadata metadata) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> MarkAsExternal(MovieMetadata metadata)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE MovieMetadata SET MetadataKind = @Kind WHERE Id = @Id",
new { metadata.Id, Kind = (int) MetadataKind.External }).ToUnit();
new { metadata.Id, Kind = (int)MetadataKind.External }).ToUnit();
}
public Task<Unit> SetContentRating(MovieMetadata metadata, string contentRating) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> SetContentRating(MovieMetadata metadata, string contentRating)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE MovieMetadata SET ContentRating = @ContentRating WHERE Id = @Id",
new { metadata.Id, ContentRating = contentRating }).ToUnit();
}
public Task<bool> RemoveGuid(MetadataGuid guid) =>
_dbConnection.ExecuteAsync("DELETE FROM MetadataGuid WHERE Id = @GuidId", new { GuidId = guid.Id })
public async Task<bool> RemoveGuid(MetadataGuid guid)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM MetadataGuid WHERE Id = @GuidId",
new { GuidId = guid.Id })
.Map(result => result > 0);
}
public Task<bool> AddGuid(Metadata metadata, MetadataGuid guid) =>
metadata switch
public async Task<bool> AddGuid(Metadata metadata, MetadataGuid guid)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return metadata switch
{
MovieMetadata =>
_dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"INSERT INTO MetadataGuid (Guid, MovieMetadataId) VALUES (@Guid, @MetadataId)",
new { guid.Guid, MetadataId = metadata.Id }).Map(result => result > 0),
ShowMetadata =>
_dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"INSERT INTO MetadataGuid (Guid, ShowMetadataId) VALUES (@Guid, @MetadataId)",
new { guid.Guid, MetadataId = metadata.Id }).Map(result => result > 0),
SeasonMetadata =>
_dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"INSERT INTO MetadataGuid (Guid, SeasonMetadataId) VALUES (@Guid, @MetadataId)",
new { guid.Guid, MetadataId = metadata.Id }).Map(result => result > 0),
EpisodeMetadata =>
_dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"INSERT INTO MetadataGuid (Guid, EpisodeMetadataId) VALUES (@Guid, @MetadataId)",
new { guid.Guid, MetadataId = metadata.Id }).Map(result => result > 0),
ArtistMetadata =>
_dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"INSERT INTO MetadataGuid (Guid, ArtistMetadataId) VALUES (@Guid, @MetadataId)",
new { guid.Guid, MetadataId = metadata.Id }).Map(result => result > 0),
_ => throw new NotSupportedException()
};
}
public Task<bool> RemoveDirector(Director director) =>
_dbConnection.ExecuteAsync("DELETE FROM Director WHERE Id = @DirectorId", new { DirectorId = director.Id })
public async Task<bool> RemoveDirector(Director director)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM Director WHERE Id = @DirectorId",
new { DirectorId = director.Id })
.Map(result => result > 0);
}
public Task<bool> RemoveWriter(Writer writer) =>
_dbConnection.ExecuteAsync("DELETE FROM Writer WHERE Id = @WriterId", new { WriterId = writer.Id })
public async Task<bool> RemoveWriter(Writer writer)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM Writer WHERE Id = @WriterId",
new { WriterId = writer.Id })
.Map(result => result > 0);
}
public Task<bool> RemoveGenre(Genre genre) =>
_dbConnection.ExecuteAsync("DELETE FROM Genre WHERE Id = @GenreId", new { GenreId = genre.Id })
public async Task<bool> RemoveGenre(Genre genre)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM Genre WHERE Id = @GenreId",
new { GenreId = genre.Id })
.Map(result => result > 0);
}
public Task<bool> RemoveTag(Tag tag) =>
_dbConnection.ExecuteAsync("DELETE FROM Tag WHERE Id = @TagId", new { TagId = tag.Id })
public async Task<bool> RemoveTag(Tag tag)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync("DELETE FROM Tag WHERE Id = @TagId", new { TagId = tag.Id })
.Map(result => result > 0);
}
public Task<bool> RemoveStudio(Studio studio) =>
_dbConnection.ExecuteAsync("DELETE FROM Studio WHERE Id = @StudioId", new { StudioId = studio.Id })
public async Task<bool> RemoveStudio(Studio studio)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM Studio WHERE Id = @StudioId",
new { StudioId = studio.Id })
.Map(result => result > 0);
}
public Task<bool> RemoveStyle(Style style) =>
_dbConnection.ExecuteAsync("DELETE FROM Style WHERE Id = @StyleId", new { StyleId = style.Id })
public async Task<bool> RemoveStyle(Style style)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM Style WHERE Id = @StyleId",
new { StyleId = style.Id })
.Map(result => result > 0);
}
public Task<bool> RemoveMood(Mood mood) =>
_dbConnection.ExecuteAsync("DELETE FROM Mood WHERE Id = @MoodId", new { MoodId = mood.Id })
public async Task<bool> RemoveMood(Mood mood)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync("DELETE FROM Mood WHERE Id = @MoodId", new { MoodId = mood.Id })
.Map(result => result > 0);
}
}

126
ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Emby;
@ -13,24 +12,25 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -13,24 +12,25 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MovieRepository : IMovieRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MovieRepository(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public MovieRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public Task<bool> AllMoviesExist(List<int> movieIds) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<bool> AllMoviesExist(List<int> movieIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<int>(
"SELECT COUNT(*) FROM Movie WHERE Id in @MovieIds",
new { MovieIds = movieIds })
.Map(c => c == movieIds.Count);
}
public async Task<Option<Movie>> GetMovie(int movieId)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Movies
.Include(m => m.MovieMetadata)
.ThenInclude(m => m.Artwork)
@ -101,7 +101,7 @@ public class MovieRepository : IMovieRepository @@ -101,7 +101,7 @@ public class MovieRepository : IMovieRepository
PlexLibrary library,
PlexMovie item)
{
await using TvContext context = _dbContextFactory.CreateDbContext();
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
Option<PlexMovie> maybeExisting = await context.PlexMovies
.AsNoTracking()
.Include(i => i.MovieMetadata)
@ -153,8 +153,10 @@ public class MovieRepository : IMovieRepository @@ -153,8 +153,10 @@ public class MovieRepository : IMovieRepository
.ToListAsync();
}
public Task<IEnumerable<string>> FindMoviePaths(LibraryPath libraryPath) =>
_dbConnection.QueryAsync<string>(
public async Task<IEnumerable<string>> FindMoviePaths(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT MF.Path
FROM MediaFile MF
INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id
@ -162,11 +164,12 @@ public class MovieRepository : IMovieRepository @@ -162,11 +164,12 @@ public class MovieRepository : IMovieRepository
INNER JOIN MediaItem MI on M.Id = MI.Id
WHERE MI.LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPath.Id });
}
public async Task<List<int>> DeleteByPath(LibraryPath libraryPath, string path)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await _dbConnection.QueryAsync<int>(
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT M.Id
FROM Movie M
INNER JOIN MediaItem MI on M.Id = MI.Id
@ -188,42 +191,53 @@ public class MovieRepository : IMovieRepository @@ -188,42 +191,53 @@ public class MovieRepository : IMovieRepository
bool changed = await dbContext.SaveChangesAsync() > 0;
return changed ? ids : new List<int>();
}
public Task<bool> AddGenre(MovieMetadata metadata, Genre genre) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddGenre(MovieMetadata metadata, Genre genre)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Genre (Name, MovieMetadataId) VALUES (@Name, @MetadataId)",
new { genre.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddTag(MovieMetadata metadata, Tag tag) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddTag(MovieMetadata metadata, Tag tag)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Tag (Name, MovieMetadataId) VALUES (@Name, @MetadataId)",
new { tag.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddStudio(MovieMetadata metadata, Studio studio) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddStudio(MovieMetadata metadata, Studio studio)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Studio (Name, MovieMetadataId) VALUES (@Name, @MetadataId)",
new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<bool> AddActor(MovieMetadata metadata, Actor actor)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
int? artworkId = null;
if (actor.Artwork != null)
{
artworkId = await _dbConnection.QuerySingleAsync<int>(
artworkId = await dbContext.Connection.QuerySingleAsync<int>(
@"INSERT INTO Artwork (ArtworkKind, DateAdded, DateUpdated, Path)
VALUES (@ArtworkKind, @DateAdded, @DateUpdated, @Path);
SELECT last_insert_rowid()",
new
{
ArtworkKind = (int) actor.Artwork.ArtworkKind,
ArtworkKind = (int)actor.Artwork.ArtworkKind,
actor.Artwork.DateAdded,
actor.Artwork.DateUpdated,
actor.Artwork.Path
});
}
return await _dbConnection.ExecuteAsync(
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Actor (Name, Role, \"Order\", MovieMetadataId, ArtworkId) VALUES (@Name, @Role, @Order, @MetadataId, @ArtworkId)",
new { actor.Name, actor.Role, actor.Order, MetadataId = metadata.Id, ArtworkId = artworkId })
.Map(result => result > 0);
@ -231,27 +245,34 @@ public class MovieRepository : IMovieRepository @@ -231,27 +245,34 @@ public class MovieRepository : IMovieRepository
public async Task<List<int>> RemoveMissingPlexMovies(PlexLibrary library, List<string> movieKeys)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN PlexMovie pm ON pm.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
WHERE lp.LibraryId = @LibraryId AND pm.Key not in @Keys",
new { LibraryId = library.Id, Keys = movieKeys }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
return ids;
}
public Task<bool> UpdateSortTitle(MovieMetadata movieMetadata) =>
_dbConnection.ExecuteAsync(
public async Task<bool> UpdateSortTitle(MovieMetadata movieMetadata)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"UPDATE MovieMetadata SET SortTitle = @SortTitle WHERE Id = @Id",
new { movieMetadata.SortTitle, movieMetadata.Id }).Map(result => result > 0);
}
public Task<List<JellyfinItemEtag>> GetExistingJellyfinMovies(JellyfinLibrary library) =>
_dbConnection.QueryAsync<JellyfinItemEtag>(
public async Task<List<JellyfinItemEtag>> GetExistingJellyfinMovies(JellyfinLibrary library)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<JellyfinItemEtag>(
@"SELECT ItemId, Etag FROM JellyfinMovie
INNER JOIN Movie M on JellyfinMovie.Id = M.Id
INNER JOIN MediaItem MI on M.Id = MI.Id
@ -259,10 +280,13 @@ public class MovieRepository : IMovieRepository @@ -259,10 +280,13 @@ public class MovieRepository : IMovieRepository
WHERE LP.LibraryId = @LibraryId",
new { LibraryId = library.Id })
.Map(result => result.ToList());
}
public async Task<List<int>> RemoveMissingJellyfinMovies(JellyfinLibrary library, List<string> movieIds)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT JellyfinMovie.Id FROM JellyfinMovie
INNER JOIN Movie M on JellyfinMovie.Id = M.Id
INNER JOIN MediaItem MI on M.Id = MI.Id
@ -270,7 +294,7 @@ public class MovieRepository : IMovieRepository @@ -270,7 +294,7 @@ public class MovieRepository : IMovieRepository
WHERE LP.LibraryId = @LibraryId AND ItemId IN @ItemIds",
new { LibraryId = library.Id, ItemIds = movieIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
@ -279,7 +303,7 @@ public class MovieRepository : IMovieRepository @@ -279,7 +303,7 @@ public class MovieRepository : IMovieRepository
public async Task<bool> AddJellyfin(JellyfinMovie movie)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.AddAsync(movie);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -293,7 +317,7 @@ public class MovieRepository : IMovieRepository @@ -293,7 +317,7 @@ public class MovieRepository : IMovieRepository
public async Task<Option<JellyfinMovie>> UpdateJellyfin(JellyfinMovie movie)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<JellyfinMovie> maybeExisting = await dbContext.JellyfinMovies
.Include(m => m.LibraryPath)
.ThenInclude(lp => lp.Library)
@ -506,8 +530,10 @@ public class MovieRepository : IMovieRepository @@ -506,8 +530,10 @@ public class MovieRepository : IMovieRepository
return maybeExisting;
}
public Task<List<EmbyItemEtag>> GetExistingEmbyMovies(EmbyLibrary library) =>
_dbConnection.QueryAsync<EmbyItemEtag>(
public async Task<List<EmbyItemEtag>> GetExistingEmbyMovies(EmbyLibrary library)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<EmbyItemEtag>(
@"SELECT ItemId, Etag FROM EmbyMovie
INNER JOIN Movie M on EmbyMovie.Id = M.Id
INNER JOIN MediaItem MI on M.Id = MI.Id
@ -515,10 +541,13 @@ public class MovieRepository : IMovieRepository @@ -515,10 +541,13 @@ public class MovieRepository : IMovieRepository
WHERE LP.LibraryId = @LibraryId",
new { LibraryId = library.Id })
.Map(result => result.ToList());
}
public async Task<List<int>> RemoveMissingEmbyMovies(EmbyLibrary library, List<string> movieIds)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT EmbyMovie.Id FROM EmbyMovie
INNER JOIN Movie M on EmbyMovie.Id = M.Id
INNER JOIN MediaItem MI on M.Id = MI.Id
@ -526,7 +555,7 @@ public class MovieRepository : IMovieRepository @@ -526,7 +555,7 @@ public class MovieRepository : IMovieRepository
WHERE LP.LibraryId = @LibraryId AND ItemId IN @ItemIds",
new { LibraryId = library.Id, ItemIds = movieIds }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
@ -535,7 +564,7 @@ public class MovieRepository : IMovieRepository @@ -535,7 +564,7 @@ public class MovieRepository : IMovieRepository
public async Task<bool> AddEmby(EmbyMovie movie)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
await dbContext.AddAsync(movie);
if (await dbContext.SaveChangesAsync() <= 0)
{
@ -549,7 +578,7 @@ public class MovieRepository : IMovieRepository @@ -549,7 +578,7 @@ public class MovieRepository : IMovieRepository
public async Task<Option<EmbyMovie>> UpdateEmby(EmbyMovie movie)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<EmbyMovie> maybeExisting = await dbContext.EmbyMovies
.Include(m => m.LibraryPath)
.ThenInclude(lp => lp.Library)
@ -762,20 +791,29 @@ public class MovieRepository : IMovieRepository @@ -762,20 +791,29 @@ public class MovieRepository : IMovieRepository
return maybeExisting;
}
public Task<bool> AddDirector(MovieMetadata metadata, Director director) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddDirector(MovieMetadata metadata, Director director)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Director (Name, MovieMetadataId) VALUES (@Name, @MetadataId)",
new { director.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddWriter(MovieMetadata metadata, Writer writer) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddWriter(MovieMetadata metadata, Writer writer)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Writer (Name, MovieMetadataId) VALUES (@Name, @MetadataId)",
new { writer.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<Unit> UpdatePath(int mediaFileId, string path) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> UpdatePath(int mediaFileId, string path)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE MediaFile SET Path = @Path WHERE Id = @MediaFileId",
new { Path = path, MediaFileId = mediaFileId }).Map(_ => Unit.Default);
}
private static async Task<Either<BaseError, MediaItemScanResult<Movie>>> AddMovie(
TvContext dbContext,

55
ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -10,13 +9,11 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,13 +9,11 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class MusicVideoRepository : IMusicVideoRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public MusicVideoRepository(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public MusicVideoRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<Either<BaseError, MediaItemScanResult<MusicVideo>>> GetOrAdd(
@ -53,7 +50,7 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -53,7 +50,7 @@ public class MusicVideoRepository : IMusicVideoRepository
{
if (mediaItem.ArtistId != artist.Id)
{
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"UPDATE MusicVideo SET ArtistId = @ArtistId WHERE Id = @Id",
new { mediaItem.Id, ArtistId = artist.Id });
@ -67,8 +64,10 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -67,8 +64,10 @@ public class MusicVideoRepository : IMusicVideoRepository
async () => await AddMusicVideo(dbContext, artist, libraryPath.Id, path));
}
public Task<IEnumerable<string>> FindMusicVideoPaths(LibraryPath libraryPath) =>
_dbConnection.QueryAsync<string>(
public async Task<IEnumerable<string>> FindMusicVideoPaths(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT MF.Path
FROM MediaFile MF
INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id
@ -76,10 +75,12 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -76,10 +75,12 @@ public class MusicVideoRepository : IMusicVideoRepository
INNER JOIN MediaItem MI on M.Id = MI.Id
WHERE MI.LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPath.Id });
}
public async Task<List<int>> DeleteByPath(LibraryPath libraryPath, string path)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT M.Id
FROM MusicVideo M
INNER JOIN MediaItem MI on M.Id = MI.Id
@ -88,7 +89,6 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -88,7 +89,6 @@ public class MusicVideoRepository : IMusicVideoRepository
WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path",
new { LibraryPathId = libraryPath.Id, Path = path }).Map(result => result.ToList());
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (int musicVideoId in ids)
{
MusicVideo musicVideo = await dbContext.MusicVideos.FindAsync(musicVideoId);
@ -103,20 +103,29 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -103,20 +103,29 @@ public class MusicVideoRepository : IMusicVideoRepository
return ids;
}
public Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Genre (Name, MusicVideoMetadataId) VALUES (@Name, @MetadataId)",
new { genre.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddTag(MusicVideoMetadata metadata, Tag tag) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddTag(MusicVideoMetadata metadata, Tag tag)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Tag (Name, MusicVideoMetadataId) VALUES (@Name, @MetadataId)",
new { tag.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddStudio(MusicVideoMetadata metadata, Studio studio) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddStudio(MusicVideoMetadata metadata, Studio studio)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Studio (Name, MusicVideoMetadataId) VALUES (@Name, @MetadataId)",
new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids)
{
@ -135,8 +144,10 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -135,8 +144,10 @@ public class MusicVideoRepository : IMusicVideoRepository
.ToListAsync();
}
public Task<IEnumerable<string>> FindOrphanPaths(LibraryPath libraryPath) =>
_dbConnection.QueryAsync<string>(
public async Task<IEnumerable<string>> FindOrphanPaths(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT MF.Path
FROM MediaFile MF
INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id
@ -145,11 +156,15 @@ public class MusicVideoRepository : IMusicVideoRepository @@ -145,11 +156,15 @@ public class MusicVideoRepository : IMusicVideoRepository
WHERE MI.LibraryPathId = @LibraryPathId
AND NOT EXISTS (SELECT * FROM MusicVideoMetadata WHERE MusicVideoId = M.Id)",
new { LibraryPathId = libraryPath.Id });
}
public Task<int> GetMusicVideoCount(int artistId) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<int> GetMusicVideoCount(int artistId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<int>(
@"SELECT COUNT(*) FROM MusicVideo WHERE ArtistId = @ArtistId",
new { ArtistId = artistId });
}
public async Task<List<MusicVideoMetadata>> GetPagedMusicVideos(int artistId, int pageNumber, int pageSize)
{

35
ErsatzTV.Infrastructure/Data/Repositories/OtherVideoRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -10,12 +9,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,12 +9,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class OtherVideoRepository : IOtherVideoRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public OtherVideoRepository(IDbConnection dbConnection, IDbContextFactory<TvContext> dbContextFactory)
public OtherVideoRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbConnection = dbConnection;
_dbContextFactory = dbContextFactory;
}
@ -23,7 +20,7 @@ public class OtherVideoRepository : IOtherVideoRepository @@ -23,7 +20,7 @@ public class OtherVideoRepository : IOtherVideoRepository
LibraryPath libraryPath,
string path)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
Option<OtherVideo> maybeExisting = await dbContext.OtherVideos
.AsNoTracking()
.Include(ov => ov.OtherVideoMetadata)
@ -48,8 +45,10 @@ public class OtherVideoRepository : IOtherVideoRepository @@ -48,8 +45,10 @@ public class OtherVideoRepository : IOtherVideoRepository
async () => await AddOtherVideo(dbContext, libraryPath.Id, path));
}
public Task<IEnumerable<string>> FindOtherVideoPaths(LibraryPath libraryPath) =>
_dbConnection.QueryAsync<string>(
public async Task<IEnumerable<string>> FindOtherVideoPaths(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT MF.Path
FROM MediaFile MF
INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id
@ -57,10 +56,13 @@ public class OtherVideoRepository : IOtherVideoRepository @@ -57,10 +56,13 @@ public class OtherVideoRepository : IOtherVideoRepository
INNER JOIN MediaItem MI on O.Id = MI.Id
WHERE MI.LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPath.Id });
}
public async Task<List<int>> DeleteByPath(LibraryPath libraryPath, string path)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT O.Id
FROM OtherVideo O
INNER JOIN MediaItem MI on O.Id = MI.Id
@ -69,11 +71,13 @@ public class OtherVideoRepository : IOtherVideoRepository @@ -69,11 +71,13 @@ public class OtherVideoRepository : IOtherVideoRepository
WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path",
new { LibraryPathId = libraryPath.Id, Path = path }).Map(result => result.ToList());
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
foreach (int otherVideoId in ids)
{
OtherVideo otherVideo = await dbContext.OtherVideos.FindAsync(otherVideoId);
dbContext.OtherVideos.Remove(otherVideo);
if (otherVideo != null)
{
dbContext.OtherVideos.Remove(otherVideo);
}
}
await dbContext.SaveChangesAsync();
@ -81,14 +85,17 @@ public class OtherVideoRepository : IOtherVideoRepository @@ -81,14 +85,17 @@ public class OtherVideoRepository : IOtherVideoRepository
return ids;
}
public Task<bool> AddTag(OtherVideoMetadata metadata, Tag tag) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddTag(OtherVideoMetadata metadata, Tag tag)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Tag (Name, OtherVideoMetadataId) VALUES (@Name, @MetadataId)",
new { tag.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<List<OtherVideoMetadata>> GetOtherVideosForCards(List<int> ids)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.OtherVideoMetadata
.AsNoTracking()
.Filter(ovm => ids.Contains(ovm.OtherVideoId))

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

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Extensions;
@ -9,18 +8,19 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -9,18 +8,19 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class SearchRepository : ISearchRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SearchRepository(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
public SearchRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public Task<List<int>> GetItemIdsToIndex() =>
_dbConnection.QueryAsync<int>(@"SELECT Id FROM MediaItem")
public async Task<List<int>> GetItemIdsToIndex()
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<int>(@"SELECT Id FROM MediaItem")
.Map(result => result.ToList());
}
public async Task<Option<MediaItem>> GetItemToIndex(int id)
{
@ -111,8 +111,10 @@ public class SearchRepository : ISearchRepository @@ -111,8 +111,10 @@ public class SearchRepository : ISearchRepository
.Map(Optional);
}
public Task<List<string>> GetLanguagesForShow(Show show) =>
_dbConnection.QueryAsync<string>(
public async Task<List<string>> GetLanguagesForShow(Show show)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT DISTINCT Language
FROM MediaStream
INNER JOIN MediaVersion MV ON MediaStream.MediaVersionId = MV.Id
@ -120,18 +122,24 @@ public class SearchRepository : ISearchRepository @@ -120,18 +122,24 @@ public class SearchRepository : ISearchRepository
INNER JOIN Season S ON E.SeasonId = S.Id
WHERE MediaStreamKind = 2 AND S.ShowId = @ShowId",
new { ShowId = show.Id }).Map(result => result.ToList());
}
public Task<List<string>> GetLanguagesForSeason(Season season) =>
_dbConnection.QueryAsync<string>(
public async Task<List<string>> GetLanguagesForSeason(Season season)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT DISTINCT Language
FROM MediaStream
INNER JOIN MediaVersion MV ON MediaStream.MediaVersionId = MV.Id
INNER JOIN Episode E ON MV.EpisodeId = E.Id
WHERE MediaStreamKind = 2 AND E.SeasonId = @SeasonId",
new { SeasonId = season.Id }).Map(result => result.ToList());
}
public Task<List<string>> GetLanguagesForArtist(Artist artist) =>
_dbConnection.QueryAsync<string>(
public async Task<List<string>> GetLanguagesForArtist(Artist artist)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT DISTINCT Language
FROM MediaStream
INNER JOIN MediaVersion V ON MediaStream.MediaVersionId = V.Id
@ -139,7 +147,8 @@ public class SearchRepository : ISearchRepository @@ -139,7 +147,8 @@ public class SearchRepository : ISearchRepository
INNER JOIN Artist A on MV.ArtistId = A.Id
WHERE MediaStreamKind = 2 AND A.Id = @ArtistId",
new { ArtistId = artist.Id }).Map(result => result.ToList());
}
public async Task<List<string>> GetAllLanguageCodes(List<string> mediaCodes)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();

33
ErsatzTV.Infrastructure/Data/Repositories/SongRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -10,12 +9,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,12 +9,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class SongRepository : ISongRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public SongRepository(IDbConnection dbConnection, IDbContextFactory<TvContext> dbContextFactory)
public SongRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbConnection = dbConnection;
_dbContextFactory = dbContextFactory;
}
@ -53,8 +50,10 @@ public class SongRepository : ISongRepository @@ -53,8 +50,10 @@ public class SongRepository : ISongRepository
async () => await AddSong(dbContext, libraryPath.Id, path));
}
public Task<IEnumerable<string>> FindSongPaths(LibraryPath libraryPath) =>
_dbConnection.QueryAsync<string>(
public async Task<IEnumerable<string>> FindSongPaths(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT MF.Path
FROM MediaFile MF
INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id
@ -62,10 +61,13 @@ public class SongRepository : ISongRepository @@ -62,10 +61,13 @@ public class SongRepository : ISongRepository
INNER JOIN MediaItem MI on O.Id = MI.Id
WHERE MI.LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPath.Id });
}
public async Task<List<int>> DeleteByPath(LibraryPath libraryPath, string path)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT O.Id
FROM Song O
INNER JOIN MediaItem MI on O.Id = MI.Id
@ -74,7 +76,6 @@ public class SongRepository : ISongRepository @@ -74,7 +76,6 @@ public class SongRepository : ISongRepository
WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path",
new { LibraryPathId = libraryPath.Id, Path = path }).Map(result => result.ToList());
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (int songId in ids)
{
Song song = await dbContext.Songs.FindAsync(songId);
@ -89,15 +90,21 @@ public class SongRepository : ISongRepository @@ -89,15 +90,21 @@ public class SongRepository : ISongRepository
return ids;
}
public Task<bool> AddGenre(SongMetadata metadata, Genre genre) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddGenre(SongMetadata metadata, Genre genre)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Genre (Name, SongMetadataId) VALUES (@Name, @MetadataId)",
new { genre.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddTag(SongMetadata metadata, Tag tag) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddTag(SongMetadata metadata, Tag tag)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Tag (Name, SongMetadataId) VALUES (@Name, @MetadataId)",
new { tag.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<List<SongMetadata>> GetSongsForCards(List<int> ids)
{

128
ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System.Data;
using Dapper;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -10,32 +9,39 @@ namespace ErsatzTV.Infrastructure.Data.Repositories; @@ -10,32 +9,39 @@ namespace ErsatzTV.Infrastructure.Data.Repositories;
public class TelevisionRepository : ITelevisionRepository
{
private readonly IDbConnection _dbConnection;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public TelevisionRepository(IDbConnection dbConnection, IDbContextFactory<TvContext> dbContextFactory)
public TelevisionRepository(IDbContextFactory<TvContext> dbContextFactory)
{
_dbConnection = dbConnection;
_dbContextFactory = dbContextFactory;
}
public Task<bool> AllShowsExist(List<int> showIds) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<bool> AllShowsExist(List<int> showIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<int>(
"SELECT COUNT(*) FROM Show WHERE Id in @ShowIds",
new { ShowIds = showIds })
.Map(c => c == showIds.Count);
}
public Task<bool> AllSeasonsExist(List<int> seasonIds) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<bool> AllSeasonsExist(List<int> seasonIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<int>(
"SELECT COUNT(*) FROM Season WHERE Id in @SeasonIds",
new { SeasonIds = seasonIds })
.Map(c => c == seasonIds.Count);
}
public Task<bool> AllEpisodesExist(List<int> episodeIds) =>
_dbConnection.QuerySingleAsync<int>(
public async Task<bool> AllEpisodesExist(List<int> episodeIds)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QuerySingleAsync<int>(
"SELECT COUNT(*) FROM Episode WHERE Id in @EpisodeIds",
new { EpisodeIds = episodeIds })
.Map(c => c == episodeIds.Count);
}
public async Task<List<Show>> GetAllShows()
{
@ -161,7 +167,9 @@ public class TelevisionRepository : ITelevisionRepository @@ -161,7 +167,9 @@ public class TelevisionRepository : ITelevisionRepository
public async Task<List<Season>> GetPagedSeasons(int televisionShowId, int pageNumber, int pageSize)
{
List<int> showIds = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> showIds = await dbContext.Connection.QueryAsync<int>(
@"SELECT m1.ShowId
FROM ShowMetadata m1
LEFT OUTER JOIN ShowMetadata m2 ON m2.ShowId = @ShowId
@ -169,7 +177,6 @@ public class TelevisionRepository : ITelevisionRepository @@ -169,7 +177,6 @@ public class TelevisionRepository : ITelevisionRepository
new { ShowId = televisionShowId })
.Map(results => results.ToList());
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Seasons
.AsNoTracking()
.Where(s => showIds.Contains(s.ShowId))
@ -357,7 +364,7 @@ public class TelevisionRepository : ITelevisionRepository @@ -357,7 +364,7 @@ public class TelevisionRepository : ITelevisionRepository
episode.SeasonId = season.Id;
episode.Season = season;
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"UPDATE Episode SET SeasonId = @SeasonId WHERE Id = @EpisodeId",
new { SeasonId = season.Id, EpisodeId = episode.Id });
}
@ -367,8 +374,10 @@ public class TelevisionRepository : ITelevisionRepository @@ -367,8 +374,10 @@ public class TelevisionRepository : ITelevisionRepository
async () => await AddEpisode(dbContext, season, libraryPath.Id, path));
}
public Task<IEnumerable<string>> FindEpisodePaths(LibraryPath libraryPath) =>
_dbConnection.QueryAsync<string>(
public async Task<IEnumerable<string>> FindEpisodePaths(LibraryPath libraryPath)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<string>(
@"SELECT MF.Path
FROM MediaFile MF
INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id
@ -376,10 +385,13 @@ public class TelevisionRepository : ITelevisionRepository @@ -376,10 +385,13 @@ public class TelevisionRepository : ITelevisionRepository
INNER JOIN MediaItem MI on E.Id = MI.Id
WHERE MI.LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPath.Id });
}
public async Task<Unit> DeleteByPath(LibraryPath libraryPath, string path)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT E.Id
FROM Episode E
INNER JOIN MediaItem MI on E.Id = MI.Id
@ -388,7 +400,6 @@ public class TelevisionRepository : ITelevisionRepository @@ -388,7 +400,6 @@ public class TelevisionRepository : ITelevisionRepository
WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path",
new { LibraryPathId = libraryPath.Id, Path = path });
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
foreach (int episodeId in ids)
{
Episode episode = await dbContext.Episodes.FindAsync(episodeId);
@ -521,8 +532,10 @@ public class TelevisionRepository : ITelevisionRepository @@ -521,8 +532,10 @@ public class TelevisionRepository : ITelevisionRepository
async () => await AddPlexEpisode(dbContext, library, item));
}
public Task<Unit> RemoveMissingPlexSeasons(string showKey, List<string> seasonKeys) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> RemoveMissingPlexSeasons(string showKey, List<string> seasonKeys)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
@"DELETE FROM MediaItem WHERE Id IN
(SELECT m.Id FROM MediaItem m
INNER JOIN Season s ON m.Id = s.Id
@ -530,10 +543,13 @@ public class TelevisionRepository : ITelevisionRepository @@ -530,10 +543,13 @@ public class TelevisionRepository : ITelevisionRepository
INNER JOIN PlexShow P on P.Id = s.ShowId
WHERE P.Key = @ShowKey AND ps.Key not in @Keys)",
new { ShowKey = showKey, Keys = seasonKeys }).ToUnit();
}
public async Task<List<int>> RemoveMissingPlexEpisodes(string seasonKey, List<string> episodeKeys)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN Episode e ON m.Id = e.Id
INNER JOIN PlexEpisode pe ON pe.Id = m.Id
@ -541,7 +557,7 @@ public class TelevisionRepository : ITelevisionRepository @@ -541,7 +557,7 @@ public class TelevisionRepository : ITelevisionRepository
WHERE P.Key = @SeasonKey AND pe.Key not in @Keys",
new { SeasonKey = seasonKey, Keys = episodeKeys }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });
@ -550,38 +566,49 @@ public class TelevisionRepository : ITelevisionRepository @@ -550,38 +566,49 @@ public class TelevisionRepository : ITelevisionRepository
public async Task<Unit> RemoveMetadata(Episode episode, EpisodeMetadata metadata)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
episode.EpisodeMetadata.Remove(metadata);
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
@"DELETE FROM EpisodeMetadata WHERE Id = @MetadataId",
new { MetadataId = metadata.Id });
return Unit.Default;
}
public Task<bool> AddDirector(EpisodeMetadata metadata, Director director) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddDirector(EpisodeMetadata metadata, Director director)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Director (Name, EpisodeMetadataId) VALUES (@Name, @MetadataId)",
new { director.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddWriter(EpisodeMetadata metadata, Writer writer) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddWriter(EpisodeMetadata metadata, Writer writer)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Writer (Name, EpisodeMetadataId) VALUES (@Name, @MetadataId)",
new { writer.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<Unit> UpdatePath(int mediaFileId, string path) =>
_dbConnection.ExecuteAsync(
public async Task<Unit> UpdatePath(int mediaFileId, string path)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"UPDATE MediaFile SET Path = @Path WHERE Id = @MediaFileId",
new { Path = path, MediaFileId = mediaFileId }).Map(_ => Unit.Default);
}
public async Task<List<Episode>> GetShowItems(int showId)
{
IEnumerable<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
IEnumerable<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT Episode.Id FROM Show
INNER JOIN Season ON Season.ShowId = Show.Id
INNER JOIN Episode ON Episode.SeasonId = Season.Id
WHERE Show.Id = @ShowId",
new { ShowId = showId });
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Episodes
.AsNoTracking()
.Include(e => e.EpisodeMetadata)
@ -613,28 +640,39 @@ public class TelevisionRepository : ITelevisionRepository @@ -613,28 +640,39 @@ public class TelevisionRepository : ITelevisionRepository
.ToListAsync();
}
public Task<bool> AddGenre(ShowMetadata metadata, Genre genre) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddGenre(ShowMetadata metadata, Genre genre)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Genre (Name, ShowMetadataId) VALUES (@Name, @MetadataId)",
new { genre.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddTag(ShowMetadata metadata, Tag tag) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddTag(ShowMetadata metadata, Tag tag)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Tag (Name, ShowMetadataId) VALUES (@Name, @MetadataId)",
new { tag.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public Task<bool> AddStudio(ShowMetadata metadata, Studio studio) =>
_dbConnection.ExecuteAsync(
public async Task<bool> AddStudio(ShowMetadata metadata, Studio studio)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Studio (Name, ShowMetadataId) VALUES (@Name, @MetadataId)",
new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<bool> AddActor(ShowMetadata metadata, Actor actor)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
int? artworkId = null;
if (actor.Artwork != null)
{
artworkId = await _dbConnection.QuerySingleAsync<int>(
artworkId = await dbContext.Connection.QuerySingleAsync<int>(
@"INSERT INTO Artwork (ArtworkKind, DateAdded, DateUpdated, Path)
VALUES (@ArtworkKind, @DateAdded, @DateUpdated, @Path);
SELECT last_insert_rowid()",
@ -647,7 +685,7 @@ public class TelevisionRepository : ITelevisionRepository @@ -647,7 +685,7 @@ public class TelevisionRepository : ITelevisionRepository
});
}
return await _dbConnection.ExecuteAsync(
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Actor (Name, Role, \"Order\", ShowMetadataId, ArtworkId) VALUES (@Name, @Role, @Order, @MetadataId, @ArtworkId)",
new { actor.Name, actor.Role, actor.Order, MetadataId = metadata.Id, ArtworkId = artworkId })
.Map(result => result > 0);
@ -655,11 +693,13 @@ public class TelevisionRepository : ITelevisionRepository @@ -655,11 +693,13 @@ public class TelevisionRepository : ITelevisionRepository
public async Task<bool> AddActor(EpisodeMetadata metadata, Actor actor)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
int? artworkId = null;
if (actor.Artwork != null)
{
artworkId = await _dbConnection.QuerySingleAsync<int>(
artworkId = await dbContext.Connection.QuerySingleAsync<int>(
@"INSERT INTO Artwork (ArtworkKind, DateAdded, DateUpdated, Path)
VALUES (@ArtworkKind, @DateAdded, @DateUpdated, @Path);
SELECT last_insert_rowid()",
@ -672,7 +712,7 @@ public class TelevisionRepository : ITelevisionRepository @@ -672,7 +712,7 @@ public class TelevisionRepository : ITelevisionRepository
});
}
return await _dbConnection.ExecuteAsync(
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO Actor (Name, Role, \"Order\", EpisodeMetadataId, ArtworkId) VALUES (@Name, @Role, @Order, @MetadataId, @ArtworkId)",
new { actor.Name, actor.Role, actor.Order, MetadataId = metadata.Id, ArtworkId = artworkId })
.Map(result => result > 0);
@ -680,14 +720,16 @@ public class TelevisionRepository : ITelevisionRepository @@ -680,14 +720,16 @@ public class TelevisionRepository : ITelevisionRepository
public async Task<List<int>> RemoveMissingPlexShows(PlexLibrary library, List<string> showKeys)
{
List<int> ids = await _dbConnection.QueryAsync<int>(
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
List<int> ids = await dbContext.Connection.QueryAsync<int>(
@"SELECT m.Id FROM MediaItem m
INNER JOIN PlexShow ps ON ps.Id = m.Id
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
WHERE lp.LibraryId = @LibraryId AND ps.Key not in @Keys",
new { LibraryId = library.Id, Keys = showKeys }).Map(result => result.ToList());
await _dbConnection.ExecuteAsync(
await dbContext.Connection.ExecuteAsync(
"DELETE FROM MediaItem WHERE Id IN @Ids",
new { Ids = ids });

5
ErsatzTV.Infrastructure/Data/TvContext.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using System.Data;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@ -13,6 +14,8 @@ public class TvContext : DbContext @@ -13,6 +14,8 @@ public class TvContext : DbContext
: base(options) =>
_loggerFactory = loggerFactory;
public IDbConnection Connection => Database.GetDbConnection();
public DbSet<ConfigElement> ConfigElements { get; set; }
public DbSet<Channel> Channels { get; set; }
public DbSet<ChannelWatermark> ChannelWatermarks { get; set; }

3
ErsatzTV/Startup.cs

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
using System.Data;
using System.Reflection;
using System.Text;
using System.Threading.Channels;
@ -55,7 +54,6 @@ using Ganss.XSS; @@ -55,7 +54,6 @@ using Ganss.XSS;
using MediatR;
using MediatR.Courier.DependencyInjection;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using MudBlazor.Services;
@ -200,7 +198,6 @@ public class Startup @@ -200,7 +198,6 @@ public class Startup
o.MigrationsAssembly("ErsatzTV.Infrastructure");
}));
services.AddTransient<IDbConnection>(_ => new SqliteConnection(connectionString));
SqlMapper.AddTypeHandler(new DateTimeOffsetHandler());
SqlMapper.AddTypeHandler(new GuidHandler());
SqlMapper.AddTypeHandler(new TimeSpanHandler());

Loading…
Cancel
Save