Browse Source

remove jellyfin admin user id requirement (#2025)

pull/2027/head
Jason Dove 2 weeks ago committed by GitHub
parent
commit
da1cfab5f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/Emby/Commands/SynchronizeEmbyMediaSourcesHandler.cs
  3. 6
      ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserId.cs
  4. 107
      ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs
  5. 3
      ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinMediaSourcesHandler.cs
  6. 1
      ErsatzTV.Core/Interfaces/Jellyfin/IJellyfinApiClient.cs
  7. 14
      ErsatzTV.Infrastructure/Jellyfin/IJellyfinApi.cs
  8. 82
      ErsatzTV.Infrastructure/Jellyfin/JellyfinApiClient.cs
  9. 5
      ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserId.cs
  10. 103
      ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs
  11. 11
      ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinLibraryByIdHandler.cs
  12. 11
      ErsatzTV.Scanner/Core/Jellyfin/JellyfinCollectionScanner.cs
  13. 21
      ErsatzTV/Services/ScannerService.cs

1
CHANGELOG.md

@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- When the connection is no longer cached, a ping will be sent to the last used address for Plex (the last address that had a successful ping)
- If the ping is successful, the address will be cached for another 30 seconds
- If the ping is not successful, all addresses will be checked again, and the first address to return a successful ping will be cached for 30 seconds
- Remove requirement to have Jellyfin admin user; user id is no longer required on requests to latest Jellyfin server
### Fixed
- Fix error message about synchronizing Plex collections from a Plex server that has zero collections

1
ErsatzTV.Application/Emby/Commands/SynchronizeEmbyMediaSourcesHandler.cs

@ -26,7 +26,6 @@ public class SynchronizeEmbyMediaSourcesHandler : IRequestHandler<SynchronizeEmb @@ -26,7 +26,6 @@ public class SynchronizeEmbyMediaSourcesHandler : IRequestHandler<SynchronizeEmb
List<EmbyMediaSource> mediaSources = await _mediaSourceRepository.GetAllEmby();
foreach (EmbyMediaSource mediaSource in mediaSources)
{
// await _channel.WriteAsync(new SynchronizeEmbyAdminUserId(mediaSource.Id), cancellationToken);
await _scannerWorkerChannel.WriteAsync(new SynchronizeEmbyLibraries(mediaSource.Id), cancellationToken);
}

6
ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserId.cs

@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
using ErsatzTV.Core;
namespace ErsatzTV.Application.Jellyfin;
public record SynchronizeJellyfinAdminUserId(int JellyfinMediaSourceId) : IRequest<Either<BaseError, Unit>>,
IScannerBackgroundServiceRequest;

107
ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs

@ -1,107 +0,0 @@ @@ -1,107 +0,0 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Jellyfin;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Application.Jellyfin;
public class
SynchronizeJellyfinAdminUserIdHandler : IRequestHandler<SynchronizeJellyfinAdminUserId,
Either<BaseError, Unit>>
{
private readonly IJellyfinApiClient _jellyfinApiClient;
private readonly IJellyfinSecretStore _jellyfinSecretStore;
private readonly ILogger<SynchronizeJellyfinAdminUserIdHandler> _logger;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMemoryCache _memoryCache;
public SynchronizeJellyfinAdminUserIdHandler(
IMemoryCache memoryCache,
IMediaSourceRepository mediaSourceRepository,
IJellyfinSecretStore jellyfinSecretStore,
IJellyfinApiClient jellyfinApiClient,
ILogger<SynchronizeJellyfinAdminUserIdHandler> logger)
{
_memoryCache = memoryCache;
_mediaSourceRepository = mediaSourceRepository;
_jellyfinSecretStore = jellyfinSecretStore;
_jellyfinApiClient = jellyfinApiClient;
_logger = logger;
}
public Task<Either<BaseError, Unit>> Handle(
SynchronizeJellyfinAdminUserId request,
CancellationToken cancellationToken) =>
Validate(request)
.Map(v => v.ToEither<ConnectionParameters>())
.BindT(PerformSync);
private async Task<Either<BaseError, Unit>> PerformSync(ConnectionParameters parameters)
{
if (_memoryCache.TryGetValue($"jellyfin_admin_user_id.{parameters.JellyfinMediaSource.Id}", out string _))
{
return Unit.Default;
}
Either<BaseError, string> maybeUserId = await _jellyfinApiClient.GetAdminUserId(
parameters.ActiveConnection.Address,
parameters.ApiKey);
return await maybeUserId.Match(
userId =>
{
// _logger.LogDebug("Jellyfin admin user id is {UserId}", userId);
_memoryCache.Set($"jellyfin_admin_user_id.{parameters.JellyfinMediaSource.Id}", userId);
return Task.FromResult<Either<BaseError, Unit>>(Unit.Default);
},
async error =>
{
// clear api key if unable to sync with jellyfin
if (error.Value.Contains("Unauthorized"))
{
await _jellyfinSecretStore.SaveSecrets(
new JellyfinSecrets { Address = parameters.ActiveConnection.Address, ApiKey = null });
}
return Left<BaseError, Unit>(error);
});
}
private Task<Validation<BaseError, ConnectionParameters>> Validate(SynchronizeJellyfinAdminUserId request) =>
MediaSourceMustExist(request)
.BindT(MediaSourceMustHaveActiveConnection)
.BindT(MediaSourceMustHaveApiKey);
private Task<Validation<BaseError, JellyfinMediaSource>> MediaSourceMustExist(
SynchronizeJellyfinAdminUserId request) =>
_mediaSourceRepository.GetJellyfin(request.JellyfinMediaSourceId)
.Map(o => o.ToValidation<BaseError>("Jellyfin media source does not exist."));
private Validation<BaseError, ConnectionParameters> MediaSourceMustHaveActiveConnection(
JellyfinMediaSource jellyfinMediaSource)
{
Option<JellyfinConnection> maybeConnection = jellyfinMediaSource.Connections.HeadOrNone();
return maybeConnection.Map(connection => new ConnectionParameters(jellyfinMediaSource, connection))
.ToValidation<BaseError>("Jellyfin media source requires an active connection");
}
private async Task<Validation<BaseError, ConnectionParameters>> MediaSourceMustHaveApiKey(
ConnectionParameters connectionParameters)
{
JellyfinSecrets secrets = await _jellyfinSecretStore.ReadSecrets();
return Optional(secrets.Address == connectionParameters.ActiveConnection.Address)
.Where(match => match)
.Map(_ => connectionParameters with { ApiKey = secrets.ApiKey })
.ToValidation<BaseError>("Jellyfin media source requires an api key");
}
private sealed record ConnectionParameters(
JellyfinMediaSource JellyfinMediaSource,
JellyfinConnection ActiveConnection)
{
public string ApiKey { get; set; }
}
}

3
ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinMediaSourcesHandler.cs

@ -26,9 +26,6 @@ public class SynchronizeJellyfinMediaSourcesHandler : IRequestHandler<Synchroniz @@ -26,9 +26,6 @@ public class SynchronizeJellyfinMediaSourcesHandler : IRequestHandler<Synchroniz
List<JellyfinMediaSource> mediaSources = await _mediaSourceRepository.GetAllJellyfin();
foreach (JellyfinMediaSource mediaSource in mediaSources)
{
await _scannerWorkerChannel.WriteAsync(
new SynchronizeJellyfinAdminUserId(mediaSource.Id),
cancellationToken);
await _scannerWorkerChannel.WriteAsync(new SynchronizeJellyfinLibraries(mediaSource.Id), cancellationToken);
}

1
ErsatzTV.Core/Interfaces/Jellyfin/IJellyfinApiClient.cs

@ -7,7 +7,6 @@ public interface IJellyfinApiClient @@ -7,7 +7,6 @@ public interface IJellyfinApiClient
{
Task<Either<BaseError, JellyfinServerInformation>> GetServerInformation(string address, string apiKey);
Task<Either<BaseError, List<JellyfinLibrary>>> GetLibraries(string address, string apiKey);
Task<Either<BaseError, string>> GetAdminUserId(string address, string apiKey);
IAsyncEnumerable<Tuple<JellyfinMovie, int>> GetMovieLibraryItems(string address, string apiKey, JellyfinLibrary library);

14
ErsatzTV.Infrastructure/Jellyfin/IJellyfinApi.cs

@ -27,8 +27,6 @@ public interface IJellyfinApi @@ -27,8 +27,6 @@ public interface IJellyfinApi
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
[Query]
string parentId,
[Query]
string fields =
@ -49,8 +47,6 @@ public interface IJellyfinApi @@ -49,8 +47,6 @@ public interface IJellyfinApi
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
[Query]
string parentId,
[Query]
string fields =
@ -69,8 +65,6 @@ public interface IJellyfinApi @@ -69,8 +65,6 @@ public interface IJellyfinApi
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
[Query]
string parentId,
[Query]
string fields = "Path,DateCreated,Etag,Taglines,ProviderIds",
@ -88,8 +82,6 @@ public interface IJellyfinApi @@ -88,8 +82,6 @@ public interface IJellyfinApi
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
[Query]
string parentId,
[Query]
string fields = "Path,Genres,Tags,DateCreated,Etag,Overview,ProviderIds,People,Chapters",
@ -107,8 +99,6 @@ public interface IJellyfinApi @@ -107,8 +99,6 @@ public interface IJellyfinApi
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
[Query]
string parentId,
[Query]
string fields = "Etag",
@ -126,8 +116,6 @@ public interface IJellyfinApi @@ -126,8 +116,6 @@ public interface IJellyfinApi
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
[Query]
string parentId,
[Query]
string fields = "Etag",
@ -144,7 +132,5 @@ public interface IJellyfinApi @@ -144,7 +132,5 @@ public interface IJellyfinApi
public Task<JellyfinPlaybackInfoResponse> GetPlaybackInfo(
[Header("X-Emby-Token")]
string apiKey,
[Query]
string userId,
string itemId);
}

82
ErsatzTV.Infrastructure/Jellyfin/JellyfinApiClient.cs

@ -73,26 +73,6 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -73,26 +73,6 @@ public class JellyfinApiClient : IJellyfinApiClient
}
}
public async Task<Either<BaseError, string>> GetAdminUserId(string address, string apiKey)
{
try
{
IJellyfinApi service = RestService.For<IJellyfinApi>(address);
List<JellyfinUserResponse> users = await service.GetUsers(apiKey);
Option<string> maybeUserId = users
.Filter(user => user.Policy.IsAdministrator && !user.Policy.IsDisabled && user.Policy.EnableAllFolders)
.Map(user => user.Id)
.HeadOrNone();
return maybeUserId.ToEither(BaseError.New("Unable to locate jellyfin admin user"));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting jellyfin admin user id");
return BaseError.New(ex.Message);
}
}
public IAsyncEnumerable<Tuple<JellyfinMovie, int>> GetMovieLibraryItems(
string address,
string apiKey,
@ -102,9 +82,8 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -102,9 +82,8 @@ public class JellyfinApiClient : IJellyfinApiClient
library,
library.MediaSourceId,
library.ItemId,
(service, userId, itemId, skip, pageSize) => service.GetMovieLibraryItems(
(service, itemId, skip, pageSize) => service.GetMovieLibraryItems(
apiKey,
userId,
itemId,
startIndex: skip,
limit: pageSize),
@ -119,9 +98,8 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -119,9 +98,8 @@ public class JellyfinApiClient : IJellyfinApiClient
library,
library.MediaSourceId,
library.ItemId,
(service, userId, itemId, skip, pageSize) => service.GetShowLibraryItems(
(service, itemId, skip, pageSize) => service.GetShowLibraryItems(
apiKey,
userId,
itemId,
startIndex: skip,
limit: pageSize),
@ -137,9 +115,8 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -137,9 +115,8 @@ public class JellyfinApiClient : IJellyfinApiClient
library,
library.MediaSourceId,
showId,
(service, userId, _, skip, pageSize) => service.GetSeasonLibraryItems(
(service, _, skip, pageSize) => service.GetSeasonLibraryItems(
apiKey,
userId,
showId,
startIndex: skip,
limit: pageSize),
@ -155,9 +132,8 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -155,9 +132,8 @@ public class JellyfinApiClient : IJellyfinApiClient
library,
library.MediaSourceId,
seasonId,
(service, userId, _, skip, pageSize) => service.GetEpisodeLibraryItems(
(service, _, skip, pageSize) => service.GetEpisodeLibraryItems(
apiKey,
userId,
seasonId,
startIndex: skip,
limit: pageSize),
@ -177,9 +153,8 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -177,9 +153,8 @@ public class JellyfinApiClient : IJellyfinApiClient
None,
mediaSourceId,
itemId,
(service, userId, _, skip, pageSize) => service.GetCollectionLibraryItems(
(service, _, skip, pageSize) => service.GetCollectionLibraryItems(
apiKey,
userId,
itemId,
startIndex: skip,
limit: pageSize),
@ -199,9 +174,8 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -199,9 +174,8 @@ public class JellyfinApiClient : IJellyfinApiClient
None,
mediaSourceId,
collectionId,
(service, userId, _, skip, pageSize) => service.GetCollectionItems(
(service, _, skip, pageSize) => service.GetCollectionItems(
apiKey,
userId,
collectionId,
startIndex: skip,
limit: pageSize),
@ -215,15 +189,10 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -215,15 +189,10 @@ public class JellyfinApiClient : IJellyfinApiClient
{
try
{
if (_memoryCache.TryGetValue($"jellyfin_admin_user_id.{library.MediaSourceId}", out string userId))
{
IJellyfinApi service = RestService.For<IJellyfinApi>(address);
JellyfinPlaybackInfoResponse playbackInfo = await service.GetPlaybackInfo(apiKey, userId, itemId);
Option<MediaVersion> maybeVersion = ProjectToMediaVersion(playbackInfo);
return maybeVersion.ToEither(() => BaseError.New("Unable to locate Jellyfin statistics"));
}
return BaseError.New("Jellyfin admin user id is not available");
IJellyfinApi service = RestService.For<IJellyfinApi>(address);
JellyfinPlaybackInfoResponse playbackInfo = await service.GetPlaybackInfo(apiKey, itemId);
Option<MediaVersion> maybeVersion = ProjectToMediaVersion(playbackInfo);
return maybeVersion.ToEither(() => BaseError.New("Unable to locate Jellyfin statistics"));
}
catch (Exception ex)
{
@ -232,34 +201,31 @@ public class JellyfinApiClient : IJellyfinApiClient @@ -232,34 +201,31 @@ public class JellyfinApiClient : IJellyfinApiClient
}
}
private async IAsyncEnumerable<Tuple<TItem, int>> GetPagedLibraryItems<TItem>(
private static async IAsyncEnumerable<Tuple<TItem, int>> GetPagedLibraryItems<TItem>(
string address,
Option<JellyfinLibrary> maybeLibrary,
int mediaSourceId,
string parentId,
Func<IJellyfinApi, string, string, int, int, Task<JellyfinLibraryItemsResponse>> getItems,
Func<IJellyfinApi, string, int, int, Task<JellyfinLibraryItemsResponse>> getItems,
Func<Option<JellyfinLibrary>, JellyfinLibraryItemResponse, Option<TItem>> mapper)
{
if (_memoryCache.TryGetValue($"jellyfin_admin_user_id.{mediaSourceId}", out string userId))
{
IJellyfinApi service = RestService.For<IJellyfinApi>(address);
IJellyfinApi service = RestService.For<IJellyfinApi>(address);
const int PAGE_SIZE = 10;
const int PAGE_SIZE = 10;
int pages = int.MaxValue;
for (var i = 0; i < pages; i++)
{
int skip = i * PAGE_SIZE;
int pages = int.MaxValue;
for (var i = 0; i < pages; i++)
{
int skip = i * PAGE_SIZE;
JellyfinLibraryItemsResponse result = await getItems(service, userId, parentId, skip, PAGE_SIZE);
JellyfinLibraryItemsResponse result = await getItems(service, parentId, skip, PAGE_SIZE);
// update page count
pages = Math.Min(pages, (result.TotalRecordCount - 1) / PAGE_SIZE + 1);
// update page count
pages = Math.Min(pages, (result.TotalRecordCount - 1) / PAGE_SIZE + 1);
foreach (TItem item in result.Items.Map(item => mapper(maybeLibrary, item)).Somes())
{
yield return new Tuple<TItem, int>(item, result.TotalRecordCount);
}
foreach (TItem item in result.Items.Map(item => mapper(maybeLibrary, item)).Somes())
{
yield return new Tuple<TItem, int>(item, result.TotalRecordCount);
}
}
}

5
ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserId.cs

@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
using ErsatzTV.Core;
namespace ErsatzTV.Scanner.Application.Jellyfin;
public record SynchronizeJellyfinAdminUserId(int JellyfinMediaSourceId) : IRequest<Either<BaseError, Unit>>;

103
ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinAdminUserIdHandler.cs

@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Jellyfin;
using Microsoft.Extensions.Caching.Memory;
namespace ErsatzTV.Scanner.Application.Jellyfin;
public class
SynchronizeJellyfinAdminUserIdHandler : IRequestHandler<SynchronizeJellyfinAdminUserId,
Either<BaseError, Unit>>
{
private readonly IJellyfinApiClient _jellyfinApiClient;
private readonly IJellyfinSecretStore _jellyfinSecretStore;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMemoryCache _memoryCache;
public SynchronizeJellyfinAdminUserIdHandler(
IMemoryCache memoryCache,
IMediaSourceRepository mediaSourceRepository,
IJellyfinSecretStore jellyfinSecretStore,
IJellyfinApiClient jellyfinApiClient)
{
_memoryCache = memoryCache;
_mediaSourceRepository = mediaSourceRepository;
_jellyfinSecretStore = jellyfinSecretStore;
_jellyfinApiClient = jellyfinApiClient;
}
public Task<Either<BaseError, Unit>> Handle(
SynchronizeJellyfinAdminUserId request,
CancellationToken cancellationToken) =>
Validate(request)
.Map(v => v.ToEither<ConnectionParameters>())
.BindT(PerformSync);
private async Task<Either<BaseError, Unit>> PerformSync(ConnectionParameters parameters)
{
if (_memoryCache.TryGetValue($"jellyfin_admin_user_id.{parameters.JellyfinMediaSource.Id}", out string? _))
{
return Unit.Default;
}
Either<BaseError, string> maybeUserId = await _jellyfinApiClient.GetAdminUserId(
parameters.ActiveConnection.Address,
parameters.ApiKey);
return await maybeUserId.Match(
userId =>
{
// _logger.LogDebug("Jellyfin admin user id is {UserId}", userId);
_memoryCache.Set($"jellyfin_admin_user_id.{parameters.JellyfinMediaSource.Id}", userId);
return Task.FromResult<Either<BaseError, Unit>>(Unit.Default);
},
async error =>
{
// clear api key if unable to sync with jellyfin
if (error.Value.Contains("Unauthorized"))
{
await _jellyfinSecretStore.SaveSecrets(
new JellyfinSecrets { Address = parameters.ActiveConnection.Address, ApiKey = null });
}
return Left<BaseError, Unit>(error);
});
}
private Task<Validation<BaseError, ConnectionParameters>> Validate(SynchronizeJellyfinAdminUserId request) =>
MediaSourceMustExist(request)
.BindT(MediaSourceMustHaveActiveConnection)
.BindT(MediaSourceMustHaveApiKey);
private Task<Validation<BaseError, JellyfinMediaSource>> MediaSourceMustExist(
SynchronizeJellyfinAdminUserId request) =>
_mediaSourceRepository.GetJellyfin(request.JellyfinMediaSourceId)
.Map(o => o.ToValidation<BaseError>("Jellyfin media source does not exist."));
private Validation<BaseError, ConnectionParameters> MediaSourceMustHaveActiveConnection(
JellyfinMediaSource jellyfinMediaSource)
{
Option<JellyfinConnection> maybeConnection = jellyfinMediaSource.Connections.HeadOrNone();
return maybeConnection.Map(connection => new ConnectionParameters(jellyfinMediaSource, connection))
.ToValidation<BaseError>("Jellyfin media source requires an active connection");
}
private async Task<Validation<BaseError, ConnectionParameters>> MediaSourceMustHaveApiKey(
ConnectionParameters connectionParameters)
{
JellyfinSecrets secrets = await _jellyfinSecretStore.ReadSecrets();
return Optional(secrets.Address == connectionParameters.ActiveConnection.Address)
.Where(match => match)
.Map(_ => connectionParameters with { ApiKey = secrets.ApiKey })
.ToValidation<BaseError>("Jellyfin media source requires an api key");
}
private record ConnectionParameters(
JellyfinMediaSource JellyfinMediaSource,
JellyfinConnection ActiveConnection)
{
public string? ApiKey { get; init; }
}
}

11
ErsatzTV.Scanner/Application/Jellyfin/Commands/SynchronizeJellyfinLibraryByIdHandler.cs

@ -59,17 +59,6 @@ public class @@ -59,17 +59,6 @@ public class
DateTimeOffset nextScan = lastScan + TimeSpan.FromHours(parameters.LibraryRefreshInterval);
if (parameters.ForceScan || parameters.LibraryRefreshInterval > 0 && nextScan < DateTimeOffset.Now)
{
// need the jellyfin admin user id for now
Either<BaseError, Unit> syncAdminResult = await _mediator.Send(
new SynchronizeJellyfinAdminUserId(parameters.Library.MediaSourceId),
cancellationToken);
foreach (BaseError error in syncAdminResult.LeftToSeq())
{
_logger.LogError("Error synchronizing jellyfin admin user id: {Error}", error);
return error;
}
Either<BaseError, Unit> result = parameters.Library.MediaKind switch
{
LibraryMediaKind.Movies =>

11
ErsatzTV.Scanner/Core/Jellyfin/JellyfinCollectionScanner.cs

@ -31,17 +31,6 @@ public class JellyfinCollectionScanner : IJellyfinCollectionScanner @@ -31,17 +31,6 @@ public class JellyfinCollectionScanner : IJellyfinCollectionScanner
{
try
{
// need the jellyfin admin user id for now
Either<BaseError, Unit> syncAdminResult = await _mediator.Send(
new SynchronizeJellyfinAdminUserId(mediaSourceId),
CancellationToken.None);
foreach (BaseError error in syncAdminResult.LeftToSeq())
{
_logger.LogError("Error synchronizing jellyfin admin user id: {Error}", error);
return error;
}
// need to call get libraries to find library that contains collections (box sets)
await _jellyfinApiClient.GetLibraries(address, apiKey);

21
ErsatzTV/Services/ScannerService.cs

@ -57,9 +57,6 @@ public class ScannerService : BackgroundService @@ -57,9 +57,6 @@ public class ScannerService : BackgroundService
case SynchronizePlexCollections synchronizePlexCollections:
requestTask = SynchronizePlexCollections(synchronizePlexCollections, stoppingToken);
break;
case SynchronizeJellyfinAdminUserId synchronizeJellyfinAdminUserId:
requestTask = SynchronizeAdminUserId(synchronizeJellyfinAdminUserId, stoppingToken);
break;
case SynchronizeJellyfinLibraries synchronizeJellyfinLibraries:
requestTask = SynchronizeLibraries(synchronizeJellyfinLibraries, stoppingToken);
break;
@ -223,24 +220,6 @@ public class ScannerService : BackgroundService @@ -223,24 +220,6 @@ public class ScannerService : BackgroundService
}
}
private async Task SynchronizeAdminUserId(
SynchronizeJellyfinAdminUserId 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 Jellyfin admin user id for source {MediaSourceId}",
request.JellyfinMediaSourceId),
error => _logger.LogWarning(
"Unable to synchronize Jellyfin admin user id for source {MediaSourceId}: {Error}",
request.JellyfinMediaSourceId,
error.Value));
}
private async Task SynchronizeLibraries(SynchronizeJellyfinLibraries request, CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();

Loading…
Cancel
Save