use cancellation tokens in ui (#666)

* use cancellation tokens in pages

* use cancellation token in shared ui

* use cancellation tokens in artwork controller
This commit is contained in:
Jason Dove
2022-03-01 21:31:48 -06:00
committed by GitHub
parent 9e2f445785
commit 452f361384
66 changed files with 762 additions and 306 deletions
+14 -5
View File
@@ -8,8 +8,10 @@
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands
@using System.Globalization
@using System.Threading
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit
@implements IDisposable
@inject IMediator _mediator
@inject IDialogService _dialog
@inject NavigationManager _navigationManager
@@ -185,6 +187,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int ArtistId { get; set; }
@@ -195,12 +198,18 @@
private List<string> _sortedStyles = new();
private List<string> _sortedMoods = new();
private MusicVideoCardResultsViewModel _musicVideos;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override Task OnParametersSetAsync() => RefreshData();
private async Task RefreshData()
{
await _mediator.Send(new GetArtistById(ArtistId)).IfSomeAsync(vm =>
await _mediator.Send(new GetArtistById(ArtistId), _cts.Token).IfSomeAsync(vm =>
{
_artist = vm;
_sortedLanguages = _artist.Languages.OrderBy(ci => ci.EnglishName).ToList();
@@ -209,7 +218,7 @@
_sortedMoods = _artist.Moods.OrderBy(m => m).ToList();
});
_musicVideos = await _mediator.Send(new GetMusicVideoCards(ArtistId, 1, 100));
_musicVideos = await _mediator.Send(new GetMusicVideoCards(ArtistId, 1, 100), _cts.Token);
}
private async Task AddToCollection()
@@ -221,7 +230,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
await _mediator.Send(new AddArtistToCollection(collection.Id, ArtistId));
await _mediator.Send(new AddArtistToCollection(collection.Id, ArtistId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}");
}
}
@@ -235,7 +244,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule)
{
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.Artist, null, null, null, ArtistId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null));
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.Artist, null, null, null, ArtistId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null), _cts.Token);
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
}
}
@@ -250,7 +259,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddMusicVideoToCollection(collection.Id, musicVideo.MusicVideoId);
Either<BaseError, Unit> addResult = await _mediator.Send(request);
Either<BaseError, Unit> addResult = await _mediator.Send(request, _cts.Token);
addResult.Match(
Left: error =>
{
+2 -2
View File
@@ -97,7 +97,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:artist" : $"type:artist AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexArtists(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexArtists(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -144,7 +144,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddArtistToCollection(collection.Id, artist.ArtistId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+25 -16
View File
@@ -6,6 +6,7 @@
@using ErsatzTV.Application.Images.Commands
@using ErsatzTV.Application.MediaItems.Queries
@using System.Globalization
@using System.Threading
@using ErsatzTV.Application.Channels
@using ErsatzTV.Application.Channels.Queries
@using ErsatzTV.Application.Filler
@@ -13,6 +14,7 @@
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Application.Watermarks.Queries
@using ErsatzTV.Core.Domain.Filler
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ChannelEditor> _logger
@inject ISnackbar _snackbar
@@ -107,6 +109,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int? Id { get; set; }
@@ -119,17 +122,23 @@
private List<CultureInfo> _availableCultures;
private List<WatermarkViewModel> _watermarks;
private List<FillerPresetViewModel> _fillerPresets;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
await LoadFFmpegProfiles();
_availableCultures = await _mediator.Send(new GetAllLanguageCodes());
await LoadWatermarks();
await LoadFillerPresets();
await LoadFFmpegProfiles(_cts.Token);
_availableCultures = await _mediator.Send(new GetAllLanguageCodes(), _cts.Token);
await LoadWatermarks(_cts.Token);
await LoadFillerPresets(_cts.Token);
if (Id.HasValue)
{
Option<ChannelViewModel> maybeChannel = await _mediator.Send(new GetChannelById(Id.Value));
Option<ChannelViewModel> maybeChannel = await _mediator.Send(new GetChannelById(Id.Value), _cts.Token);
maybeChannel.Match(
channelViewModel =>
{
@@ -149,10 +158,10 @@
}
else
{
FFmpegSettingsViewModel ffmpegSettings = await _mediator.Send(new GetFFmpegSettings());
FFmpegSettingsViewModel ffmpegSettings = await _mediator.Send(new GetFFmpegSettings(), _cts.Token);
// TODO: command for new channel
IEnumerable<int> channelNumbers = await _mediator.Send(new GetAllChannels())
IEnumerable<int> channelNumbers = await _mediator.Send(new GetAllChannels(), _cts.Token)
.Map(list => list.Map(c => int.TryParse(c.Number.Split(".").Head(), out int result) ? result : 0));
int maxNumber = Optional(channelNumbers).Flatten().DefaultIfEmpty(0).Max();
_model.Number = (maxNumber + 1).ToString();
@@ -171,14 +180,14 @@
private bool IsEdit => Id.HasValue;
private async Task LoadFFmpegProfiles() =>
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles());
private async Task LoadFFmpegProfiles(CancellationToken cancellationToken) =>
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles(), cancellationToken);
private async Task LoadWatermarks() =>
_watermarks = await _mediator.Send(new GetAllWatermarks());
private async Task LoadWatermarks(CancellationToken cancellationToken) =>
_watermarks = await _mediator.Send(new GetAllWatermarks(), cancellationToken);
private async Task LoadFillerPresets() =>
_fillerPresets = await _mediator.Send(new GetAllFillerPresets())
private async Task LoadFillerPresets(CancellationToken cancellationToken) =>
_fillerPresets = await _mediator.Send(new GetAllFillerPresets(), cancellationToken)
.Map(list => list.Filter(vm => vm.FillerKind == FillerKind.Fallback).ToList());
private async Task HandleSubmitAsync()
@@ -187,8 +196,8 @@
if (_editContext.Validate())
{
Seq<BaseError> errorMessage = IsEdit ?
(await _mediator.Send(_model.ToUpdate())).LeftToSeq() :
(await _mediator.Send(_model.ToCreate())).LeftToSeq();
(await _mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() :
(await _mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq();
errorMessage.HeadOrNone().Match(
error =>
@@ -205,7 +214,7 @@
try
{
Either<BaseError, string> maybeCacheFileName =
await _mediator.Send(new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Logo));
await _mediator.Send(new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Logo), _cts.Token);
maybeCacheFileName.Match(
relativeFileName =>
{
+15 -5
View File
@@ -7,6 +7,8 @@
@using ErsatzTV.Application.FFmpegProfiles
@using ErsatzTV.Application.FFmpegProfiles.Queries
@using System.Globalization
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -82,15 +84,23 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<ChannelViewModel> _table;
private List<FFmpegProfileViewModel> _ffmpegProfiles;
private int _rowsPerPage;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles());
_rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.ChannelsPageSize))
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles(), _cts.Token);
_rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.ChannelsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
}
@@ -103,16 +113,16 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteChannel(channel.Id));
await _mediator.Send(new DeleteChannel(channel.Id), _cts.Token);
await _table.ReloadServerData();
}
}
private async Task<TableData<ChannelViewModel>> ServerReload(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.ChannelsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.ChannelsPageSize, state.PageSize.ToString()), _cts.Token);
List<ChannelViewModel> channels = await _mediator.Send(new GetAllChannels());
List<ChannelViewModel> channels = await _mediator.Send(new GetAllChannels(), _cts.Token);
IOrderedEnumerable<ChannelViewModel> sorted = channels.OrderBy(c => decimal.Parse(c.Number));
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
+13 -4
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.MediaCollections.Queries
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<CollectionEditor> _logger
@inject ISnackbar _snackbar
@@ -29,19 +31,26 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
private readonly CollectionEditViewModel _model = new();
private EditContext _editContext;
private ValidationMessageStore _messageStore;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
if (IsEdit)
{
Option<MediaCollectionViewModel> maybeCollection = await _mediator.Send(new GetCollectionById(Id));
Option<MediaCollectionViewModel> maybeCollection = await _mediator.Send(new GetCollectionById(Id), _cts.Token);
maybeCollection.IfSome(collection =>
{
_model.Id = collection.Id;
@@ -68,8 +77,8 @@
if (_editContext.Validate())
{
Seq<BaseError> errorMessage = IsEdit ?
(await _mediator.Send(new UpdateCollection(Id, _model.Name))).LeftToSeq() :
(await _mediator.Send(new CreateCollection(_model.Name))).LeftToSeq();
(await _mediator.Send(new UpdateCollection(Id, _model.Name), _cts.Token)).LeftToSeq() :
(await _mediator.Send(new CreateCollection(_model.Name), _cts.Token)).LeftToSeq();
errorMessage.HeadOrNone().Match(
error =>
+3 -3
View File
@@ -294,7 +294,7 @@
protected override async Task RefreshData()
{
Either<BaseError, CollectionCardResultsViewModel> maybeResult =
await Mediator.Send(new GetCollectionCards(Id));
await Mediator.Send(new GetCollectionCards(Id), CancellationToken);
maybeResult.Match(
result => _data = result,
@@ -459,7 +459,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await Mediator.Send(request);
await Mediator.Send(request, CancellationToken);
await RefreshData();
}
}
@@ -468,7 +468,7 @@
{
_data.UseCustomPlaybackOrder = !_data.UseCustomPlaybackOrder;
var request = new UpdateCollection(Id, _data.Name) { UseCustomPlaybackOrder = _data.UseCustomPlaybackOrder };
await Mediator.Send(request);
await Mediator.Send(request, CancellationToken);
}
}
+22 -12
View File
@@ -5,6 +5,8 @@
@using ErsatzTV.Application.Configuration.Queries
@using ErsatzTV.Application.Configuration.Commands
@using ErsatzTV.Extensions
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -134,6 +136,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<MediaCollectionViewModel> _collectionsTable;
private MudTable<MultiCollectionViewModel> _multiCollectionsTable;
private MudTable<SmartCollectionViewModel> _smartCollectionsTable;
@@ -141,16 +145,22 @@
private int _collectionsRowsPerPage;
private int _multiCollectionsRowsPerPage;
private int _smartCollectionsRowsPerPage;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_collectionsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.CollectionsPageSize))
_collectionsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.CollectionsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
_multiCollectionsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.MultiCollectionsPageSize))
_multiCollectionsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.MultiCollectionsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
_smartCollectionsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.SmartCollectionsPageSize))
_smartCollectionsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.SmartCollectionsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
}
@@ -163,7 +173,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteCollection(collection.Id));
await _mediator.Send(new DeleteCollection(collection.Id), _cts.Token);
await _collectionsTable.ReloadServerData();
}
}
@@ -177,7 +187,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteMultiCollection(collection.Id));
await _mediator.Send(new DeleteMultiCollection(collection.Id), _cts.Token);
await _multiCollectionsTable.ReloadServerData();
}
}
@@ -191,32 +201,32 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteSmartCollection(collection.Id));
await _mediator.Send(new DeleteSmartCollection(collection.Id), _cts.Token);
await _smartCollectionsTable.ReloadServerData();
}
}
private async Task<TableData<MediaCollectionViewModel>> ServerReloadCollections(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.CollectionsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.CollectionsPageSize, state.PageSize.ToString()), _cts.Token);
PagedMediaCollectionsViewModel data = await _mediator.Send(new GetPagedCollections(state.Page, state.PageSize));
PagedMediaCollectionsViewModel data = await _mediator.Send(new GetPagedCollections(state.Page, state.PageSize), _cts.Token);
return new TableData<MediaCollectionViewModel> { TotalItems = data.TotalCount, Items = data.Page };
}
private async Task<TableData<MultiCollectionViewModel>> ServerReloadMultiCollections(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.MultiCollectionsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.MultiCollectionsPageSize, state.PageSize.ToString()), _cts.Token);
PagedMultiCollectionsViewModel data = await _mediator.Send(new GetPagedMultiCollections(state.Page, state.PageSize));
PagedMultiCollectionsViewModel data = await _mediator.Send(new GetPagedMultiCollections(state.Page, state.PageSize), _cts.Token);
return new TableData<MultiCollectionViewModel> { TotalItems = data.TotalCount, Items = data.Page };
}
private async Task<TableData<SmartCollectionViewModel>> ServerReloadSmartCollections(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.SmartCollectionsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.SmartCollectionsPageSize, state.PageSize.ToString()), _cts.Token);
PagedSmartCollectionsViewModel data = await _mediator.Send(new GetPagedSmartCollections(state.Page, state.PageSize));
PagedSmartCollectionsViewModel data = await _mediator.Send(new GetPagedSmartCollections(state.Page, state.PageSize), _cts.Token);
return new TableData<SmartCollectionViewModel> { TotalItems = data.TotalCount, Items = data.Page };
}
+10 -1
View File
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Emby.Queries
@using ErsatzTV.Application.MediaSources
@using ErsatzTV.Application.Emby
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject ChannelWriter<IEmbyBackgroundServiceRequest> _channel
@@ -16,10 +18,17 @@
SynchronizeLibraryByIdIfNeeded="SynchronizeLibraryByIdIfNeeded"/>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private IRequest<Either<BaseError, Unit>> GetUpdateLibraryRequest(List<RemoteMediaSourceLibraryEditViewModel> libraries) =>
new UpdateEmbyLibraryPreferences(
libraries.Map(l => new EmbyLibraryPreference(l.Id, l.ShouldSyncItems)).ToList());
@@ -42,7 +51,7 @@
private async Task<Unit> SynchronizeLibraryByIdIfNeeded(int libraryId)
{
await _channel.WriteAsync(new SynchronizeEmbyLibraryByIdIfNeeded(libraryId));
await _channel.WriteAsync(new SynchronizeEmbyLibraryByIdIfNeeded(libraryId), _cts.Token);
return Unit.Default;
}
+11 -2
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Core.Emby
@using ErsatzTV.Application.Emby.Queries
@using ErsatzTV.Application.Emby.Commands
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject NavigationManager _navigationManager
@inject ISnackbar _snackbar
@@ -14,10 +16,17 @@
SaveSecrets="SaveSecrets"/>
@code {
private readonly CancellationTokenSource _cts = new();
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private async Task<Unit> LoadSecrets(RemoteMediaSourceEditViewModel viewModel)
{
EmbySecrets secrets = await _mediator.Send(new GetEmbySecrets());
EmbySecrets secrets = await _mediator.Send(new GetEmbySecrets(), _cts.Token);
viewModel.Address = secrets.Address;
viewModel.ApiKey = secrets.ApiKey;
return Unit.Default;
@@ -26,7 +35,7 @@
private async Task<Either<BaseError, Unit>> SaveSecrets(RemoteMediaSourceEditViewModel viewModel)
{
var secrets = new EmbySecrets { Address = viewModel.Address, ApiKey = viewModel.ApiKey };
return await _mediator.Send(new SaveEmbySecrets(secrets));
return await _mediator.Send(new SaveEmbySecrets(secrets), _cts.Token);
}
}
+10 -1
View File
@@ -2,6 +2,8 @@
@using ErsatzTV.Core.Interfaces.Emby
@using ErsatzTV.Application.Emby.Commands
@using ErsatzTV.Application.Emby.Queries
@using System.Threading
@implements IDisposable
@inject IEmbySecretStore _embySecretStore
@inject ChannelWriter<IEmbyBackgroundServiceRequest> _channel
@@ -16,8 +18,15 @@
SecretStore="@_embySecretStore"/>
@code {
private readonly CancellationTokenSource _cts = new();
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private async Task RefreshLibraries(int mediaSourceId) =>
await _channel.WriteAsync(new SynchronizeEmbyLibraries(mediaSourceId));
await _channel.WriteAsync(new SynchronizeEmbyLibraries(mediaSourceId), _cts.Token);
}
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Emby
@using ErsatzTV.Application.Emby.Commands
@using Unit = LanguageExt.Unit
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ScheduleItemsEditor> _logger
@inject ISnackbar _snackbar
@@ -17,16 +19,23 @@
GetPathReplacementsBySourceId="GetPathReplacementsBySourceId"/>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int id) =>
_mediator.Send(new GetEmbyMediaSourceById(Id))
_mediator.Send(new GetEmbyMediaSourceById(Id), _cts.Token)
.MapT(vm => new RemoteMediaSourceViewModel(vm.Id, vm.Name, vm.Address));
private Task<List<RemoteMediaSourcePathReplacementEditViewModel>> GetPathReplacementsBySourceId(int mediaSourceId) =>
_mediator.Send(new GetEmbyPathReplacementsBySourceId(Id))
_mediator.Send(new GetEmbyPathReplacementsBySourceId(Id), _cts.Token)
.Map(list => list.Map(ProjectToEditViewModel).ToList());
private RemoteMediaSourcePathReplacementEditViewModel ProjectToEditViewModel(EmbyPathReplacementViewModel item) =>
+2 -2
View File
@@ -97,7 +97,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:episode" : $"type:episode AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexEpisodes(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexEpisodes(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -144,7 +144,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddEpisodeToCollection(collection.Id, episode.EpisodeId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+15 -5
View File
@@ -2,6 +2,8 @@
@using ErsatzTV.Application.FFmpegProfiles
@using ErsatzTV.Application.FFmpegProfiles.Commands
@using ErsatzTV.Application.FFmpegProfiles.Queries
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@inject ILogger<FFmpeg> _logger
@@ -78,12 +80,20 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private List<FFmpegProfileViewModel> _ffmpegProfiles;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync() => await LoadFFmpegProfilesAsync();
protected override async Task OnParametersSetAsync() => await LoadFFmpegProfilesAsync(_cts.Token);
private async Task LoadFFmpegProfilesAsync() =>
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles());
private async Task LoadFFmpegProfilesAsync(CancellationToken cancellationToken) =>
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles(), cancellationToken);
private async Task DeleteProfileAsync(FFmpegProfileViewModel ffmpegProfile)
{
@@ -94,8 +104,8 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteFFmpegProfile(ffmpegProfile.Id));
await LoadFFmpegProfilesAsync();
await _mediator.Send(new DeleteFFmpegProfile(ffmpegProfile.Id), _cts.Token);
await LoadFFmpegProfilesAsync(_cts.Token);
}
}
+14 -5
View File
@@ -8,6 +8,8 @@
@using ErsatzTV.Core.FFmpeg
@using Microsoft.AspNetCore.Components
@using Microsoft.Extensions.Caching.Memory
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<FFmpegEditor> _logger
@inject ISnackbar _snackbar
@@ -121,6 +123,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -132,20 +135,26 @@
private List<ResolutionViewModel> _resolutions;
private List<string> _vaapiDevices;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_resolutions = await _mediator.Send(new GetAllResolutions());
_resolutions = await _mediator.Send(new GetAllResolutions(), _cts.Token);
if (IsEdit)
{
Option<FFmpegProfileViewModel> profile = await _mediator.Send(new GetFFmpegProfileById(Id));
Option<FFmpegProfileViewModel> profile = await _mediator.Send(new GetFFmpegProfileById(Id), _cts.Token);
profile.Match(
ffmpegProfileViewModel => _model = new FFmpegProfileEditViewModel(ffmpegProfileViewModel),
() => _navigationManager.NavigateTo("404"));
}
else
{
_model = new FFmpegProfileEditViewModel(await _mediator.Send(new NewFFmpegProfile()));
_model = new FFmpegProfileEditViewModel(await _mediator.Send(new NewFFmpegProfile(), _cts.Token));
}
_editContext = new EditContext(_model);
@@ -167,8 +176,8 @@
if (_editContext.Validate())
{
Seq<BaseError> errorMessage = IsEdit ?
(await _mediator.Send(_model.ToUpdate())).LeftToSeq() :
(await _mediator.Send(_model.ToCreate())).LeftToSeq();
(await _mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() :
(await _mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq();
errorMessage.HeadOrNone().Match(
error =>
+18 -8
View File
@@ -9,6 +9,8 @@
@using ErsatzTV.Application.MediaItems
@using ErsatzTV.Core.Domain.Filler
@using Microsoft.AspNetCore.Components
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<FillerPresetEditor> _logger
@inject ISnackbar _snackbar
@@ -134,6 +136,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -148,24 +152,30 @@
private List<NamedMediaItemViewModel> _televisionSeasons;
private List<NamedMediaItemViewModel> _artists;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_mediaCollections = await _mediator.Send(new GetAllCollections())
_mediaCollections = await _mediator.Send(new GetAllCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_multiCollections = await _mediator.Send(new GetAllMultiCollections())
_multiCollections = await _mediator.Send(new GetAllMultiCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_smartCollections = await _mediator.Send(new GetAllSmartCollections())
_smartCollections = await _mediator.Send(new GetAllSmartCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_televisionShows = await _mediator.Send(new GetAllTelevisionShows())
_televisionShows = await _mediator.Send(new GetAllTelevisionShows(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_televisionSeasons = await _mediator.Send(new GetAllTelevisionSeasons())
_televisionSeasons = await _mediator.Send(new GetAllTelevisionSeasons(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_artists = await _mediator.Send(new GetAllArtists())
_artists = await _mediator.Send(new GetAllArtists(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
if (IsEdit)
{
Option<FillerPresetViewModel> maybeFillerPreset = await _mediator.Send(new GetFillerPresetById(Id));
Option<FillerPresetViewModel> maybeFillerPreset = await _mediator.Send(new GetFillerPresetById(Id), _cts.Token);
maybeFillerPreset.IfSome(fillerPreset =>
{
_model.Id = fillerPreset.Id;
@@ -212,7 +222,7 @@
{
IRequest<Either<BaseError, LanguageExt.Unit>> request = IsEdit ? _model.ToEdit() : _model.ToUpdate();
Seq<BaseError> errorMessage = await _mediator.Send(request)
Seq<BaseError> errorMessage = await _mediator.Send(request, _cts.Token)
.Map(result => result.LeftToSeq());
errorMessage.HeadOrNone().Match(
+15 -4
View File
@@ -5,6 +5,8 @@
@using ErsatzTV.Application.Filler.Commands
@using ErsatzTV.Application.Filler.Queries
@using ErsatzTV.Core.Domain.Filler
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -69,13 +71,21 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<FillerPresetViewModel> _fillerPresetsTable;
private int _fillerPresetsRowsPerPage;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_fillerPresetsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.FillerPresetsPageSize))
_fillerPresetsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.FillerPresetsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
}
@@ -88,16 +98,17 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteFillerPreset(fillerPreset.Id));
await _mediator.Send(new DeleteFillerPreset(fillerPreset.Id), _cts.Token);
await _fillerPresetsTable.ReloadServerData();
}
}
private async Task<TableData<FillerPresetViewModel>> ServerReloadFillerPresets(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.FillerPresetsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.FillerPresetsPageSize, state.PageSize.ToString()), _cts.Token);
PagedFillerPresetsViewModel data = await _mediator.Send(new GetPagedFillerPresets(state.Page, state.PageSize));
PagedFillerPresetsViewModel data = await _mediator.Send(new GetPagedFillerPresets(state.Page, state.PageSize), _cts.Token);
return new TableData<FillerPresetViewModel> { TotalItems = data.TotalCount, Items = data.Page };
}
}
+12 -1
View File
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Extensions;
using Microsoft.AspNetCore.Components;
@@ -10,13 +11,23 @@ namespace ErsatzTV.Pages
{
public class FragmentNavigationBase : ComponentBase, IDisposable
{
private readonly CancellationTokenSource _cts = new();
protected CancellationToken CancellationToken => _cts.Token;
[Inject]
private NavigationManager NavManager { get; set; }
[Inject]
private IJSRuntime JsRuntime { get; set; }
public void Dispose() => NavManager.LocationChanged -= TryFragmentNavigation;
public void Dispose()
{
NavManager.LocationChanged -= TryFragmentNavigation;
_cts?.Cancel();
_cts?.Dispose();
}
protected override void OnInitialized() => NavManager.LocationChanged += TryFragmentNavigation;
+12 -3
View File
@@ -1,9 +1,11 @@
@page "/"
@using Microsoft.Extensions.Caching.Memory
@using System.Reflection
@using System.Threading
@using ErsatzTV.Application.Health.Queries
@using ErsatzTV.Core.Health
@using ErsatzTV.Core.Interfaces.GitHub
@implements IDisposable
@inject IGitHubApiClient _gitHubApiClient
@inject IMemoryCache _memoryCache
@inject IMediator _mediator
@@ -71,9 +73,16 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private string _releaseNotes;
private MudTable<HealthCheckResult> _table;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
@@ -101,12 +110,12 @@
gitHubVersion = $"v{gitHubVersion}";
}
maybeNotes = await _gitHubApiClient.GetReleaseNotes(gitHubVersion);
maybeNotes = await _gitHubApiClient.GetReleaseNotes(gitHubVersion, _cts.Token);
maybeNotes.IfRight(notes => _releaseNotes = notes);
}
else
{
maybeNotes = await _gitHubApiClient.GetLatestReleaseNotes();
maybeNotes = await _gitHubApiClient.GetLatestReleaseNotes(_cts.Token);
maybeNotes.IfRight(notes => _releaseNotes = notes);
}
}
@@ -126,7 +135,7 @@
private async Task<TableData<HealthCheckResult>> ServerReload(TableState state)
{
List<HealthCheckResult> healthCheckResults = await _mediator.Send(new GetAllHealthCheckResults());
List<HealthCheckResult> healthCheckResults = await _mediator.Send(new GetAllHealthCheckResults(), _cts.Token);
return new TableData<HealthCheckResult>
{
+14 -5
View File
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Jellyfin.Queries
@using ErsatzTV.Application.MediaSources
@using ErsatzTV.Application.Jellyfin
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject ChannelWriter<IJellyfinBackgroundServiceRequest> _channel
@@ -16,20 +18,27 @@
SynchronizeLibraryByIdIfNeeded="SynchronizeLibraryByIdIfNeeded"/>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private IRequest<Either<BaseError, Unit>> GetUpdateLibraryRequest(List<RemoteMediaSourceLibraryEditViewModel> libraries) =>
new UpdateJellyfinLibraryPreferences(
libraries.Map(l => new JellyfinLibraryPreference(l.Id, l.ShouldSyncItems)).ToList());
private Task<List<RemoteMediaSourceLibraryEditViewModel>> GetLibrariesBySourceId(int mediaSourceId) =>
_mediator.Send(new GetJellyfinLibrariesBySourceId(Id))
private async Task<List<RemoteMediaSourceLibraryEditViewModel>> GetLibrariesBySourceId(int mediaSourceId) =>
await _mediator.Send(new GetJellyfinLibrariesBySourceId(Id), _cts.Token)
.Map(list => list.Map(ProjectToEditViewModel).OrderBy(x => x.MediaKind).ThenBy(x => x.Name).ToList());
private Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int mediaSourceId) =>
_mediator.Send(new GetJellyfinMediaSourceById(Id))
private async Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int mediaSourceId) =>
await _mediator.Send(new GetJellyfinMediaSourceById(Id), _cts.Token)
.MapT(vm => new RemoteMediaSourceViewModel(vm.Id, vm.Name, vm.Address));
private RemoteMediaSourceLibraryEditViewModel ProjectToEditViewModel(JellyfinLibraryViewModel library) => new()
@@ -42,7 +51,7 @@
private async Task<Unit> SynchronizeLibraryByIdIfNeeded(int libraryId)
{
await _channel.WriteAsync(new SynchronizeJellyfinLibraryByIdIfNeeded(libraryId));
await _channel.WriteAsync(new SynchronizeJellyfinLibraryByIdIfNeeded(libraryId), _cts.Token);
return Unit.Default;
}
+11 -2
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Core.Jellyfin
@using ErsatzTV.Application.Jellyfin.Queries
@using ErsatzTV.Application.Jellyfin.Commands
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject NavigationManager _navigationManager
@inject ISnackbar _snackbar
@@ -14,10 +16,17 @@
SaveSecrets="SaveSecrets"/>
@code {
private readonly CancellationTokenSource _cts = new();
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private async Task<Unit> LoadSecrets(RemoteMediaSourceEditViewModel viewModel)
{
JellyfinSecrets secrets = await _mediator.Send(new GetJellyfinSecrets());
JellyfinSecrets secrets = await _mediator.Send(new GetJellyfinSecrets(), _cts.Token);
viewModel.Address = secrets.Address;
viewModel.ApiKey = secrets.ApiKey;
return Unit.Default;
@@ -26,7 +35,7 @@
private async Task<Either<BaseError, Unit>> SaveSecrets(RemoteMediaSourceEditViewModel viewModel)
{
var secrets = new JellyfinSecrets { Address = viewModel.Address, ApiKey = viewModel.ApiKey };
return await _mediator.Send(new SaveJellyfinSecrets(secrets));
return await _mediator.Send(new SaveJellyfinSecrets(secrets), _cts.Token);
}
}
+10 -1
View File
@@ -2,6 +2,8 @@
@using ErsatzTV.Core.Interfaces.Jellyfin
@using ErsatzTV.Application.Jellyfin.Commands
@using ErsatzTV.Application.Jellyfin.Queries
@using System.Threading
@implements IDisposable
@inject IJellyfinSecretStore _jellyfinSecretStore
@inject ChannelWriter<IJellyfinBackgroundServiceRequest> _channel
@@ -16,8 +18,15 @@
SecretStore="@_jellyfinSecretStore"/>
@code {
private readonly CancellationTokenSource _cts = new();
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private async Task RefreshLibraries(int mediaSourceId) =>
await _channel.WriteAsync(new SynchronizeJellyfinLibraries(mediaSourceId));
await _channel.WriteAsync(new SynchronizeJellyfinLibraries(mediaSourceId), _cts.Token);
}
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Jellyfin
@using ErsatzTV.Application.Jellyfin.Commands
@using Unit = LanguageExt.Unit
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ScheduleItemsEditor> _logger
@inject ISnackbar _snackbar
@@ -17,16 +19,23 @@
GetPathReplacementsBySourceId="GetPathReplacementsBySourceId"/>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
private Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int id) =>
_mediator.Send(new GetJellyfinMediaSourceById(Id))
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private async Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int id) =>
await _mediator.Send(new GetJellyfinMediaSourceById(Id), _cts.Token)
.MapT(vm => new RemoteMediaSourceViewModel(vm.Id, vm.Name, vm.Address));
private Task<List<RemoteMediaSourcePathReplacementEditViewModel>> GetPathReplacementsBySourceId(int mediaSourceId) =>
_mediator.Send(new GetJellyfinPathReplacementsBySourceId(Id))
private async Task<List<RemoteMediaSourcePathReplacementEditViewModel>> GetPathReplacementsBySourceId(int mediaSourceId) =>
await _mediator.Send(new GetJellyfinPathReplacementsBySourceId(Id), _cts.Token)
.Map(list => list.Map(ProjectToEditViewModel).ToList());
private RemoteMediaSourcePathReplacementEditViewModel ProjectToEditViewModel(JellyfinPathReplacementViewModel item) =>
+12 -7
View File
@@ -78,6 +78,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private IList<LibraryViewModel> _libraries;
private Dictionary<int, int> _progressByLibrary;
@@ -87,11 +89,11 @@
_courier.Subscribe<LibraryScanProgress>(HandleScanProgress);
}
protected override async Task OnParametersSetAsync() => await LoadLibraries();
protected override async Task OnParametersSetAsync() => await LoadLibraries(_cts.Token);
private async Task LoadLibraries()
private async Task LoadLibraries(CancellationToken cancellationToken)
{
_libraries = await _mediator.Send(new GetConfiguredLibraries());
_libraries = await _mediator.Send(new GetConfiguredLibraries(), cancellationToken);
_progressByLibrary = _libraries.ToDictionary(vm => vm.Id, _ => 0);
}
@@ -102,16 +104,16 @@
switch (library)
{
case LocalLibraryViewModel:
await _workerChannel.WriteAsync(new ForceScanLocalLibrary(library.Id));
await _workerChannel.WriteAsync(new ForceScanLocalLibrary(library.Id), _cts.Token);
break;
case PlexLibraryViewModel:
await _plexWorkerChannel.WriteAsync(new ForceSynchronizePlexLibraryById(library.Id));
await _plexWorkerChannel.WriteAsync(new ForceSynchronizePlexLibraryById(library.Id), _cts.Token);
break;
case JellyfinLibraryViewModel:
await _jellyfinWorkerChannel.WriteAsync(new ForceSynchronizeJellyfinLibraryById(library.Id));
await _jellyfinWorkerChannel.WriteAsync(new ForceSynchronizeJellyfinLibraryById(library.Id), _cts.Token);
break;
case EmbyLibraryViewModel:
await _embyWorkerChannel.WriteAsync(new ForceSynchronizeEmbyLibraryById(library.Id));
await _embyWorkerChannel.WriteAsync(new ForceSynchronizeEmbyLibraryById(library.Id), _cts.Token);
break;
}
@@ -142,6 +144,9 @@
{
_locker.OnLibraryChanged -= LockChanged;
_courier.UnSubscribe<LibraryScanProgress>(HandleScanProgress);
_cts.Cancel();
_cts.Dispose();
}
}
+12 -6
View File
@@ -2,6 +2,7 @@
@using ErsatzTV.Application.Libraries
@using ErsatzTV.Application.Libraries.Commands
@using ErsatzTV.Application.Libraries.Queries
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -53,6 +54,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private IList<LocalLibraryViewModel> _libraries;
protected override void OnInitialized()
@@ -60,11 +63,11 @@
_locker.OnLibraryChanged += LockChanged;
}
protected override async Task OnParametersSetAsync() => await LoadLibraries();
protected override async Task OnParametersSetAsync() => await LoadLibraries(_cts.Token);
private async Task LoadLibraries()
private async Task LoadLibraries(CancellationToken cancellationToken)
{
_libraries = await _mediator.Send(new GetAllLocalLibraries());
_libraries = await _mediator.Send(new GetAllLocalLibraries(), cancellationToken);
}
private void LockChanged(object sender, EventArgs e) =>
@@ -72,7 +75,7 @@
private async Task DeleteLibrary(LocalLibraryViewModel library)
{
int count = await _mediator.Send(new CountMediaItemsByLibrary(library.Id));
int count = await _mediator.Send(new CountMediaItemsByLibrary(library.Id), _cts.Token);
var parameters = new DialogParameters
{
{ "EntityType", "library" },
@@ -86,14 +89,17 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteLocalLibrary(library.Id));
await LoadLibraries();
await _mediator.Send(new DeleteLocalLibrary(library.Id), _cts.Token);
await LoadLibraries(_cts.Token);
}
}
void IDisposable.Dispose()
{
_locker.OnLibraryChanged -= LockChanged;
_cts.Cancel();
_cts.Dispose();
}
}
+11 -6
View File
@@ -4,6 +4,7 @@
@using ErsatzTV.Application.Libraries.Commands
@using ErsatzTV.Application.Libraries.Queries
@using Unit = LanguageExt.Unit
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IEntityLocker _locker
@@ -76,6 +77,7 @@
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -91,7 +93,7 @@
{
if (IsEdit)
{
Option<LocalLibraryViewModel> maybeLibrary = await _mediator.Send(new GetLocalLibraryById(Id));
Option<LocalLibraryViewModel> maybeLibrary = await _mediator.Send(new GetLocalLibraryById(Id), _cts.Token);
await maybeLibrary.Match(
async library =>
{
@@ -130,7 +132,7 @@
private async Task LoadLibraryPaths()
{
_model.HasChanges = false;
_model.Paths = await _mediator.Send(new GetLocalLibraryPaths(Id))
_model.Paths = await _mediator.Send(new GetLocalLibraryPaths(Id), _cts.Token)
.Map(list => list.Map(vm => new LocalLibraryPathEditViewModel
{
Id = vm.Id,
@@ -148,7 +150,7 @@
if (!result.Cancelled && result.Data is LocalLibraryViewModel library)
{
var request = new MoveLocalLibraryPath(libraryPath.Id, library.Id);
Either<BaseError, Unit> moveResult = await _mediator.Send(request);
Either<BaseError, Unit> moveResult = await _mediator.Send(request, _cts.Token);
moveResult.Match(
_ => _navigationManager.NavigateTo($"/media/sources/local/{library.Id}/edit"),
error =>
@@ -167,7 +169,7 @@
_model.Paths.Remove(libraryPath);
}
int count = await _mediator.Send(new CountMediaItemsByLibraryPath(libraryPath.Id));
int count = await _mediator.Send(new CountMediaItemsByLibraryPath(libraryPath.Id), _cts.Token);
var parameters = new DialogParameters
{
{ "EntityType", "library path" },
@@ -209,11 +211,11 @@
? await _mediator.Send(new UpdateLocalLibrary(
_model.Id,
_model.Name,
_model.Paths.Map(p => new UpdateLocalLibraryPath(p.Id, p.Path)).ToList()))
_model.Paths.Map(p => new UpdateLocalLibraryPath(p.Id, p.Path)).ToList()), _cts.Token)
: await _mediator.Send(new CreateLocalLibrary(
_model.Name,
_model.MediaKind,
_model.Paths.Map(p => p.Path).ToList()));
_model.Paths.Map(p => p.Path).ToList()), _cts.Token);
result.Match(
_ => _navigationManager.NavigateTo("/media/sources/local"),
@@ -235,6 +237,9 @@
void IDisposable.Dispose()
{
_locker.OnLibraryChanged -= LockChanged;
_cts.Cancel();
_cts.Dispose();
}
}
+12 -3
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Application.Libraries.Commands
@using ErsatzTV.Application.Libraries.Queries
@using ErsatzTV.Application.MediaSources.Commands
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<LocalLibraryPathEditor> _logger
@inject ISnackbar _snackbar
@@ -32,6 +34,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -41,10 +44,16 @@
private ValidationMessageStore _messageStore;
private LocalLibraryViewModel _library;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
Option<LocalLibraryViewModel> maybeLibrary = await _mediator.Send(new GetLocalLibraryById(Id));
Option<LocalLibraryViewModel> maybeLibrary = await _mediator.Send(new GetLocalLibraryById(Id), _cts.Token);
maybeLibrary.Match(
library => _library = library,
() => _navigationManager.NavigateTo("404"));
@@ -62,7 +71,7 @@
if (_editContext.Validate())
{
var command = new CreateLocalLibraryPath(_library.Id, _model.Path);
Either<BaseError, LocalLibraryPathViewModel> result = await _mediator.Send(command);
Either<BaseError, LocalLibraryPathViewModel> result = await _mediator.Send(command, _cts.Token);
await result.Match(
Left: error =>
{
@@ -74,7 +83,7 @@
{
if (_locker.LockLibrary(_library.Id))
{
await _channel.WriteAsync(new ScanLocalLibraryIfNeeded(_library.Id));
await _channel.WriteAsync(new ScanLocalLibraryIfNeeded(_library.Id), _cts.Token);
_navigationManager.NavigateTo("/media/libraries");
}
});
+16 -5
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Application.Logs.Queries
@using ErsatzTV.Application.Configuration.Queries
@using ErsatzTV.Application.Configuration.Commands
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
@@ -36,15 +38,24 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<LogEntryViewModel> _table;
private int _rowsPerPage;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync() => _rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.LogsPageSize))
protected override async Task OnParametersSetAsync() => _rowsPerPage =
await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.LogsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
private async Task<TableData<LogEntryViewModel>> ServerReload(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.LogsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.LogsPageSize, state.PageSize.ToString()), _cts.Token);
PagedLogEntriesViewModel data;
@@ -57,7 +68,7 @@
SortDescending = state.SortDirection == SortDirection.None
? Option<bool>.None
: state.SortDirection == SortDirection.Descending
});
}, _cts.Token);
break;
case "level":
data = await _mediator.Send(new GetRecentLogEntries(state.Page, state.PageSize)
@@ -66,13 +77,13 @@
SortDescending = state.SortDirection == SortDirection.None
? Option<bool>.None
: state.SortDirection == SortDirection.Descending
});
}, _cts.Token);
break;
default:
data = await _mediator.Send(new GetRecentLogEntries(state.Page, state.PageSize)
{
SortDescending = Option<bool>.None
});
}, _cts.Token);
break;
}
+12 -3
View File
@@ -6,6 +6,8 @@
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Extensions
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject IDialogService _dialog
@inject NavigationManager _navigationManager
@@ -187,6 +189,7 @@
}
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int MovieId { get; set; }
@@ -200,10 +203,16 @@
private List<string> _sortedGenres = new();
private List<string> _sortedTags = new();
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override Task OnParametersSetAsync() => RefreshData();
private Task RefreshData() =>
_mediator.Send(new GetMovieById(MovieId)).IfSomeAsync(vm =>
private async Task RefreshData() =>
await _mediator.Send(new GetMovieById(MovieId), _cts.Token).IfSomeAsync(vm =>
{
_movie = vm;
_sortedContentRatings = _movie.ContentRatings.OrderBy(cr => cr).ToList();
@@ -224,7 +233,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
await _mediator.Send(new AddMovieToCollection(collection.Id, MovieId));
await _mediator.Send(new AddMovieToCollection(collection.Id, MovieId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}");
}
}
+5 -6
View File
@@ -1,7 +1,6 @@
@page "/media/movies"
@page "/media/movies/page/{PageNumber:int}"
@using LanguageExt.UnsafeValueAccess
@using Microsoft.AspNetCore.WebUtilities
@using ErsatzTV.Application.MediaCards
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@@ -81,7 +80,7 @@
private MovieCardResultsViewModel _data;
private string _query;
protected override Task OnParametersSetAsync()
{
if (PageNumber == 0)
@@ -96,12 +95,12 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:movie" : $"type:movie AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexMovies(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexMovies(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
{
var uri = $"/media/movies/page/{PageNumber - 1}";
string uri = $"/media/movies/page/{PageNumber - 1}";
if (!string.IsNullOrWhiteSpace(_query))
{
(string key, string value) = _query.EncodeQuery();
@@ -112,7 +111,7 @@
private void NextPage()
{
var uri = $"/media/movies/page/{PageNumber + 1}";
string uri = $"/media/movies/page/{PageNumber + 1}";
if (!string.IsNullOrWhiteSpace(_query))
{
(string key, string value) = _query.EncodeQuery();
@@ -143,7 +142,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddMovieToCollection(collection.Id, movie.MovieId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+15 -5
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.MediaCollections.Queries
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject NavigationManager _navigationManager
@inject ISnackbar _snackbar
@@ -104,6 +106,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -117,17 +121,23 @@
private MudSelect<MediaCollectionViewModel> _collectionSelect;
private MudSelect<SmartCollectionViewModel> _smartCollectionSelect;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_collections = await _mediator.Send(new GetAllCollections())
_collections = await _mediator.Send(new GetAllCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_smartCollections = await _mediator.Send(new GetAllSmartCollections())
_smartCollections = await _mediator.Send(new GetAllSmartCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
if (IsEdit)
{
Option<MultiCollectionViewModel> maybeCollection = await _mediator.Send(new GetMultiCollectionById(Id));
Option<MultiCollectionViewModel> maybeCollection = await _mediator.Send(new GetMultiCollectionById(Id), _cts.Token);
maybeCollection.IfSome(collection =>
{
_model.Id = collection.Id;
@@ -170,8 +180,8 @@
if (_editContext.Validate())
{
Seq<BaseError> errorMessage = IsEdit ?
(await _mediator.Send(new UpdateMultiCollection(Id, _model.Name, GetUpdateItems()))).LeftToSeq() :
(await _mediator.Send(new CreateMultiCollection(_model.Name, GetCreateItems()))).LeftToSeq();
(await _mediator.Send(new UpdateMultiCollection(Id, _model.Name, GetUpdateItems()), _cts.Token)).LeftToSeq() :
(await _mediator.Send(new CreateMultiCollection(_model.Name, GetCreateItems()), _cts.Token)).LeftToSeq();
errorMessage.HeadOrNone().Match(
error =>
+4 -2
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Application.MediaCards;
using ErsatzTV.Application.MediaCollections;
@@ -137,7 +138,7 @@ namespace ErsatzTV.Pages
otherVideoIds,
songIds);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -173,7 +174,8 @@ namespace ErsatzTV.Pages
new RemoveItemsFromCollection(collectionId)
{
MediaItemIds = itemIds
});
},
CancellationToken);
await RefreshData();
ClearSelection();
+2 -2
View File
@@ -97,7 +97,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:music_video" : $"type:music_video AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexMusicVideos(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexMusicVideos(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -144,7 +144,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddMusicVideoToCollection(collection.Id, musicVideo.MusicVideoId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+2 -2
View File
@@ -96,7 +96,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:other_video" : $"type:other_video AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexOtherVideos(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexOtherVideos(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -143,7 +143,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddOtherVideoToCollection(collection.Id, otherVideo.OtherVideoId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+12 -3
View File
@@ -3,6 +3,8 @@
@using ErsatzTV.Application.Channels.Queries
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Queries
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<PlayoutEditor> _logger
@inject ISnackbar _snackbar
@@ -48,6 +50,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private readonly PlayoutEditViewModel _model = new();
private List<ChannelViewModel> _channels;
@@ -55,12 +58,18 @@
private EditContext _editContext;
private ValidationMessageStore _messageStore;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_channels = await _mediator.Send(new GetAllChannels())
_channels = await _mediator.Send(new GetAllChannels(), _cts.Token)
.Map(list => list.OrderBy(vm => decimal.Parse(vm.Number)).ToList());
_programSchedules = await _mediator.Send(new GetAllProgramSchedules())
_programSchedules = await _mediator.Send(new GetAllProgramSchedules(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name).ToList());
}
@@ -75,7 +84,7 @@
_messageStore.Clear();
if (_editContext.Validate())
{
Seq<BaseError> errorMessage = (await _mediator.Send(_model.ToCreate())).LeftToSeq();
Seq<BaseError> errorMessage = (await _mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq();
errorMessage.HeadOrNone().Match(
error =>
+20 -10
View File
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Playouts.Queries
@using ErsatzTV.Application.Configuration.Commands
@using ErsatzTV.Application.Configuration.Queries
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -99,6 +101,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<PlayoutNameViewModel> _table;
private MudTable<PlayoutItemViewModel> _detailTable;
private int _rowsPerPage;
@@ -118,14 +122,20 @@
}
}
}
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsPageSize))
_rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
_detailRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsDetailPageSize))
_detailRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsDetailPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
_showFiller = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsDetailShowFiller))
_showFiller = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsDetailShowFiller), _cts.Token)
.Map(maybeShow => maybeShow.Match(ce => bool.TryParse(ce.Value, out bool show) && show, () => false));
}
@@ -152,7 +162,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeletePlayout(playout.PlayoutId));
await _mediator.Send(new DeletePlayout(playout.PlayoutId), _cts.Token);
await _table.ReloadServerData();
if (_selectedPlayoutId == playout.PlayoutId)
{
@@ -163,7 +173,7 @@
private async Task RebuildPlayout(PlayoutNameViewModel playout)
{
await _mediator.Send(new BuildPlayout(playout.PlayoutId, true));
await _mediator.Send(new BuildPlayout(playout.PlayoutId, true), _cts.Token);
await _table.ReloadServerData();
if (_selectedPlayoutId == playout.PlayoutId)
{
@@ -188,9 +198,9 @@
private async Task<TableData<PlayoutNameViewModel>> ServerReload(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsPageSize, state.PageSize.ToString()), _cts.Token);
List<PlayoutNameViewModel> playouts = await _mediator.Send(new GetAllPlayouts());
List<PlayoutNameViewModel> playouts = await _mediator.Send(new GetAllPlayouts(), _cts.Token);
IOrderedEnumerable<PlayoutNameViewModel> sorted = playouts.OrderBy(p => decimal.Parse(p.ChannelNumber));
// TODO: properly page this data
@@ -203,13 +213,13 @@
private async Task<TableData<PlayoutItemViewModel>> DetailServerReload(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsDetailPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsDetailShowFiller, _showFiller.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsDetailPageSize, state.PageSize.ToString()), _cts.Token);
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsDetailShowFiller, _showFiller.ToString()), _cts.Token);
if (_selectedPlayoutId.HasValue)
{
PagedPlayoutItemsViewModel data =
await _mediator.Send(new GetFuturePlayoutItemsById(_selectedPlayoutId.Value, _showFiller, state.Page, state.PageSize));
await _mediator.Send(new GetFuturePlayoutItemsById(_selectedPlayoutId.Value, _showFiller, state.Page, state.PageSize), _cts.Token);
return new TableData<PlayoutItemViewModel>
{
TotalItems = data.TotalCount,
+14 -5
View File
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Plex.Queries
@using ErsatzTV.Application.MediaSources
@using ErsatzTV.Application.Plex
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject ChannelWriter<IPlexBackgroundServiceRequest> _channel
@@ -16,6 +18,7 @@
SynchronizeLibraryByIdIfNeeded="SynchronizeLibraryByIdIfNeeded"/>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -24,14 +27,20 @@
new UpdatePlexLibraryPreferences(
libraries.Map(l => new PlexLibraryPreference(l.Id, l.ShouldSyncItems)).ToList());
private Task<List<RemoteMediaSourceLibraryEditViewModel>> GetLibrariesBySourceId(int mediaSourceId) =>
_mediator.Send(new GetPlexLibrariesBySourceId(Id))
private async Task<List<RemoteMediaSourceLibraryEditViewModel>> GetLibrariesBySourceId(int mediaSourceId) =>
await _mediator.Send(new GetPlexLibrariesBySourceId(Id), _cts.Token)
.Map(list => list.Map(ProjectToEditViewModel).OrderBy(x => x.MediaKind).ThenBy(x => x.Name).ToList());
private Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int mediaSourceId) =>
_mediator.Send(new GetPlexMediaSourceById(Id))
private async Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int mediaSourceId) =>
await _mediator.Send(new GetPlexMediaSourceById(Id), _cts.Token)
.MapT(vm => new RemoteMediaSourceViewModel(vm.Id, vm.Name, vm.Address));
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private RemoteMediaSourceLibraryEditViewModel ProjectToEditViewModel(PlexLibraryViewModel library) => new()
{
Id = library.Id,
@@ -42,7 +51,7 @@
private async Task<Unit> SynchronizeLibraryByIdIfNeeded(int libraryId)
{
await _channel.WriteAsync(new SynchronizePlexLibraryByIdIfNeeded(libraryId));
await _channel.WriteAsync(new SynchronizePlexLibraryByIdIfNeeded(libraryId), _cts.Token);
return Unit.Default;
}
+1
View File
@@ -3,6 +3,7 @@
@using ErsatzTV.Application.Plex
@using ErsatzTV.Application.Plex.Commands
@using ErsatzTV.Application.Plex.Queries
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Plex.Commands
@using ErsatzTV.Application.Plex.Queries
@using Unit = LanguageExt.Unit
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ScheduleItemsEditor> _logger
@inject ISnackbar _snackbar
@@ -17,16 +19,23 @@
GetPathReplacementsBySourceId="GetPathReplacementsBySourceId"/>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
private Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int id) =>
_mediator.Send(new GetPlexMediaSourceById(Id))
private async Task<Option<RemoteMediaSourceViewModel>> GetMediaSourceById(int id) =>
await _mediator.Send(new GetPlexMediaSourceById(Id), _cts.Token)
.MapT(vm => new RemoteMediaSourceViewModel(vm.Id, vm.Name, vm.Address));
private Task<List<RemoteMediaSourcePathReplacementEditViewModel>> GetPathReplacementsBySourceId(int mediaSourceId) =>
_mediator.Send(new GetPlexPathReplacementsBySourceId(Id))
private async Task<List<RemoteMediaSourcePathReplacementEditViewModel>> GetPathReplacementsBySourceId(int mediaSourceId) =>
await _mediator.Send(new GetPlexPathReplacementsBySourceId(Id), _cts.Token)
.Map(list => list.Map(ProjectToEditViewModel).ToList());
private RemoteMediaSourcePathReplacementEditViewModel ProjectToEditViewModel(PlexPathReplacementViewModel item) =>
+13 -4
View File
@@ -2,6 +2,8 @@
@page "/schedules/add"
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Queries
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ScheduleEditor> _logger
@inject ISnackbar _snackbar
@@ -50,6 +52,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -57,12 +60,18 @@
private readonly ProgramScheduleEditViewModel _model = new();
private EditContext _editContext;
private ValidationMessageStore _messageStore;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
if (IsEdit)
{
Option<ProgramScheduleViewModel> maybeProgramSchedule = await _mediator.Send(new GetProgramScheduleById(Id));
Option<ProgramScheduleViewModel> maybeProgramSchedule = await _mediator.Send(new GetProgramScheduleById(Id), _cts.Token);
maybeProgramSchedule.Match(
viewModel =>
{
@@ -93,9 +102,9 @@
_messageStore.Clear();
if (_editContext.Validate())
{
Either<BaseError, EntityIdResult> result = IsEdit ?
await _mediator.Send(_model.ToUpdate()).MapT(r => r as EntityIdResult) :
await _mediator.Send(_model.ToCreate()).MapT(r => r as EntityIdResult);
Either<BaseError, EntityIdResult> result = IsEdit
? await _mediator.Send(_model.ToUpdate(), _cts.Token).MapT(r => r as EntityIdResult)
: await _mediator.Send(_model.ToCreate(), _cts.Token).MapT(r => r as EntityIdResult);
result.Match(
programSchedule =>
+19 -10
View File
@@ -10,6 +10,8 @@
@using ErsatzTV.Application.Filler
@using ErsatzTV.Application.Filler.Queries
@using ErsatzTV.Core.Domain.Filler
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<ScheduleItemsEditor> _logger
@inject ISnackbar _snackbar
@@ -289,6 +291,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -303,37 +306,43 @@
private List<FillerPresetViewModel> _fillerPresets;
private ProgramScheduleItemEditViewModel _selectedItem;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override Task OnParametersSetAsync() => LoadScheduleItems();
private async Task LoadScheduleItems()
{
// TODO: fix performance
_mediaCollections = await _mediator.Send(new GetAllCollections())
_mediaCollections = await _mediator.Send(new GetAllCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_multiCollections = await _mediator.Send(new GetAllMultiCollections())
_multiCollections = await _mediator.Send(new GetAllMultiCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_smartCollections = await _mediator.Send(new GetAllSmartCollections())
_smartCollections = await _mediator.Send(new GetAllSmartCollections(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_televisionShows = await _mediator.Send(new GetAllTelevisionShows())
_televisionShows = await _mediator.Send(new GetAllTelevisionShows(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_televisionSeasons = await _mediator.Send(new GetAllTelevisionSeasons())
_televisionSeasons = await _mediator.Send(new GetAllTelevisionSeasons(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_artists = await _mediator.Send(new GetAllArtists())
_artists = await _mediator.Send(new GetAllArtists(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
_fillerPresets = await _mediator.Send(new GetAllFillerPresets())
_fillerPresets = await _mediator.Send(new GetAllFillerPresets(), _cts.Token)
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
string name = string.Empty;
var shuffleScheduleItems = false;
Option<ProgramScheduleViewModel> maybeSchedule = await _mediator.Send(new GetProgramScheduleById(Id));
Option<ProgramScheduleViewModel> maybeSchedule = await _mediator.Send(new GetProgramScheduleById(Id), _cts.Token);
foreach (ProgramScheduleViewModel schedule in maybeSchedule)
{
name = schedule.Name;
shuffleScheduleItems = schedule.ShuffleScheduleItems;
}
Option<IEnumerable<ProgramScheduleItemViewModel>> maybeResults = await _mediator.Send(new GetProgramScheduleItems(Id));
Option<IEnumerable<ProgramScheduleItemViewModel>> maybeResults = await _mediator.Send(new GetProgramScheduleItems(Id), _cts.Token);
foreach (IEnumerable<ProgramScheduleItemViewModel> items in maybeResults)
{
_schedule = new ProgramScheduleItemsEditViewModel
@@ -450,7 +459,7 @@
item.TailFiller?.Id,
item.FallbackFiller?.Id)).ToList();
Seq<BaseError> errorMessages = await _mediator.Send(new ReplaceProgramScheduleItems(Id, items)).Map(e => e.LeftToSeq());
Seq<BaseError> errorMessages = await _mediator.Send(new ReplaceProgramScheduleItems(Id, items), _cts.Token).Map(e => e.LeftToSeq());
errorMessages.HeadOrNone().Match(
error =>
+17 -7
View File
@@ -5,6 +5,8 @@
@using ErsatzTV.Application.Configuration.Queries
@using ErsatzTV.Application.Configuration.Commands
@using NaturalSort.Extension
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@@ -90,17 +92,25 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<ProgramScheduleViewModel> _table;
private MudTable<ProgramScheduleItemViewModel> _detailTable;
private int _rowsPerPage;
private int _detailRowsPerPage;
private ProgramScheduleViewModel _selectedSchedule;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
_rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.SchedulesPageSize))
_rowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.SchedulesPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
_detailRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.SchedulesDetailPageSize))
_detailRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.SchedulesDetailPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
}
@@ -119,7 +129,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteProgramSchedule(programSchedule.Id));
await _mediator.Send(new DeleteProgramSchedule(programSchedule.Id), _cts.Token);
await _table.ReloadServerData();
if (_selectedSchedule == programSchedule)
{
@@ -130,9 +140,9 @@
private async Task<TableData<ProgramScheduleViewModel>> ServerReload(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.SchedulesPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.SchedulesPageSize, state.PageSize.ToString()), _cts.Token);
List<ProgramScheduleViewModel> schedules = await _mediator.Send(new GetAllProgramSchedules());
List<ProgramScheduleViewModel> schedules = await _mediator.Send(new GetAllProgramSchedules(), _cts.Token);
IOrderedEnumerable<ProgramScheduleViewModel> sorted = schedules.OrderBy(s => s.Name, new NaturalSortComparer(StringComparison.CurrentCultureIgnoreCase));
// TODO: properly page this data
@@ -145,9 +155,9 @@
private async Task<TableData<ProgramScheduleItemViewModel>> DetailServerReload(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.SchedulesDetailPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.SchedulesDetailPageSize, state.PageSize.ToString()), _cts.Token);
List<ProgramScheduleItemViewModel> scheduleItems = await _mediator.Send(new GetProgramScheduleItems(_selectedSchedule.Id));
List<ProgramScheduleItemViewModel> scheduleItems = await _mediator.Send(new GetProgramScheduleItems(_selectedSchedule.Id), _cts.Token);
IOrderedEnumerable<ProgramScheduleItemViewModel> sorted = scheduleItems.OrderBy(s => s.Index);
// TODO: properly page this data
+16 -16
View File
@@ -333,14 +333,14 @@
_query = _navigationManager.Uri.GetSearchQuery();
if (!string.IsNullOrWhiteSpace(_query))
{
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50));
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50));
_seasons = await Mediator.Send(new QuerySearchIndexSeasons($"type:season AND ({_query})", 1, 50));
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50));
_musicVideos = await Mediator.Send(new QuerySearchIndexMusicVideos($"type:music_video AND ({_query})", 1, 50));
_otherVideos = await Mediator.Send(new QuerySearchIndexOtherVideos($"type:other_video AND ({_query})", 1, 50));
_songs = await Mediator.Send(new QuerySearchIndexSongs($"type:song AND ({_query})", 1, 50));
_artists = await Mediator.Send(new QuerySearchIndexArtists($"type:artist AND ({_query})", 1, 50));
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50), CancellationToken);
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50), CancellationToken);
_seasons = await Mediator.Send(new QuerySearchIndexSeasons($"type:season AND ({_query})", 1, 50), CancellationToken);
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50), CancellationToken);
_musicVideos = await Mediator.Send(new QuerySearchIndexMusicVideos($"type:music_video AND ({_query})", 1, 50), CancellationToken);
_otherVideos = await Mediator.Send(new QuerySearchIndexOtherVideos($"type:other_video AND ({_query})", 1, 50), CancellationToken);
_songs = await Mediator.Send(new QuerySearchIndexSongs($"type:song AND ({_query})", 1, 50), CancellationToken);
_artists = await Mediator.Send(new QuerySearchIndexArtists($"type:artist AND ({_query})", 1, 50), CancellationToken);
}
}
@@ -374,7 +374,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddMovieToCollection(collection.Id, movie.MovieId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -395,7 +395,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddShowToCollection(collection.Id, show.TelevisionShowId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -416,7 +416,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddEpisodeToCollection(collection.Id, episode.EpisodeId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -437,7 +437,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddArtistToCollection(collection.Id, artist.ArtistId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -458,7 +458,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddMusicVideoToCollection(collection.Id, musicVideo.MusicVideoId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -479,7 +479,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddOtherVideoToCollection(collection.Id, otherVideo.OtherVideoId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
@@ -581,7 +581,7 @@
private async Task AddAllToCollection(MouseEventArgs _)
{
SearchResultAllItemsViewModel results = await Mediator.Send(new QuerySearchIndexAllItems(_query));
SearchResultAllItemsViewModel results = await Mediator.Send(new QuerySearchIndexAllItems(_query), CancellationToken);
await AddItemsToCollection(
results.MovieIds,
results.ShowIds,
@@ -606,7 +606,7 @@
collection.Id,
_query);
Either<BaseError, Unit> updateResult = await Mediator.Send(request);
Either<BaseError, Unit> updateResult = await Mediator.Send(request, CancellationToken);
updateResult.Match(
Left: error =>
{
+22 -12
View File
@@ -16,6 +16,8 @@
@using ErsatzTV.Core.Domain.Filler
@using ErsatzTV.Core.FFmpeg
@using Microsoft.AspNetCore.Components
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject ISnackbar _snackbar
@inject ILogger<Settings> _logger
@@ -177,6 +179,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private bool _success;
private bool _hdhrSuccess;
private bool _scannerSuccess;
@@ -189,22 +193,28 @@
private int _tunerCount;
private int _libraryRefreshInterval;
private int _playoutDaysToBuild;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
await LoadFFmpegProfilesAsync();
_ffmpegSettings = await _mediator.Send(new GetFFmpegSettings());
_ffmpegSettings = await _mediator.Send(new GetFFmpegSettings(), _cts.Token);
_success = File.Exists(_ffmpegSettings.FFmpegPath) && File.Exists(_ffmpegSettings.FFprobePath);
_availableCultures = await _mediator.Send(new GetAllLanguageCodes());
_watermarks = await _mediator.Send(new GetAllWatermarks());
_fillerPresets = await _mediator.Send(new GetAllFillerPresets())
_availableCultures = await _mediator.Send(new GetAllLanguageCodes(), _cts.Token);
_watermarks = await _mediator.Send(new GetAllWatermarks(), _cts.Token);
_fillerPresets = await _mediator.Send(new GetAllFillerPresets(), _cts.Token)
.Map(list => list.Filter(fp => fp.FillerKind == FillerKind.Fallback).ToList());
_tunerCount = await _mediator.Send(new GetHDHRTunerCount());
_tunerCount = await _mediator.Send(new GetHDHRTunerCount(), _cts.Token);
_hdhrSuccess = string.IsNullOrWhiteSpace(ValidateTunerCount(_tunerCount));
_libraryRefreshInterval = await _mediator.Send(new GetLibraryRefreshInterval());
_libraryRefreshInterval = await _mediator.Send(new GetLibraryRefreshInterval(), _cts.Token);
_scannerSuccess = _libraryRefreshInterval > 0;
_playoutDaysToBuild = await _mediator.Send(new GetPlayoutDaysToBuild());
_playoutDaysToBuild = await _mediator.Send(new GetPlayoutDaysToBuild(), _cts.Token);
_playoutSuccess = _playoutDaysToBuild > 0;
}
@@ -223,11 +233,11 @@
private static string ValidateInitialSegmentCount(int count) => count < 1 ? "HLS Segmenter initial segment count must be greater than or equal to 1" : null;
private async Task LoadFFmpegProfilesAsync() =>
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles());
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles(), _cts.Token);
private async Task SaveFFmpegSettings()
{
Either<BaseError, Unit> result = await _mediator.Send(new UpdateFFmpegSettings(_ffmpegSettings));
Either<BaseError, Unit> result = await _mediator.Send(new UpdateFFmpegSettings(_ffmpegSettings), _cts.Token);
result.Match(
Left: error =>
{
@@ -239,7 +249,7 @@
private async Task SaveHDHRSettings()
{
Either<BaseError, Unit> result = await _mediator.Send(new UpdateHDHRTunerCount(_tunerCount));
Either<BaseError, Unit> result = await _mediator.Send(new UpdateHDHRTunerCount(_tunerCount), _cts.Token);
result.Match(
Left: error =>
{
@@ -251,7 +261,7 @@
private async Task SaveScannerSettings()
{
Either<BaseError, Unit> result = await _mediator.Send(new UpdateLibraryRefreshInterval(_libraryRefreshInterval));
Either<BaseError, Unit> result = await _mediator.Send(new UpdateLibraryRefreshInterval(_libraryRefreshInterval), _cts.Token);
result.Match(
Left: error =>
{
@@ -263,7 +273,7 @@
private async Task SavePlayoutSettings()
{
Either<BaseError, Unit> result = await _mediator.Send(new UpdatePlayoutDaysToBuild(_playoutDaysToBuild));
Either<BaseError, Unit> result = await _mediator.Send(new UpdatePlayoutDaysToBuild(_playoutDaysToBuild), _cts.Token);
result.Match(
Left: error =>
{
+2 -2
View File
@@ -96,7 +96,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:song" : $"type:song AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexSongs(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexSongs(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -143,7 +143,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddSongToCollection(collection.Id, song.SongId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+14 -5
View File
@@ -9,6 +9,8 @@
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands
@using Unit = LanguageExt.Unit
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject ILogger<TelevisionEpisodeList> _logger
@inject ISnackbar _snackbar
@@ -156,6 +158,7 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int SeasonId { get; set; }
@@ -166,6 +169,12 @@
private readonly int _pageNumber = 1;
private TelevisionEpisodeCardResultsViewModel _data;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
@@ -179,10 +188,10 @@
private async Task RefreshData()
{
await _mediator.Send(new GetTelevisionSeasonById(SeasonId))
await _mediator.Send(new GetTelevisionSeasonById(SeasonId), _cts.Token)
.IfSomeAsync(vm => _season = vm);
_data = await _mediator.Send(new GetTelevisionEpisodeCards(SeasonId, _pageNumber, _pageSize));
_data = await _mediator.Send(new GetTelevisionEpisodeCards(SeasonId, _pageNumber, _pageSize), _cts.Token);
}
private async Task AddToCollection()
@@ -194,7 +203,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
await _mediator.Send(new AddSeasonToCollection(collection.Id, SeasonId));
await _mediator.Send(new AddSeasonToCollection(collection.Id, SeasonId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}");
}
}
@@ -209,7 +218,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule)
{
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, null, SeasonId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null));
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionSeason, null, null, null, SeasonId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null), _cts.Token);
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
}
}
@@ -224,7 +233,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddEpisodeToCollection(collection.Id, episode.EpisodeId);
Either<BaseError, Unit> addResult = await _mediator.Send(request);
Either<BaseError, Unit> addResult = await _mediator.Send(request, _cts.Token);
addResult.Match(
Left: error =>
{
+14 -5
View File
@@ -10,6 +10,8 @@
@using ErsatzTV.Application.ProgramSchedules.Commands
@using ErsatzTV.Extensions
@using Unit = LanguageExt.Unit
@using System.Threading
@implements IDisposable
@inject IMediator _mediator
@inject ILogger<TelevisionSeasonList> _logger
@inject ISnackbar _snackbar
@@ -168,6 +170,7 @@
}
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int ShowId { get; set; }
@@ -183,12 +186,18 @@
private readonly int _pageNumber = 1;
private TelevisionSeasonCardResultsViewModel _data;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override Task OnParametersSetAsync() => RefreshData();
private async Task RefreshData()
{
await _mediator.Send(new GetTelevisionShowById(ShowId))
await _mediator.Send(new GetTelevisionShowById(ShowId), _cts.Token)
.IfSomeAsync(vm =>
{
_show = vm;
@@ -199,7 +208,7 @@
_sortedTags = _show.Tags.OrderBy(t => t).ToList();
});
_data = await _mediator.Send(new GetTelevisionSeasonCards(ShowId, _pageNumber, _pageSize));
_data = await _mediator.Send(new GetTelevisionSeasonCards(ShowId, _pageNumber, _pageSize), _cts.Token);
}
private async Task AddToCollection()
@@ -211,7 +220,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
await _mediator.Send(new AddShowToCollection(collection.Id, ShowId));
await _mediator.Send(new AddShowToCollection(collection.Id, ShowId), _cts.Token);
_navigationManager.NavigateTo($"/media/collections/{collection.Id}");
}
}
@@ -225,7 +234,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule)
{
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, null, null, ShowId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null));
await _mediator.Send(new AddProgramScheduleItem(schedule.Id, StartType.Dynamic, null, PlayoutMode.One, ProgramScheduleItemCollectionType.TelevisionShow, null, null, null, ShowId, PlaybackOrder.Shuffle, null, null, TailMode.None, null, GuideMode.Normal, null, null, null, null, null), _cts.Token);
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
}
}
@@ -242,7 +251,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddSeasonToCollection(collection.Id, season.TelevisionSeasonId);
Either<BaseError, Unit> addResult = await _mediator.Send(request);
Either<BaseError, Unit> addResult = await _mediator.Send(request, _cts.Token);
addResult.Match(
Left: error =>
{
@@ -95,7 +95,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:season" : $"type:season AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexSeasons(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexSeasons(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -142,7 +142,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddSeasonToCollection(collection.Id, season.TelevisionSeasonId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+2 -2
View File
@@ -95,7 +95,7 @@
protected override async Task RefreshData()
{
string searchQuery = string.IsNullOrWhiteSpace(_query) ? "type:show" : $"type:show AND ({_query})";
_data = await Mediator.Send(new QuerySearchIndexShows(searchQuery, PageNumber, PageSize));
_data = await Mediator.Send(new QuerySearchIndexShows(searchQuery, PageNumber, PageSize), CancellationToken);
}
private void PrevPage()
@@ -142,7 +142,7 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddShowToCollection(collection.Id, show.TelevisionShowId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
addResult.Match(
Left: error =>
{
+16 -6
View File
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Configuration.Queries
@using ErsatzTV.Application.Configuration.Commands
@using ErsatzTV.Application.MediaCollections.Commands
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@inject ISnackbar _snackbar
@@ -75,9 +77,17 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private MudTable<TraktListViewModel> _traktListsTable;
private int _traktListsRowsPerPage;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override void OnInitialized()
{
@@ -86,7 +96,7 @@
protected override async Task OnParametersSetAsync()
{
_traktListsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.TraktListsPageSize))
_traktListsRowsPerPage = await _mediator.Send(new GetConfigElementByKey(ConfigElementKey.TraktListsPageSize), _cts.Token)
.Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10));
}
@@ -104,7 +114,7 @@
{
if (_locker.LockTrakt())
{
await _workerChannel.WriteAsync(new MatchTraktListItems(traktList.Id));
await _workerChannel.WriteAsync(new MatchTraktListItems(traktList.Id), _cts.Token);
}
}
@@ -119,16 +129,16 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _workerChannel.WriteAsync(new DeleteTraktList(traktList.Id));
await _workerChannel.WriteAsync(new DeleteTraktList(traktList.Id), _cts.Token);
}
}
}
private async Task<TableData<TraktListViewModel>> ServerReloadTraktLists(TableState state)
{
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.TraktListsPageSize, state.PageSize.ToString()));
await _mediator.Send(new SaveConfigElementByKey(ConfigElementKey.TraktListsPageSize, state.PageSize.ToString()), _cts.Token);
PagedTraktListsViewModel data = await _mediator.Send(new GetPagedTraktLists(state.Page, state.PageSize));
PagedTraktListsViewModel data = await _mediator.Send(new GetPagedTraktLists(state.Page, state.PageSize), _cts.Token);
return new TableData<TraktListViewModel> { TotalItems = data.TotalCount, Items = data.Page };
}
@@ -141,7 +151,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is string url)
{
await _workerChannel.WriteAsync(new AddTraktList(url));
await _workerChannel.WriteAsync(new AddTraktList(url), _cts.Token);
}
}
}
+10 -10
View File
@@ -327,14 +327,14 @@
_query = "state:FileNotFound";
if (!string.IsNullOrWhiteSpace(_query))
{
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50));
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50));
_seasons = await Mediator.Send(new QuerySearchIndexSeasons($"type:season AND ({_query})", 1, 50));
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50));
_musicVideos = await Mediator.Send(new QuerySearchIndexMusicVideos($"type:music_video AND ({_query})", 1, 50));
_otherVideos = await Mediator.Send(new QuerySearchIndexOtherVideos($"type:other_video AND ({_query})", 1, 50));
_songs = await Mediator.Send(new QuerySearchIndexSongs($"type:song AND ({_query})", 1, 50));
_artists = await Mediator.Send(new QuerySearchIndexArtists($"type:artist AND ({_query})", 1, 50));
_movies = await Mediator.Send(new QuerySearchIndexMovies($"type:movie AND ({_query})", 1, 50), CancellationToken);
_shows = await Mediator.Send(new QuerySearchIndexShows($"type:show AND ({_query})", 1, 50), CancellationToken);
_seasons = await Mediator.Send(new QuerySearchIndexSeasons($"type:season AND ({_query})", 1, 50), CancellationToken);
_episodes = await Mediator.Send(new QuerySearchIndexEpisodes($"type:episode AND ({_query})", 1, 50), CancellationToken);
_musicVideos = await Mediator.Send(new QuerySearchIndexMusicVideos($"type:music_video AND ({_query})", 1, 50), CancellationToken);
_otherVideos = await Mediator.Send(new QuerySearchIndexOtherVideos($"type:other_video AND ({_query})", 1, 50), CancellationToken);
_songs = await Mediator.Send(new QuerySearchIndexSongs($"type:song AND ({_query})", 1, 50), CancellationToken);
_artists = await Mediator.Send(new QuerySearchIndexArtists($"type:artist AND ({_query})", 1, 50), CancellationToken);
}
}
@@ -486,7 +486,7 @@
.Append(songIds)
.ToList());
Either<BaseError, Unit> addResult = await Mediator.Send(request);
Either<BaseError, Unit> addResult = await Mediator.Send(request, CancellationToken);
await addResult.Match(
Left: error =>
{
@@ -556,7 +556,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await Mediator.Send(request);
await Mediator.Send(request, CancellationToken);
await RefreshData();
}
}
+16 -6
View File
@@ -4,6 +4,8 @@
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Application.Watermarks.Queries
@using ErsatzTV.FFmpeg.State
@using System.Threading
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<WatermarkEditor> _logger
@inject ISnackbar _snackbar
@@ -146,7 +148,8 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
[Parameter]
public int Id { get; set; }
@@ -154,11 +157,17 @@
private EditContext _editContext;
private ValidationMessageStore _messageStore;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync()
{
if (IsEdit)
{
Option<WatermarkViewModel> watermark = await _mediator.Send(new GetWatermarkById(Id));
Option<WatermarkViewModel> watermark = await _mediator.Send(new GetWatermarkById(Id), _cts.Token);
watermark.Match(
watermarkViewModel => _model = new WatermarkEditViewModel(watermarkViewModel),
() => _navigationManager.NavigateTo("404"));
@@ -193,8 +202,8 @@
if (_editContext.Validate())
{
Seq<BaseError> errorMessage = IsEdit ?
(await _mediator.Send(_model.ToUpdate())).LeftToSeq() :
(await _mediator.Send(_model.ToCreate())).LeftToSeq();
(await _mediator.Send(_model.ToUpdate(), _cts.Token)).LeftToSeq() :
(await _mediator.Send(_model.ToCreate(), _cts.Token)).LeftToSeq();
errorMessage.HeadOrNone().Match(
error =>
@@ -210,8 +219,9 @@
{
try
{
Either<BaseError, string> maybeCacheFileName = await _mediator
.Send(new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Watermark));
Either<BaseError, string> maybeCacheFileName = await _mediator.Send(
new SaveArtworkToDisk(e.File.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024), ArtworkKind.Watermark),
_cts.Token);
maybeCacheFileName.Match(
relativeFileName =>
{
+12 -2
View File
@@ -2,6 +2,8 @@
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Application.Watermarks.Commands
@using ErsatzTV.Application.Watermarks.Queries
@using System.Threading
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@inject ILogger<Watermarks> _logger
@@ -72,12 +74,20 @@
</MudContainer>
@code {
private readonly CancellationTokenSource _cts = new();
private List<WatermarkViewModel> _watermarks;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
protected override async Task OnParametersSetAsync() => await LoadWatermarksAsync();
private async Task LoadWatermarksAsync() =>
_watermarks = await _mediator.Send(new GetAllWatermarks());
_watermarks = await _mediator.Send(new GetAllWatermarks(), _cts.Token);
private async Task DeleteWatermarkAsync(WatermarkViewModel watermark)
{
@@ -88,7 +98,7 @@
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await _mediator.Send(new DeleteWatermark(watermark.Id));
await _mediator.Send(new DeleteWatermark(watermark.Id), _cts.Token);
await LoadWatermarksAsync();
}
}