using Dapper; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Infrastructure.Data.Repositories; public class JellyfinCollectionRepository : IJellyfinCollectionRepository { private readonly IDbContextFactory _dbContextFactory; public JellyfinCollectionRepository(IDbContextFactory dbContextFactory) => _dbContextFactory = dbContextFactory; public async Task> GetCollections() { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.JellyfinCollections.ToListAsync(); } public async Task AddCollection(JellyfinCollection collection) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); await dbContext.AddAsync(collection); return await dbContext.SaveChangesAsync() > 0; } public async Task RemoveCollection(JellyfinCollection collection) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); dbContext.Remove(collection); // remove all tags that reference this collection await dbContext.Connection.ExecuteAsync( @"DELETE FROM Tag WHERE Name = @Name AND ExternalCollectionId = @ItemId", new { collection.Name, collection.ItemId }); return await dbContext.SaveChangesAsync() > 0; } public async Task> RemoveAllTags(JellyfinCollection collection) { var result = new List(); await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); // movies result.AddRange( await dbContext.Connection.QueryAsync( @"SELECT JM.Id FROM Tag T INNER JOIN MovieMetadata MM on T.MovieMetadataId = MM.Id INNER JOIN JellyfinMovie JM on JM.Id = MM.MovieId WHERE T.ExternalCollectionId = @ItemId", new { collection.ItemId })); // shows result.AddRange( await dbContext.Connection.QueryAsync( @"SELECT JS.Id FROM Tag T INNER JOIN ShowMetadata SM on T.ShowMetadataId = SM.Id INNER JOIN JellyfinShow JS on JS.Id = SM.ShowId WHERE T.ExternalCollectionId = @ItemId", new { collection.ItemId })); // seasons result.AddRange( await dbContext.Connection.QueryAsync( @"SELECT JS.Id FROM Tag T INNER JOIN SeasonMetadata SM on T.SeasonMetadataId = SM.Id INNER JOIN JellyfinSeason JS on JS.Id = SM.SeasonId WHERE T.ExternalCollectionId = @ItemId", new { collection.ItemId })); // episodes result.AddRange( await dbContext.Connection.QueryAsync( @"SELECT JE.Id FROM Tag T INNER JOIN EpisodeMetadata EM on T.EpisodeMetadataId = EM.Id INNER JOIN JellyfinEpisode JE on JE.Id = EM.EpisodeId WHERE T.ExternalCollectionId = @ItemId", new { collection.ItemId })); // delete all tags await dbContext.Connection.ExecuteAsync( @"DELETE FROM Tag WHERE Name = @Name AND ExternalCollectionId = @ItemId", new { collection.Name, collection.ItemId }); return result; } public async Task AddTag(MediaItem item, JellyfinCollection collection) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); switch (item) { case JellyfinMovie movie: int movieId = await dbContext.Connection.ExecuteScalarAsync( @"SELECT Id FROM JellyfinMovie WHERE ItemId = @ItemId", new { movie.ItemId }); await dbContext.Connection.ExecuteAsync( @"INSERT INTO Tag (Name, ExternalCollectionId, MovieMetadataId) SELECT @Name, @ItemId, Id FROM (SELECT Id FROM MovieMetadata WHERE MovieId = @MovieId) AS A", new { collection.Name, collection.ItemId, MovieId = movieId }); return movieId; case JellyfinShow show: int showId = await dbContext.Connection.ExecuteScalarAsync( @"SELECT Id FROM JellyfinShow WHERE ItemId = @ItemId", new { show.ItemId }); await dbContext.Connection.ExecuteAsync( @"INSERT INTO Tag (Name, ExternalCollectionId, ShowMetadataId) SELECT @Name, @ItemId, Id FROM (SELECT Id FROM ShowMetadata WHERE ShowId = @ShowId) AS A", new { collection.Name, collection.ItemId, ShowId = showId }); return showId; case JellyfinSeason season: int seasonId = await dbContext.Connection.ExecuteScalarAsync( @"SELECT Id FROM JellyfinSeason WHERE ItemId = @ItemId", new { season.ItemId }); await dbContext.Connection.ExecuteAsync( @"INSERT INTO Tag (Name, ExternalCollectionId, SeasonMetadataId) SELECT @Name, @ItemId, Id FROM (SELECT Id FROM SeasonMetadata WHERE SeasonId = @SeasonId) AS A", new { collection.Name, collection.ItemId, SeasonId = seasonId }); return seasonId; case JellyfinEpisode episode: int episodeId = await dbContext.Connection.ExecuteScalarAsync( @"SELECT Id FROM JellyfinEpisode WHERE ItemId = @ItemId", new { episode.ItemId }); await dbContext.Connection.ExecuteAsync( @"INSERT INTO Tag (Name, ExternalCollectionId, EpisodeMetadataId) SELECT @Name, @ItemId, Id FROM (SELECT Id FROM EpisodeMetadata WHERE EpisodeId = @EpisodeId) AS A", new { collection.Name, collection.ItemId, EpisodeId = episodeId }); return episodeId; default: return 0; } } public async Task SetEtag(JellyfinCollection collection) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.Connection.ExecuteAsync( @"UPDATE JellyfinCollection SET Etag = @Etag WHERE ItemId = @ItemId", new { collection.Etag, collection.ItemId }) > 0; } }