@page "/media/libraries" @using MediatR.Courier @using ErsatzTV.Application.Libraries @using ErsatzTV.Application.MediaSources @using ErsatzTV.Application.Plex @using ErsatzTV.Core.Metadata @using PlexLibraryViewModel = ErsatzTV.Application.Libraries.PlexLibraryViewModel @using ErsatzTV.Application.Jellyfin @using ErsatzTV.Application.Emby @implements IDisposable @inject IMediator _mediator @inject IEntityLocker _locker @inject ChannelWriter _scannerWorkerChannel; @inject ICourier _courier Libraries Library Kind Name Media Kind @context.LibraryKind @context.Name @context.MediaKind
@if (_locker.IsLibraryLocked(context.Id)) {
@if (_progressByLibrary[context.Id] > 0) { @($"{_progressByLibrary[context.Id]} %") }
} else { if (context is PlexLibraryViewModel or EmbyLibraryViewModel or JellyfinLibraryViewModel) { } else {
} }
@if (_externalCollections.Any()) { External Collections Library Kind @context.LibraryKind
@if (AreCollectionsLocked(context.LibraryKind)) {
} else {
}
} @code { private readonly CancellationTokenSource _cts = new(); private IList _libraries; private IList _externalCollections; private Dictionary _progressByLibrary; protected override void OnInitialized() { _locker.OnLibraryChanged += LockChanged; _locker.OnEmbyCollectionsChanged += LockChanged; _courier.Subscribe(HandleScanProgress); } protected override async Task OnParametersSetAsync() => await LoadLibraries(_cts.Token); private async Task LoadLibraries(CancellationToken cancellationToken) { _libraries = await _mediator.Send(new GetConfiguredLibraries(), cancellationToken); _externalCollections = await _mediator.Send(new GetExternalCollections(), cancellationToken); _progressByLibrary = _libraries.ToDictionary(vm => vm.Id, _ => 0); } private async Task ScanLibrary(LibraryViewModel library, bool deepScan = false) { if (_locker.LockLibrary(library.Id)) { switch (library) { case LocalLibraryViewModel: await _scannerWorkerChannel.WriteAsync(new ForceScanLocalLibrary(library.Id), _cts.Token); break; case PlexLibraryViewModel: await _scannerWorkerChannel.WriteAsync(new ForceSynchronizePlexLibraryById(library.Id, deepScan), _cts.Token); break; case JellyfinLibraryViewModel: await _scannerWorkerChannel.WriteAsync(new SynchronizeJellyfinLibraries(library.MediaSourceId), _cts.Token); await _scannerWorkerChannel.WriteAsync(new ForceSynchronizeJellyfinLibraryById(library.Id, deepScan), _cts.Token); break; case EmbyLibraryViewModel: await _scannerWorkerChannel.WriteAsync(new SynchronizeEmbyLibraries(library.MediaSourceId), _cts.Token); await _scannerWorkerChannel.WriteAsync(new ForceSynchronizeEmbyLibraryById(library.Id, deepScan), _cts.Token); break; } StateHasChanged(); } } private async Task ScanExternalCollections(LibraryViewModel library) { switch (library.LibraryKind.ToLowerInvariant()) { case "emby": if (_locker.LockEmbyCollections()) { await _scannerWorkerChannel.WriteAsync(new SynchronizeEmbyCollections(library.MediaSourceId, true)); } break; } } private void LockChanged(object sender, EventArgs e) => InvokeAsync(StateHasChanged); private bool AreCollectionsLocked(string libraryKind) { switch (libraryKind.ToLowerInvariant()) { case "emby": return _locker.AreEmbyCollectionsLocked(); } return false; } private async Task HandleScanProgress(LibraryScanProgress libraryScanProgress, CancellationToken cancellationToken) { try { if (_progressByLibrary != null && _progressByLibrary.ContainsKey(libraryScanProgress.LibraryId)) { _progressByLibrary[libraryScanProgress.LibraryId] = (int)(libraryScanProgress.Progress * 100); await InvokeAsync(StateHasChanged); } } catch (Exception) { // ignore } } void IDisposable.Dispose() { _locker.OnLibraryChanged -= LockChanged; _locker.OnEmbyCollectionsChanged -= LockChanged; _courier.UnSubscribe(HandleScanProgress); _cts.Cancel(); _cts.Dispose(); } }