fix plex server and connection sync (#153)
This commit is contained in:
@@ -10,6 +10,7 @@ using ErsatzTV.Core.Interfaces.Plex;
|
|||||||
using ErsatzTV.Core.Interfaces.Repositories;
|
using ErsatzTV.Core.Interfaces.Repositories;
|
||||||
using LanguageExt;
|
using LanguageExt;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Plex.Commands
|
namespace ErsatzTV.Application.Plex.Commands
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,7 @@ namespace ErsatzTV.Application.Plex.Commands
|
|||||||
{
|
{
|
||||||
private readonly ChannelWriter<IPlexBackgroundServiceRequest> _channel;
|
private readonly ChannelWriter<IPlexBackgroundServiceRequest> _channel;
|
||||||
private readonly IEntityLocker _entityLocker;
|
private readonly IEntityLocker _entityLocker;
|
||||||
|
private readonly ILogger<SynchronizePlexMediaSourcesHandler> _logger;
|
||||||
private readonly IMediaSourceRepository _mediaSourceRepository;
|
private readonly IMediaSourceRepository _mediaSourceRepository;
|
||||||
private readonly IPlexTvApiClient _plexTvApiClient;
|
private readonly IPlexTvApiClient _plexTvApiClient;
|
||||||
|
|
||||||
@@ -26,12 +28,14 @@ namespace ErsatzTV.Application.Plex.Commands
|
|||||||
IMediaSourceRepository mediaSourceRepository,
|
IMediaSourceRepository mediaSourceRepository,
|
||||||
IPlexTvApiClient plexTvApiClient,
|
IPlexTvApiClient plexTvApiClient,
|
||||||
ChannelWriter<IPlexBackgroundServiceRequest> channel,
|
ChannelWriter<IPlexBackgroundServiceRequest> channel,
|
||||||
IEntityLocker entityLocker)
|
IEntityLocker entityLocker,
|
||||||
|
ILogger<SynchronizePlexMediaSourcesHandler> logger)
|
||||||
{
|
{
|
||||||
_mediaSourceRepository = mediaSourceRepository;
|
_mediaSourceRepository = mediaSourceRepository;
|
||||||
_plexTvApiClient = plexTvApiClient;
|
_plexTvApiClient = plexTvApiClient;
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_entityLocker = entityLocker;
|
_entityLocker = entityLocker;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Either<BaseError, List<PlexMediaSource>>> Handle(
|
public Task<Either<BaseError, List<PlexMediaSource>>> Handle(
|
||||||
@@ -47,6 +51,14 @@ namespace ErsatzTV.Application.Plex.Commands
|
|||||||
await SynchronizeServer(allExisting, server);
|
await SynchronizeServer(allExisting, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete removed servers
|
||||||
|
foreach (PlexMediaSource removed in allExisting.Filter(
|
||||||
|
s => servers.All(pms => pms.ClientIdentifier != s.ClientIdentifier)))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Deleting removed Plex server {ServerName}!", removed.Id.ToString());
|
||||||
|
await _mediaSourceRepository.DeletePlex(removed);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (PlexMediaSource mediaSource in await _mediaSourceRepository.GetAllPlex())
|
foreach (PlexMediaSource mediaSource in await _mediaSourceRepository.GetAllPlex())
|
||||||
{
|
{
|
||||||
await _channel.WriteAsync(new SynchronizePlexLibraries(mediaSource.Id));
|
await _channel.WriteAsync(new SynchronizePlexLibraries(mediaSource.Id));
|
||||||
@@ -72,7 +84,7 @@ namespace ErsatzTV.Application.Plex.Commands
|
|||||||
.Filter(connection => existing.Connections.All(c => c.Uri != connection.Uri)).ToList();
|
.Filter(connection => existing.Connections.All(c => c.Uri != connection.Uri)).ToList();
|
||||||
var toRemove = existing.Connections
|
var toRemove = existing.Connections
|
||||||
.Filter(connection => server.Connections.All(c => c.Uri != connection.Uri)).ToList();
|
.Filter(connection => server.Connections.All(c => c.Uri != connection.Uri)).ToList();
|
||||||
return _mediaSourceRepository.Update(existing, toAdd, toRemove);
|
return _mediaSourceRepository.Update(existing, server.Connections, toAdd, toRemove);
|
||||||
},
|
},
|
||||||
async () =>
|
async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ namespace ErsatzTV.Core.Interfaces.Repositories
|
|||||||
Task<List<PlexPathReplacement>> GetPlexPathReplacementsByLibraryId(int plexLibraryPathId);
|
Task<List<PlexPathReplacement>> GetPlexPathReplacementsByLibraryId(int plexLibraryPathId);
|
||||||
Task<int> CountMediaItems(int id);
|
Task<int> CountMediaItems(int id);
|
||||||
Task Update(LocalMediaSource localMediaSource);
|
Task Update(LocalMediaSource localMediaSource);
|
||||||
Task Update(PlexMediaSource plexMediaSource, List<PlexConnection> toAdd, List<PlexConnection> toDelete);
|
|
||||||
|
Task Update(
|
||||||
|
PlexMediaSource plexMediaSource,
|
||||||
|
List<PlexConnection> prioritizedConnections,
|
||||||
|
List<PlexConnection> toAdd,
|
||||||
|
List<PlexConnection> toDelete);
|
||||||
|
|
||||||
Task<Unit> UpdateLibraries(
|
Task<Unit> UpdateLibraries(
|
||||||
int plexMediaSourceId,
|
int plexMediaSourceId,
|
||||||
@@ -36,6 +41,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories
|
|||||||
Task Update(PlexLibrary plexMediaSourceLibrary);
|
Task Update(PlexLibrary plexMediaSourceLibrary);
|
||||||
Task Delete(int mediaSourceId);
|
Task Delete(int mediaSourceId);
|
||||||
Task<List<int>> DeleteAllPlex();
|
Task<List<int>> DeleteAllPlex();
|
||||||
|
Task<List<int>> DeletePlex(PlexMediaSource plexMediaSource);
|
||||||
Task<List<int>> DisablePlexLibrarySync(List<int> libraryIds);
|
Task<List<int>> DisablePlexLibrarySync(List<int> libraryIds);
|
||||||
Task EnablePlexLibrarySync(IEnumerable<int> libraryIds);
|
Task EnablePlexLibrarySync(IEnumerable<int> libraryIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
|||||||
|
|
||||||
public async Task Update(
|
public async Task Update(
|
||||||
PlexMediaSource plexMediaSource,
|
PlexMediaSource plexMediaSource,
|
||||||
|
List<PlexConnection> sortedConnections,
|
||||||
List<PlexConnection> toAdd,
|
List<PlexConnection> toAdd,
|
||||||
List<PlexConnection> toDelete)
|
List<PlexConnection> toDelete)
|
||||||
{
|
{
|
||||||
@@ -174,27 +175,34 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
|||||||
plexMediaSource.Id
|
plexMediaSource.Id
|
||||||
});
|
});
|
||||||
|
|
||||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
|
|
||||||
|
|
||||||
foreach (PlexConnection add in toAdd)
|
foreach (PlexConnection add in toAdd)
|
||||||
{
|
{
|
||||||
add.PlexMediaSourceId = plexMediaSource.Id;
|
await _dbConnection.ExecuteAsync(
|
||||||
dbContext.Entry(add).State = EntityState.Added;
|
@"INSERT INTO PlexConnection (IsActive, Uri, PlexMediaSourceId)
|
||||||
|
VALUES (0, @Uri, @PlexMediaSourceId)",
|
||||||
|
new { add.Uri, PlexMediaSourceId = plexMediaSource.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PlexConnection delete in toDelete)
|
foreach (PlexConnection delete in toDelete)
|
||||||
{
|
{
|
||||||
dbContext.Entry(delete).State = EntityState.Deleted;
|
await _dbConnection.ExecuteAsync(
|
||||||
|
@"DELETE FROM PlexConnection WHERE Id = @Id",
|
||||||
|
new { delete.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync();
|
int activeCount = await _dbConnection.QuerySingleAsync<int>(
|
||||||
|
@"SELECT COUNT(*) FROM PlexConnection WHERE IsActive = 1 AND PlexMediaSourceId = @PlexMediaSourceId",
|
||||||
PlexMediaSource pms = await dbContext.PlexMediaSources.FindAsync(plexMediaSource.Id);
|
new { PlexMediaSourceId = plexMediaSource.Id });
|
||||||
await dbContext.Entry(pms).Collection(x => x.Connections).LoadAsync();
|
if (activeCount == 0)
|
||||||
if (plexMediaSource.Connections.Any() && plexMediaSource.Connections.All(c => !c.IsActive))
|
|
||||||
{
|
{
|
||||||
plexMediaSource.Connections.Head().IsActive = true;
|
Option<PlexConnection> toActivate =
|
||||||
await dbContext.SaveChangesAsync();
|
sortedConnections.FirstOrDefault(c => toDelete.All(d => d.Id != c.Id));
|
||||||
|
|
||||||
|
// update on uri because connections from Plex API don't have our local ids
|
||||||
|
await toActivate.IfSomeAsync(
|
||||||
|
async c => await _dbConnection.ExecuteAsync(
|
||||||
|
@"UPDATE PlexConnection SET IsActive = 1 WHERE Uri = @Uri",
|
||||||
|
new { c.Uri }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,6 +300,23 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
|||||||
return movieIds.Append(showIds).ToList();
|
return movieIds.Append(showIds).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<int>> DeletePlex(PlexMediaSource plexMediaSource)
|
||||||
|
{
|
||||||
|
List<int> mediaItemIds = await _dbConnection.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
|
||||||
|
WHERE L.MediaSourceId = @PlexMediaSourceId",
|
||||||
|
new { PlexMediaSourceId = plexMediaSource.Id })
|
||||||
|
.Map(result => result.ToList());
|
||||||
|
|
||||||
|
await _dbConnection.ExecuteAsync(
|
||||||
|
@"DELETE FROM MediaSource WHERE Id = @PlexMediaSourceId",
|
||||||
|
new { PlexMediaSourceId = plexMediaSource.Id });
|
||||||
|
|
||||||
|
return mediaItemIds;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<int>> DisablePlexLibrarySync(List<int> libraryIds)
|
public async Task<List<int>> DisablePlexLibrarySync(List<int> libraryIds)
|
||||||
{
|
{
|
||||||
await _dbConnection.ExecuteAsync(
|
await _dbConnection.ExecuteAsync(
|
||||||
|
|||||||
Reference in New Issue
Block a user