Interface improvements (#34)
* fix plex library synchronization * add basic plex movie synchronization * proxy plex movie thumbnails (posters) * add plex path replacements * use transcoded plex artwork * remove unsynchronized plex movies on save; queue plex library scan on save * log plex path replacements * prefer buttons instead of menus * lock plex libraries before sync * add movie to collection from paged view * fix plex import memory use; quick add seasons/shows * quick add episode to collection * add favicon * add search page * disable plex for now
This commit is contained in:
@@ -49,10 +49,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.Map(Optional);
|
||||
}
|
||||
|
||||
public Task<List<LocalLibrary>> GetAllLocal()
|
||||
public Task<List<Library>> GetAll()
|
||||
{
|
||||
using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
return context.LocalLibraries.ToListAsync();
|
||||
return context.Libraries.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<Unit> UpdateLastScan(Library library) => _dbConnection.ExecuteAsync(
|
||||
|
||||
@@ -68,10 +68,19 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<List<PlexPathReplacement>> GetPlexPathReplacements(int plexMediaSourceId)
|
||||
{
|
||||
using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
return context.PlexPathReplacements
|
||||
.Filter(r => r.PlexMediaSourceId == plexMediaSourceId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<Option<PlexLibrary>> GetPlexLibrary(int plexLibraryId)
|
||||
{
|
||||
using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
return context.PlexLibraries
|
||||
.Include(l => l.Paths)
|
||||
.OrderBy(l => l.Id) // https://github.com/dotnet/efcore/issues/22579
|
||||
.SingleOrDefaultAsync(l => l.Id == plexLibraryId)
|
||||
.Map(Optional);
|
||||
@@ -92,11 +101,37 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
return context.PlexMediaSources
|
||||
.Include(p => p.Connections)
|
||||
.Include(p => p.Libraries)
|
||||
.Include(p => p.PathReplacements)
|
||||
.OrderBy(s => s.Id) // https://github.com/dotnet/efcore/issues/22579
|
||||
.SingleOrDefaultAsync(p => p.Id == id)
|
||||
.Map(Optional);
|
||||
}
|
||||
|
||||
public Task<Option<PlexMediaSource>> GetPlexByLibraryId(int plexLibraryId)
|
||||
{
|
||||
using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
return context.PlexMediaSources
|
||||
.Include(p => p.Connections)
|
||||
.Include(p => p.Libraries)
|
||||
.Where(p => p.Libraries.Any(l => l.Id == plexLibraryId))
|
||||
.SingleOrDefaultAsync()
|
||||
.Map(Optional);
|
||||
}
|
||||
|
||||
public Task<List<PlexPathReplacement>> GetPlexPathReplacementsByLibraryId(int plexLibraryPathId)
|
||||
{
|
||||
using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
return context.PlexPathReplacements
|
||||
.FromSqlRaw(
|
||||
@"select ppr.* from LibraryPath lp
|
||||
inner join PlexLibrary pl ON pl.Id = lp.LibraryId
|
||||
inner join Library l ON l.Id = pl.Id
|
||||
inner join PlexPathReplacement ppr on ppr.PlexMediaSourceId = l.MediaSourceId
|
||||
where lp.Id = {0}",
|
||||
plexLibraryPathId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<int> CountMediaItems(int id)
|
||||
{
|
||||
using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
@@ -133,14 +168,29 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public Task DisablePlexLibrarySync(IEnumerable<int> libraryIds) =>
|
||||
_dbConnection.ExecuteAsync(
|
||||
"UPDATE PlexMediaSourceLibraries SET ShouldSyncItems = 0 WHERE Id in @ids",
|
||||
public async Task DisablePlexLibrarySync(List<int> libraryIds)
|
||||
{
|
||||
await _dbConnection.ExecuteAsync(
|
||||
"UPDATE PlexLibrary SET ShouldSyncItems = 0 WHERE Id IN @ids",
|
||||
new { ids = libraryIds });
|
||||
|
||||
await _dbConnection.ExecuteAsync(
|
||||
"UPDATE Library SET LastScan = null WHERE Id IN @ids",
|
||||
new { ids = libraryIds });
|
||||
|
||||
await _dbConnection.ExecuteAsync(
|
||||
@"DELETE FROM MediaItem WHERE Id IN
|
||||
(SELECT m.Id FROM MediaItem m
|
||||
INNER JOIN PlexMovie pm ON pm.Id = m.Id
|
||||
INNER JOIN LibraryPath lp ON lp.Id = m.LibraryPathId
|
||||
INNER JOIN Library l ON l.Id = lp.LibraryId
|
||||
WHERE l.Id IN @ids)",
|
||||
new { ids = libraryIds });
|
||||
}
|
||||
|
||||
public Task EnablePlexLibrarySync(IEnumerable<int> libraryIds) =>
|
||||
_dbConnection.ExecuteAsync(
|
||||
"UPDATE PlexMediaSourceLibraries SET ShouldSyncItems = 1 WHERE Id in @ids",
|
||||
"UPDATE PlexLibrary SET ShouldSyncItems = 1 WHERE Id IN @ids",
|
||||
new { ids = libraryIds });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,15 +58,18 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
|
||||
public async Task<Either<BaseError, PlexMovie>> GetOrAdd(PlexLibrary library, PlexMovie item)
|
||||
{
|
||||
Option<PlexMovie> maybeExisting = await _dbContext.PlexMovieMediaItems
|
||||
await using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
Option<PlexMovie> maybeExisting = await context.PlexMovies
|
||||
.AsNoTracking()
|
||||
.Include(i => i.MovieMetadata)
|
||||
.Include(i => i.Part)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.OrderBy(i => i.Key)
|
||||
.SingleOrDefaultAsync(i => i.Key == item.Key);
|
||||
|
||||
return await maybeExisting.Match(
|
||||
plexMovie => Right<BaseError, PlexMovie>(plexMovie).AsTask(),
|
||||
async () => await AddPlexMovie(library, item));
|
||||
async () => await AddPlexMovie(context, library, item));
|
||||
}
|
||||
|
||||
public async Task<bool> Update(Movie movie)
|
||||
@@ -119,17 +122,15 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Either<BaseError, PlexMovie>> AddPlexMovie(
|
||||
PlexLibrary library,
|
||||
PlexMovie item)
|
||||
private async Task<Either<BaseError, PlexMovie>> AddPlexMovie(TvContext context, PlexLibrary library, PlexMovie item)
|
||||
{
|
||||
try
|
||||
{
|
||||
item.LibraryPathId = library.Paths.Head().Id;
|
||||
|
||||
await _dbContext.PlexMovieMediaItems.AddAsync(item);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
await _dbContext.Entry(item).Reference(i => i.LibraryPath).LoadAsync();
|
||||
await context.PlexMovies.AddAsync(item);
|
||||
await context.SaveChangesAsync();
|
||||
await context.Entry(item).Reference(i => i.LibraryPath).LoadAsync();
|
||||
return item;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
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)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory;
|
||||
_dbConnection = dbConnection;
|
||||
}
|
||||
|
||||
public async Task<List<MediaItem>> SearchMediaItems(string query)
|
||||
{
|
||||
List<int> ids = await _dbConnection.QueryAsync<int>(
|
||||
@"SELECT M.Id FROM Movie M
|
||||
INNER JOIN MovieMetadata MM on M.Id = MM.MovieId
|
||||
WHERE MM.Title LIKE @Query
|
||||
UNION
|
||||
SELECT S.Id FROM Show S
|
||||
INNER JOIN ShowMetadata SM on S.Id = SM.ShowId
|
||||
WHERE SM.Title LIKE @Query",
|
||||
new { Query = $"%{query}%" })
|
||||
.Map(results => results.ToList());
|
||||
|
||||
await using TvContext context = _dbContextFactory.CreateDbContext();
|
||||
return await context.MediaItems
|
||||
.Filter(m => ids.Contains(m.Id))
|
||||
.Include(m => (m as Movie).MovieMetadata)
|
||||
.ThenInclude(mm => mm.Artwork)
|
||||
.Include(m => (m as Show).ShowMetadata)
|
||||
.ThenInclude(mm => mm.Artwork)
|
||||
.OfType<MediaItem>()
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user