Browse Source

add button to refresh list of libraries (#226)

* add button to refresh list of libraries

* code cleanup
pull/231/head
Jason Dove 4 years ago committed by GitHub
parent
commit
bbd8bc6c7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      ErsatzTV.Application/Emby/Commands/SynchronizeEmbyLibrariesHandler.cs
  2. 15
      ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibrariesHandler.cs
  3. 15
      ErsatzTV.Application/Plex/Commands/SynchronizePlexLibrariesHandler.cs
  4. 1
      ErsatzTV.Core/Interfaces/Locking/IEntityLocker.cs
  5. 6
      ErsatzTV.Core/Interfaces/Repositories/IMediaSourceRepository.cs
  6. 18
      ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs
  7. 3
      ErsatzTV.Infrastructure/Locking/EntityLocker.cs
  8. 13
      ErsatzTV/Pages/EmbyMediaSources.razor
  9. 13
      ErsatzTV/Pages/JellyfinMediaSources.razor
  10. 9
      ErsatzTV/Pages/PlexMediaSources.razor
  11. 11
      ErsatzTV/Shared/RemoteMediaSources.razor

15
ErsatzTV.Application/Emby/Commands/SynchronizeEmbyLibrariesHandler.cs

@ -7,6 +7,7 @@ using ErsatzTV.Core.Domain; @@ -7,6 +7,7 @@ using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Emby;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using LanguageExt;
using Microsoft.Extensions.Logging;
using static LanguageExt.Prelude;
@ -20,17 +21,20 @@ namespace ErsatzTV.Application.Emby.Commands @@ -20,17 +21,20 @@ namespace ErsatzTV.Application.Emby.Commands
private readonly IEmbySecretStore _embySecretStore;
private readonly ILogger<SynchronizeEmbyLibrariesHandler> _logger;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly ISearchIndex _searchIndex;
public SynchronizeEmbyLibrariesHandler(
IMediaSourceRepository mediaSourceRepository,
IEmbySecretStore embySecretStore,
IEmbyApiClient embyApiClient,
ILogger<SynchronizeEmbyLibrariesHandler> logger)
ILogger<SynchronizeEmbyLibrariesHandler> logger,
ISearchIndex searchIndex)
{
_mediaSourceRepository = mediaSourceRepository;
_embySecretStore = embySecretStore;
_embyApiClient = embyApiClient;
_logger = logger;
_searchIndex = searchIndex;
}
public Task<Either<BaseError, Unit>> Handle(
@ -75,16 +79,21 @@ namespace ErsatzTV.Application.Emby.Commands @@ -75,16 +79,21 @@ namespace ErsatzTV.Application.Emby.Commands
connectionParameters.ApiKey);
await maybeLibraries.Match(
libraries =>
async libraries =>
{
var existing = connectionParameters.EmbyMediaSource.Libraries.OfType<EmbyLibrary>()
.ToList();
var toAdd = libraries.Filter(library => existing.All(l => l.ItemId != library.ItemId)).ToList();
var toRemove = existing.Filter(library => libraries.All(l => l.ItemId != library.ItemId)).ToList();
return _mediaSourceRepository.UpdateLibraries(
List<int> ids = await _mediaSourceRepository.UpdateLibraries(
connectionParameters.EmbyMediaSource.Id,
toAdd,
toRemove);
if (ids.Any())
{
await _searchIndex.RemoveItems(ids);
_searchIndex.Commit();
}
},
error =>
{

15
ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibrariesHandler.cs

@ -6,6 +6,7 @@ using ErsatzTV.Core; @@ -6,6 +6,7 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Jellyfin;
using LanguageExt;
using Microsoft.Extensions.Logging;
@ -22,17 +23,20 @@ namespace ErsatzTV.Application.Jellyfin.Commands @@ -22,17 +23,20 @@ namespace ErsatzTV.Application.Jellyfin.Commands
private readonly IJellyfinSecretStore _jellyfinSecretStore;
private readonly ILogger<SynchronizeJellyfinLibrariesHandler> _logger;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly ISearchIndex _searchIndex;
public SynchronizeJellyfinLibrariesHandler(
IMediaSourceRepository mediaSourceRepository,
IJellyfinSecretStore jellyfinSecretStore,
IJellyfinApiClient jellyfinApiClient,
ILogger<SynchronizeJellyfinLibrariesHandler> logger)
ILogger<SynchronizeJellyfinLibrariesHandler> logger,
ISearchIndex searchIndex)
{
_mediaSourceRepository = mediaSourceRepository;
_jellyfinSecretStore = jellyfinSecretStore;
_jellyfinApiClient = jellyfinApiClient;
_logger = logger;
_searchIndex = searchIndex;
}
public Task<Either<BaseError, Unit>> Handle(
@ -77,16 +81,21 @@ namespace ErsatzTV.Application.Jellyfin.Commands @@ -77,16 +81,21 @@ namespace ErsatzTV.Application.Jellyfin.Commands
connectionParameters.ApiKey);
await maybeLibraries.Match(
libraries =>
async libraries =>
{
var existing = connectionParameters.JellyfinMediaSource.Libraries.OfType<JellyfinLibrary>()
.ToList();
var toAdd = libraries.Filter(library => existing.All(l => l.ItemId != library.ItemId)).ToList();
var toRemove = existing.Filter(library => libraries.All(l => l.ItemId != library.ItemId)).ToList();
return _mediaSourceRepository.UpdateLibraries(
List<int> ids = await _mediaSourceRepository.UpdateLibraries(
connectionParameters.JellyfinMediaSource.Id,
toAdd,
toRemove);
if (ids.Any())
{
await _searchIndex.RemoveItems(ids);
_searchIndex.Commit();
}
},
error =>
{

15
ErsatzTV.Application/Plex/Commands/SynchronizePlexLibrariesHandler.cs

@ -6,6 +6,7 @@ using ErsatzTV.Core; @@ -6,6 +6,7 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Core.Plex;
using LanguageExt;
using Microsoft.Extensions.Logging;
@ -19,17 +20,20 @@ namespace ErsatzTV.Application.Plex.Commands @@ -19,17 +20,20 @@ namespace ErsatzTV.Application.Plex.Commands
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IPlexSecretStore _plexSecretStore;
private readonly IPlexServerApiClient _plexServerApiClient;
private readonly ISearchIndex _searchIndex;
public SynchronizePlexLibrariesHandler(
IMediaSourceRepository mediaSourceRepository,
IPlexSecretStore plexSecretStore,
IPlexServerApiClient plexServerApiClient,
ILogger<SynchronizePlexLibrariesHandler> logger)
ILogger<SynchronizePlexLibrariesHandler> logger,
ISearchIndex searchIndex)
{
_mediaSourceRepository = mediaSourceRepository;
_plexSecretStore = plexSecretStore;
_plexServerApiClient = plexServerApiClient;
_logger = logger;
_searchIndex = searchIndex;
}
public Task<Either<BaseError, Unit>> Handle(
@ -73,15 +77,20 @@ namespace ErsatzTV.Application.Plex.Commands @@ -73,15 +77,20 @@ namespace ErsatzTV.Application.Plex.Commands
connectionParameters.PlexServerAuthToken);
await maybeLibraries.Match(
libraries =>
async libraries =>
{
var existing = connectionParameters.PlexMediaSource.Libraries.OfType<PlexLibrary>().ToList();
var toAdd = libraries.Filter(library => existing.All(l => l.Key != library.Key)).ToList();
var toRemove = existing.Filter(library => libraries.All(l => l.Key != library.Key)).ToList();
return _mediaSourceRepository.UpdateLibraries(
List<int> ids = await _mediaSourceRepository.UpdateLibraries(
connectionParameters.PlexMediaSource.Id,
toAdd,
toRemove);
if (ids.Any())
{
await _searchIndex.RemoveItems(ids);
_searchIndex.Commit();
}
},
error =>
{

1
ErsatzTV.Core/Interfaces/Locking/IEntityLocker.cs

@ -13,6 +13,7 @@ namespace ErsatzTV.Core.Interfaces.Locking @@ -13,6 +13,7 @@ namespace ErsatzTV.Core.Interfaces.Locking
bool LockPlex();
bool UnlockPlex();
bool IsPlexLocked();
bool IsRemoteMediaSourceLocked<TMediaSource>();
bool LockRemoteMediaSource<TMediaSource>();
bool UnlockRemoteMediaSource<TMediaSource>();
}

6
ErsatzTV.Core/Interfaces/Repositories/IMediaSourceRepository.cs

@ -27,17 +27,17 @@ namespace ErsatzTV.Core.Interfaces.Repositories @@ -27,17 +27,17 @@ namespace ErsatzTV.Core.Interfaces.Repositories
List<PlexConnection> toAdd,
List<PlexConnection> toDelete);
Task<Unit> UpdateLibraries(
Task<List<int>> UpdateLibraries(
int plexMediaSourceId,
List<PlexLibrary> toAdd,
List<PlexLibrary> toDelete);
Task<Unit> UpdateLibraries(
Task<List<int>> UpdateLibraries(
int jellyfinMediaSourceId,
List<JellyfinLibrary> toAdd,
List<JellyfinLibrary> toDelete);
Task<Unit> UpdateLibraries(
Task<List<int>> UpdateLibraries(
int embyMediaSourceId,
List<EmbyLibrary> toAdd,
List<EmbyLibrary> toDelete);

18
ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs

@ -206,7 +206,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -206,7 +206,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
}
}
public async Task<Unit> UpdateLibraries(
public async Task<List<int>> UpdateLibraries(
int plexMediaSourceId,
List<PlexLibrary> toAdd,
List<PlexLibrary> toDelete)
@ -228,12 +228,14 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -228,12 +228,14 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
dbContext.Entry(delete).State = EntityState.Deleted;
}
List<int> ids = await DisablePlexLibrarySync(toDelete.Map(l => l.Id).ToList());
await dbContext.SaveChangesAsync();
return Unit.Default;
return ids;
}
public async Task<Unit> UpdateLibraries(
public async Task<List<int>> UpdateLibraries(
int jellyfinMediaSourceId,
List<JellyfinLibrary> toAdd,
List<JellyfinLibrary> toDelete)
@ -255,12 +257,14 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -255,12 +257,14 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
dbContext.Entry(delete).State = EntityState.Deleted;
}
List<int> ids = await DisableJellyfinLibrarySync(toDelete.Map(l => l.Id).ToList());
await dbContext.SaveChangesAsync();
return Unit.Default;
return ids;
}
public async Task<Unit> UpdateLibraries(
public async Task<List<int>> UpdateLibraries(
int embyMediaSourceId,
List<EmbyLibrary> toAdd,
List<EmbyLibrary> toDelete)
@ -282,9 +286,11 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -282,9 +286,11 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
dbContext.Entry(delete).State = EntityState.Deleted;
}
List<int> ids = await DisableEmbyLibrarySync(toDelete.Map(l => l.Id).ToList());
await dbContext.SaveChangesAsync();
return Unit.Default;
return ids;
}
public async Task<Unit> UpdatePathReplacements(

3
ErsatzTV.Infrastructure/Locking/EntityLocker.cs

@ -71,6 +71,9 @@ namespace ErsatzTV.Infrastructure.Locking @@ -71,6 +71,9 @@ namespace ErsatzTV.Infrastructure.Locking
public bool IsPlexLocked() => _plex;
public bool IsRemoteMediaSourceLocked<TMediaSource>() =>
_lockedRemoteMediaSourceTypes.ContainsKey(typeof(TMediaSource));
public bool LockRemoteMediaSource<TMediaSource>()
{
Type mediaSourceType = typeof(TMediaSource);

13
ErsatzTV/Pages/EmbyMediaSources.razor

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
@page "/media/emby"
@using ErsatzTV.Core.Interfaces.Emby
@using ErsatzTV.Application.Emby.Queries
@using ErsatzTV.Application.Emby.Commands
@using ErsatzTV.Application.Emby.Queries
@inject IEmbySecretStore _embySecretStore
@inject ChannelWriter<IEmbyBackgroundServiceRequest> _channel
<RemoteMediaSources
TViewModel="ErsatzTV.Application.Emby.EmbyMediaSourceViewModel"
@ -11,4 +12,12 @@ @@ -11,4 +12,12 @@
Name="Emby"
GetAllMediaSourcesCommand="@(new GetAllEmbyMediaSources())"
DisconnectCommand="@(new DisconnectEmby())"
SecretStore="@_embySecretStore"/>
RefreshLibrariesCommand="@(mediaSourceId => RefreshLibraries(mediaSourceId))"
SecretStore="@_embySecretStore"/>
@code {
private async Task RefreshLibraries(int mediaSourceId) =>
await _channel.WriteAsync(new SynchronizeEmbyLibraries(mediaSourceId));
}

13
ErsatzTV/Pages/JellyfinMediaSources.razor

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
@page "/media/jellyfin"
@using ErsatzTV.Core.Interfaces.Jellyfin
@using ErsatzTV.Application.Jellyfin.Queries
@using ErsatzTV.Application.Jellyfin.Commands
@using ErsatzTV.Application.Jellyfin.Queries
@inject IJellyfinSecretStore _jellyfinSecretStore
@inject ChannelWriter<IJellyfinBackgroundServiceRequest> _channel
<RemoteMediaSources
TViewModel="ErsatzTV.Application.Jellyfin.JellyfinMediaSourceViewModel"
@ -11,4 +12,12 @@ @@ -11,4 +12,12 @@
Name="Jellyfin"
GetAllMediaSourcesCommand="@(new GetAllJellyfinMediaSources())"
DisconnectCommand="@(new DisconnectJellyfin())"
SecretStore="@_jellyfinSecretStore"/>
RefreshLibrariesCommand="@(mediaSourceId => RefreshLibraries(mediaSourceId))"
SecretStore="@_jellyfinSecretStore"/>
@code {
private async Task RefreshLibraries(int mediaSourceId) =>
await _channel.WriteAsync(new SynchronizeJellyfinLibraries(mediaSourceId));
}

9
ErsatzTV/Pages/PlexMediaSources.razor

@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
@inject ILogger<PlexMediaSources> _logger
@inject IJSRuntime _jsRuntime
@inject IPlexSecretStore _plexSecretStore
@inject ChannelWriter<IPlexBackgroundServiceRequest> _channel
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudTable Hover="true" Dense="true" Items="_mediaSources">
@ -32,6 +33,12 @@ @@ -32,6 +33,12 @@
<MudTd DataLabel="Address">@context.Address</MudTd>
<MudTd>
<div style="align-items: center; display: flex;">
<MudTooltip Text="Refresh Libraries">
<MudIconButton Icon="@Icons.Material.Filled.Refresh"
Disabled="@(_locker.IsPlexLocked())"
OnClick="@(_ => RefreshLibraries(context.Id))">
</MudIconButton>
</MudTooltip>
<MudTooltip Text="Edit Libraries">
<MudIconButton Icon="@Icons.Material.Filled.VideoLibrary"
Link="@($"/media/sources/plex/{context.Id}/libraries")">
@ -134,6 +141,8 @@ @@ -134,6 +141,8 @@
await InvokeAsync(StateHasChanged);
}
private async Task RefreshLibraries(int mediaSourceId) => await _channel.WriteAsync(new SynchronizePlexLibraries(mediaSourceId));
void IDisposable.Dispose() => _locker.OnPlexChanged -= PlexChanged;
}

11
ErsatzTV/Shared/RemoteMediaSources.razor

@ -27,6 +27,12 @@ @@ -27,6 +27,12 @@
<MudTd DataLabel="Address">@context.Address</MudTd>
<MudTd>
<div style="align-items: center; display: flex;">
<MudTooltip Text="Refresh Libraries">
<MudIconButton Icon="@Icons.Material.Filled.Refresh"
Disabled="@(_locker.IsRemoteMediaSourceLocked<TMediaSource>())"
OnClick="@(_ => RefreshLibraries(context.Id))">
</MudIconButton>
</MudTooltip>
<MudTooltip Text="Edit Libraries">
<MudIconButton Icon="@Icons.Material.Filled.VideoLibrary"
Link="@($"/media/sources/{Name.ToLowerInvariant()}/{context.Id}/libraries")">
@ -83,6 +89,9 @@ @@ -83,6 +89,9 @@
[Parameter]
public IRequest<Either<BaseError, Unit>> DisconnectCommand { get; set; }
[Parameter]
public Func<int, Task> RefreshLibrariesCommand { get; set; }
[Parameter]
public IRemoteMediaSourceSecretStore<TSecrets> SecretStore { get; set; }
@ -115,4 +124,6 @@ @@ -115,4 +124,6 @@
}
}
private async Task RefreshLibraries(int mediaSourceId) => await RefreshLibrariesCommand(mediaSourceId);
}
Loading…
Cancel
Save