jellyfin and emby path infos (#771)

* start adding jellyfin path info; fix some scanning bugs

* sync jellyfin libraries before scanning to ensure latest path infos

* code cleanup

* support emby path infos

* fix periodic scanning of emby and jellyfin libraries

* bug fixes
This commit is contained in:
Jason Dove
2022-04-29 15:07:17 -05:00
committed by GitHub
parent 4ed40acfbe
commit 404ea49e35
70 changed files with 13498 additions and 553 deletions
+3 -30
View File
@@ -50,9 +50,6 @@ public class EmbyService : BackgroundService
case SynchronizeEmbyMediaSources synchronizeEmbyMediaSources:
requestTask = SynchronizeSources(synchronizeEmbyMediaSources, cancellationToken);
break;
// case SynchronizeEmbyAdminUserId synchronizeEmbyAdminUserId:
// requestTask = SynchronizeAdminUserId(synchronizeEmbyAdminUserId, cancellationToken);
// break;
case SynchronizeEmbyLibraries synchronizeEmbyLibraries:
requestTask = SynchronizeLibraries(synchronizeEmbyLibraries, cancellationToken);
break;
@@ -93,9 +90,7 @@ public class EmbyService : BackgroundService
}
}
private async Task SynchronizeSources(
SynchronizeEmbyMediaSources request,
CancellationToken cancellationToken)
private async Task SynchronizeSources(SynchronizeEmbyMediaSources request, CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
@@ -117,9 +112,7 @@ public class EmbyService : BackgroundService
});
}
private async Task SynchronizeLibraries(
SynchronizeEmbyLibraries request,
CancellationToken cancellationToken)
private async Task SynchronizeLibraries(SynchronizeEmbyLibraries request, CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
@@ -135,27 +128,7 @@ public class EmbyService : BackgroundService
error.Value));
}
// private async Task SynchronizeAdminUserId(
// SynchronizeEmbyAdminUserId request,
// CancellationToken cancellationToken)
// {
// using IServiceScope scope = _serviceScopeFactory.CreateScope();
// IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
//
// Either<BaseError, Unit> result = await mediator.Send(request, cancellationToken);
// result.BiIter(
// _ => _logger.LogInformation(
// "Successfully synchronized Emby admin user id for source {MediaSourceId}",
// request.EmbyMediaSourceId),
// error => _logger.LogWarning(
// "Unable to synchronize Emby admin user id for source {MediaSourceId}: {Error}",
// request.EmbyMediaSourceId,
// error.Value));
// }
private async Task SynchronizeEmbyLibrary(
ISynchronizeEmbyLibraryById request,
CancellationToken cancellationToken)
private async Task SynchronizeEmbyLibrary(ISynchronizeEmbyLibraryById request, CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
+1 -3
View File
@@ -119,9 +119,7 @@ public class JellyfinService : BackgroundService
});
}
private async Task SynchronizeLibraries(
SynchronizeJellyfinLibraries request,
CancellationToken cancellationToken)
private async Task SynchronizeLibraries(SynchronizeJellyfinLibraries request, CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
+44 -11
View File
@@ -1,6 +1,8 @@
using System.Threading.Channels;
using Bugsnag;
using ErsatzTV.Application;
using ErsatzTV.Application.Emby;
using ErsatzTV.Application.Jellyfin;
using ErsatzTV.Application.Maintenance;
using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.MediaSources;
@@ -17,7 +19,9 @@ namespace ErsatzTV.Services;
public class SchedulerService : BackgroundService
{
private readonly ChannelWriter<IEmbyBackgroundServiceRequest> _embyWorkerChannel;
private readonly IEntityLocker _entityLocker;
private readonly ChannelWriter<IJellyfinBackgroundServiceRequest> _jellyfinWorkerChannel;
private readonly ILogger<SchedulerService> _logger;
private readonly ChannelWriter<IPlexBackgroundServiceRequest> _plexWorkerChannel;
private readonly IServiceScopeFactory _serviceScopeFactory;
@@ -27,12 +31,16 @@ public class SchedulerService : BackgroundService
IServiceScopeFactory serviceScopeFactory,
ChannelWriter<IBackgroundServiceRequest> workerChannel,
ChannelWriter<IPlexBackgroundServiceRequest> plexWorkerChannel,
ChannelWriter<IJellyfinBackgroundServiceRequest> jellyfinWorkerChannel,
ChannelWriter<IEmbyBackgroundServiceRequest> embyWorkerChannel,
IEntityLocker entityLocker,
ILogger<SchedulerService> logger)
{
_serviceScopeFactory = serviceScopeFactory;
_workerChannel = workerChannel;
_plexWorkerChannel = plexWorkerChannel;
_jellyfinWorkerChannel = jellyfinWorkerChannel;
_embyWorkerChannel = embyWorkerChannel;
_entityLocker = entityLocker;
_logger = logger;
}
@@ -89,6 +97,8 @@ public class SchedulerService : BackgroundService
await BuildPlayouts(cancellationToken);
await ScanLocalMediaSources(cancellationToken);
await ScanPlexMediaSources(cancellationToken);
await ScanJellyfinMediaSources(cancellationToken);
await ScanEmbyMediaSources(cancellationToken);
await MatchTraktLists(cancellationToken);
}
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
@@ -177,12 +187,7 @@ public class SchedulerService : BackgroundService
using IServiceScope scope = _serviceScopeFactory.CreateScope();
TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
List<int> localLibraryIds = await dbContext.LocalMediaSources
.SelectMany(ms => ms.Libraries)
.Map(l => l.Id)
.ToListAsync(cancellationToken);
foreach (int libraryId in localLibraryIds)
foreach (int libraryId in dbContext.LocalMediaSources.SelectMany(ms => ms.Libraries).Map(l => l.Id))
{
if (_entityLocker.LockLibrary(libraryId))
{
@@ -198,11 +203,7 @@ public class SchedulerService : BackgroundService
using IServiceScope scope = _serviceScopeFactory.CreateScope();
TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
List<PlexLibrary> plexLibraries = await dbContext.PlexLibraries
.Filter(l => l.ShouldSyncItems)
.ToListAsync(cancellationToken);
foreach (PlexLibrary library in plexLibraries)
foreach (PlexLibrary library in dbContext.PlexLibraries.Filter(l => l.ShouldSyncItems))
{
if (_entityLocker.LockLibrary(library.Id))
{
@@ -213,6 +214,38 @@ public class SchedulerService : BackgroundService
}
}
private async Task ScanJellyfinMediaSources(CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
foreach (JellyfinLibrary library in dbContext.JellyfinLibraries.Filter(l => l.ShouldSyncItems))
{
if (_entityLocker.LockLibrary(library.Id))
{
await _jellyfinWorkerChannel.WriteAsync(
new SynchronizeJellyfinLibraryByIdIfNeeded(library.Id),
cancellationToken);
}
}
}
private async Task ScanEmbyMediaSources(CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
foreach (EmbyLibrary library in dbContext.EmbyLibraries.Filter(l => l.ShouldSyncItems))
{
if (_entityLocker.LockLibrary(library.Id))
{
await _embyWorkerChannel.WriteAsync(
new SynchronizeEmbyLibraryByIdIfNeeded(library.Id),
cancellationToken);
}
}
}
private async Task MatchTraktLists(CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();