mirror of https://github.com/ErsatzTV/ErsatzTV.git
29 changed files with 35482 additions and 6 deletions
@ -0,0 +1,5 @@ |
|||||||
|
using ErsatzTV.Core; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCollections; |
||||||
|
|
||||||
|
public record UpdateTraktList(int Id, bool AutoRefresh) : IRequest<Option<BaseError>>; |
@ -0,0 +1,29 @@ |
|||||||
|
using ErsatzTV.Core; |
||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCollections; |
||||||
|
|
||||||
|
public class UpdateTraktListHandler(IDbContextFactory<TvContext> dbContextFactory) |
||||||
|
: IRequestHandler<UpdateTraktList, Option<BaseError>> |
||||||
|
{ |
||||||
|
public async Task<Option<BaseError>> Handle(UpdateTraktList request, CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); |
||||||
|
|
||||||
|
await dbContext.TraktLists |
||||||
|
.Where(tl => tl.Id == request.Id) |
||||||
|
.ExecuteUpdateAsync( |
||||||
|
u => u.SetProperty(p => p.AutoRefresh, p => request.AutoRefresh), |
||||||
|
cancellationToken); |
||||||
|
|
||||||
|
return Option<BaseError>.None; |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
return BaseError.New(ex.ToString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
namespace ErsatzTV.Application.MediaCollections; |
||||||
|
|
||||||
|
public record GetTraktListById(int Id) : IRequest<Option<TraktListViewModel>>; |
@ -0,0 +1,18 @@ |
|||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.MediaCollections; |
||||||
|
|
||||||
|
public class GetTraktListByIdHandler(IDbContextFactory<TvContext> dbContextFactory) |
||||||
|
: IRequestHandler<GetTraktListById, Option<TraktListViewModel>> |
||||||
|
{ |
||||||
|
public async Task<Option<TraktListViewModel>> Handle(GetTraktListById request, CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); |
||||||
|
return await dbContext.TraktLists |
||||||
|
.Include(tl => tl.Items) |
||||||
|
.SelectOneAsync(tl => tl.Id, tl => tl.Id == request.Id) |
||||||
|
.MapT(Mapper.ProjectToViewModel); |
||||||
|
} |
||||||
|
} |
@ -1,3 +1,10 @@ |
|||||||
namespace ErsatzTV.Application.MediaCollections; |
namespace ErsatzTV.Application.MediaCollections; |
||||||
|
|
||||||
public record TraktListViewModel(int Id, int TraktId, string Slug, string Name, int ItemCount, int MatchCount); |
public record TraktListViewModel( |
||||||
|
int Id, |
||||||
|
int TraktId, |
||||||
|
string Slug, |
||||||
|
string Name, |
||||||
|
int ItemCount, |
||||||
|
int MatchCount, |
||||||
|
bool AutoRefresh); |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.MySql.Migrations |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_TraktListAutoRefresh : Migration |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<bool>( |
||||||
|
name: "AutoRefresh", |
||||||
|
table: "TraktList", |
||||||
|
type: "tinyint(1)", |
||||||
|
nullable: false, |
||||||
|
defaultValue: false); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "AutoRefresh", |
||||||
|
table: "TraktList"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
using System; |
||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.MySql.Migrations |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_TraktListLastUpdate : Migration |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<DateTime>( |
||||||
|
name: "LastUpdate", |
||||||
|
table: "TraktList", |
||||||
|
type: "datetime(6)", |
||||||
|
nullable: true); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "LastUpdate", |
||||||
|
table: "TraktList"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
using System; |
||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.MySql.Migrations |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_TraktListLastMatch : Migration |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<DateTime>( |
||||||
|
name: "LastMatch", |
||||||
|
table: "TraktList", |
||||||
|
type: "datetime(6)", |
||||||
|
nullable: true); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "LastMatch", |
||||||
|
table: "TraktList"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Sqlite.Migrations |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_TraktListAutoRefresh : Migration |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<bool>( |
||||||
|
name: "AutoRefresh", |
||||||
|
table: "TraktList", |
||||||
|
type: "INTEGER", |
||||||
|
nullable: false, |
||||||
|
defaultValue: false); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "AutoRefresh", |
||||||
|
table: "TraktList"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
using System; |
||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Sqlite.Migrations |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_TraktListLastUpdate : Migration |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<DateTime>( |
||||||
|
name: "LastUpdate", |
||||||
|
table: "TraktList", |
||||||
|
type: "TEXT", |
||||||
|
nullable: true); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "LastUpdate", |
||||||
|
table: "TraktList"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
using System; |
||||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||||
|
|
||||||
|
#nullable disable |
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Sqlite.Migrations |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_TraktListLastMatch : Migration |
||||||
|
{ |
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.AddColumn<DateTime>( |
||||||
|
name: "LastMatch", |
||||||
|
table: "TraktList", |
||||||
|
type: "TEXT", |
||||||
|
nullable: true); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||||
|
{ |
||||||
|
migrationBuilder.DropColumn( |
||||||
|
name: "LastMatch", |
||||||
|
table: "TraktList"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
@page "/media/trakt/lists/{Id:int}" |
||||||
|
@using ErsatzTV.Application.MediaCollections |
||||||
|
@implements IDisposable |
||||||
|
@inject NavigationManager NavigationManager |
||||||
|
@inject ILogger<ScheduleEditor> Logger |
||||||
|
@inject ISnackbar Snackbar |
||||||
|
@inject IMediator Mediator |
||||||
|
|
||||||
|
<MudForm @ref="_form" @bind-IsValid="@_success" Style="max-height: 100%"> |
||||||
|
<MudPaper Square="true" Style="display: flex; height: 64px; min-height: 64px; width: 100%; z-index: 100; align-items: center"> |
||||||
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="ml-6" OnClick="@HandleSubmitAsync" StartIcon="@Icons.Material.Filled.Save"> |
||||||
|
Save Trakt List |
||||||
|
</MudButton> |
||||||
|
</MudPaper> |
||||||
|
<div class="d-flex flex-column" style="height: 100vh; overflow-x: auto"> |
||||||
|
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8"> |
||||||
|
<MudText Typo="Typo.h5" Class="mb-2">Trakt List</MudText> |
||||||
|
<MudDivider Class="mb-6"/> |
||||||
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5"> |
||||||
|
<div class="d-flex"> |
||||||
|
<MudText>Id</MudText> |
||||||
|
</div> |
||||||
|
<MudTextField Value="_model.Slug" Disabled="true" /> |
||||||
|
</MudStack> |
||||||
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5"> |
||||||
|
<div class="d-flex"> |
||||||
|
<MudText>Automatic Refresh</MudText> |
||||||
|
</div> |
||||||
|
<MudCheckBox @bind-Value="@_model.AutoRefresh" For="@(() => _model.AutoRefresh)" Dense="true"> |
||||||
|
<MudText Typo="Typo.caption" Style="font-weight: normal">Update list from trakt.tv once each day</MudText> |
||||||
|
</MudCheckBox> |
||||||
|
</MudStack> |
||||||
|
</MudContainer> |
||||||
|
</div> |
||||||
|
</MudForm> |
||||||
|
|
||||||
|
@code { |
||||||
|
private readonly CancellationTokenSource _cts = new(); |
||||||
|
|
||||||
|
[Parameter] |
||||||
|
public int Id { get; set; } |
||||||
|
|
||||||
|
private readonly TraktListEditViewModel _model = new(); |
||||||
|
private MudForm _form; |
||||||
|
private bool _success; |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
_cts.Cancel(); |
||||||
|
_cts.Dispose(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() |
||||||
|
{ |
||||||
|
Option<TraktListViewModel> maybeTraktList = await Mediator.Send(new GetTraktListById(Id), _cts.Token); |
||||||
|
maybeTraktList.Match( |
||||||
|
viewModel => |
||||||
|
{ |
||||||
|
_model.Id = viewModel.Id; |
||||||
|
_model.Slug = viewModel.Slug; |
||||||
|
_model.AutoRefresh = viewModel.AutoRefresh; |
||||||
|
}, |
||||||
|
() => NavigationManager.NavigateTo("404")); |
||||||
|
} |
||||||
|
|
||||||
|
private async Task HandleSubmitAsync() |
||||||
|
{ |
||||||
|
await _form.Validate(); |
||||||
|
if (_success) |
||||||
|
{ |
||||||
|
var request = new UpdateTraktList(_model.Id, _model.AutoRefresh); |
||||||
|
Option<BaseError> result = await Mediator.Send(request, _cts.Token); |
||||||
|
foreach (BaseError error in result) |
||||||
|
{ |
||||||
|
Snackbar.Add(error.Value, Severity.Error); |
||||||
|
Logger.LogError("Unexpected error saving trakt list: {Error}", error.Value); |
||||||
|
} |
||||||
|
|
||||||
|
if (result.IsNone) |
||||||
|
{ |
||||||
|
NavigationManager.NavigateTo("/media/trakt/lists"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue