Browse Source

rebuild playouts when items are added to collections

pull/39/head
Jason Dove 5 years ago
parent
commit
47c920b654
  1. 2
      ErsatzTV.Application/MediaCollections/CollectionUpdateResult.cs
  2. 4
      ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollection.cs
  3. 21
      ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs
  4. 4
      ErsatzTV.Application/MediaCollections/Commands/AddMovieCollection.cs
  5. 21
      ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs
  6. 4
      ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollection.cs
  7. 21
      ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs
  8. 4
      ErsatzTV.Application/MediaCollections/Commands/AddShowToCollection.cs
  9. 21
      ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs
  10. 3
      ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollection.cs
  11. 8
      ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs
  12. 2
      ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs
  13. 2
      ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs
  14. 11
      ErsatzTV.Core/Iptv/ChannelGuide.cs
  15. 2
      ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs
  16. 8
      ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs
  17. 2
      ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs
  18. 5
      ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs
  19. 8
      ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs
  20. 5
      ErsatzTV/Extensions/HostExtensions.cs
  21. 3
      ErsatzTV/Pages/CollectionItems.razor
  22. 17
      ErsatzTV/Pages/MovieList.razor
  23. 25
      ErsatzTV/Pages/Search.razor
  24. 16
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  25. 16
      ErsatzTV/Pages/TelevisionSeasonList.razor
  26. 14
      ErsatzTV/Pages/TelevisionShowList.razor
  27. 2
      ErsatzTV/Shared/MainLayout.razor
  28. 2
      ErsatzTV/Shared/MediaCard.razor
  29. 5
      ErsatzTV/wwwroot/browserconfig.xml
  30. 41
      ErsatzTV/wwwroot/css/site.css

2
ErsatzTV.Application/MediaCollections/CollectionUpdateResult.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
namespace ErsatzTV.Application.MediaCollections
{
public record CollectionUpdateResult
public class CollectionUpdateResult
{
public List<int> ModifiedPlayoutIds { get; set; }
}

4
ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollection.cs

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public record AddEpisodeToCollection(int CollectionId, int EpisodeId) : MediatR.IRequest<Either<BaseError, Unit>>;
public record AddEpisodeToCollection
(int CollectionId, int EpisodeId) : IRequest<Either<BaseError, CollectionUpdateResult>>;
}

21
ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs

@ -3,11 +3,14 @@ using System.Threading.Tasks; @@ -3,11 +3,14 @@ using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using Unit = LanguageExt.Unit;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public class
AddEpisodeToCollectionHandler : MediatR.IRequestHandler<AddEpisodeToCollection, Either<BaseError, Unit>>
AddEpisodeToCollectionHandler : IRequestHandler<AddEpisodeToCollection,
Either<BaseError, CollectionUpdateResult>>
{
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly ITelevisionRepository _televisionRepository;
@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands
_televisionRepository = televisionRepository;
}
public Task<Either<BaseError, Unit>> Handle(
public Task<Either<BaseError, CollectionUpdateResult>> Handle(
AddEpisodeToCollection request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(_ => ApplyAddTelevisionEpisodeRequest(request))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddTelevisionEpisodeRequest(AddEpisodeToCollection request) =>
_mediaCollectionRepository.AddMediaItem(request.CollectionId, request.EpisodeId);
private async Task<CollectionUpdateResult> ApplyAddTelevisionEpisodeRequest(AddEpisodeToCollection request)
{
var result = new CollectionUpdateResult();
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.EpisodeId))
{
result.ModifiedPlayoutIds =
await _mediaCollectionRepository.PlayoutIdsUsingCollection(request.CollectionId);
}
return result;
}
private async Task<Validation<BaseError, Unit>> Validate(AddEpisodeToCollection request) =>
(await CollectionMustExist(request), await ValidateEpisode(request))

4
ErsatzTV.Application/MediaCollections/Commands/AddMovieCollection.cs

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public record AddMovieToCollection(int CollectionId, int MovieId) : MediatR.IRequest<Either<BaseError, Unit>>;
public record AddMovieToCollection
(int CollectionId, int MovieId) : IRequest<Either<BaseError, CollectionUpdateResult>>;
}

21
ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs

@ -4,10 +4,13 @@ using ErsatzTV.Core; @@ -4,10 +4,13 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using Unit = LanguageExt.Unit;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public class AddMovieToCollectionHandler : MediatR.IRequestHandler<AddMovieToCollection, Either<BaseError, Unit>>
public class
AddMovieToCollectionHandler : IRequestHandler<AddMovieToCollection, Either<BaseError, CollectionUpdateResult>>
{
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly IMovieRepository _movieRepository;
@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands
_movieRepository = movieRepository;
}
public Task<Either<BaseError, Unit>> Handle(
public Task<Either<BaseError, CollectionUpdateResult>> Handle(
AddMovieToCollection request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(_ => ApplyAddMoviesRequest(request))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddMoviesRequest(AddMovieToCollection request) =>
_mediaCollectionRepository.AddMediaItem(request.CollectionId, request.MovieId);
private async Task<CollectionUpdateResult> ApplyAddMoviesRequest(AddMovieToCollection request)
{
var result = new CollectionUpdateResult();
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.MovieId))
{
result.ModifiedPlayoutIds =
await _mediaCollectionRepository.PlayoutIdsUsingCollection(request.CollectionId);
}
return result;
}
private async Task<Validation<BaseError, Unit>> Validate(AddMovieToCollection request) =>
(await CollectionMustExist(request), await ValidateMovies(request))

4
ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollection.cs

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public record AddSeasonToCollection(int CollectionId, int SeasonId) : MediatR.IRequest<Either<BaseError, Unit>>;
public record AddSeasonToCollection
(int CollectionId, int SeasonId) : IRequest<Either<BaseError, CollectionUpdateResult>>;
}

21
ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs

@ -4,10 +4,13 @@ using ErsatzTV.Core; @@ -4,10 +4,13 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using Unit = LanguageExt.Unit;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public class AddSeasonToCollectionHandler : MediatR.IRequestHandler<AddSeasonToCollection, Either<BaseError, Unit>>
public class
AddSeasonToCollectionHandler : IRequestHandler<AddSeasonToCollection, Either<BaseError, CollectionUpdateResult>>
{
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly ITelevisionRepository _televisionRepository;
@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands
_televisionRepository = televisionRepository;
}
public Task<Either<BaseError, Unit>> Handle(
public Task<Either<BaseError, CollectionUpdateResult>> Handle(
AddSeasonToCollection request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(_ => ApplyAddTelevisionSeasonRequest(request))
.Bind(v => v.ToEitherAsync());
private async Task<Unit> ApplyAddTelevisionSeasonRequest(AddSeasonToCollection request) =>
await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.SeasonId);
private async Task<CollectionUpdateResult> ApplyAddTelevisionSeasonRequest(AddSeasonToCollection request)
{
var result = new CollectionUpdateResult();
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.SeasonId))
{
result.ModifiedPlayoutIds =
await _mediaCollectionRepository.PlayoutIdsUsingCollection(request.CollectionId);
}
return result;
}
private async Task<Validation<BaseError, Unit>> Validate(AddSeasonToCollection request) =>
(await CollectionMustExist(request), await ValidateSeason(request))

4
ErsatzTV.Application/MediaCollections/Commands/AddShowToCollection.cs

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public record AddShowToCollection(int CollectionId, int ShowId) : MediatR.IRequest<Either<BaseError, Unit>>;
public record AddShowToCollection
(int CollectionId, int ShowId) : IRequest<Either<BaseError, CollectionUpdateResult>>;
}

21
ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs

@ -4,10 +4,13 @@ using ErsatzTV.Core; @@ -4,10 +4,13 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using Unit = LanguageExt.Unit;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public class AddShowToCollectionHandler : MediatR.IRequestHandler<AddShowToCollection, Either<BaseError, Unit>>
public class
AddShowToCollectionHandler : IRequestHandler<AddShowToCollection, Either<BaseError, CollectionUpdateResult>>
{
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly ITelevisionRepository _televisionRepository;
@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -20,15 +23,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands
_televisionRepository = televisionRepository;
}
public Task<Either<BaseError, Unit>> Handle(
public Task<Either<BaseError, CollectionUpdateResult>> Handle(
AddShowToCollection request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(_ => ApplyAddTelevisionShowRequest(request))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddTelevisionShowRequest(AddShowToCollection request)
=> _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.ShowId);
private async Task<CollectionUpdateResult> ApplyAddTelevisionShowRequest(AddShowToCollection request)
{
var result = new CollectionUpdateResult();
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.ShowId))
{
result.ModifiedPlayoutIds =
await _mediaCollectionRepository.PlayoutIdsUsingCollection(request.CollectionId);
}
return result;
}
private async Task<Validation<BaseError, Unit>> Validate(AddShowToCollection request) =>
(await CollectionMustExist(request), await ValidateShow(request))

3
ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollection.cs

@ -1,10 +1,11 @@ @@ -1,10 +1,11 @@
using System.Collections.Generic;
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public record RemoveItemsFromCollection(int MediaCollectionId) : MediatR.IRequest<Either<BaseError, CollectionUpdateResult>>
public record RemoveItemsFromCollection(int MediaCollectionId) : IRequest<Either<BaseError, CollectionUpdateResult>>
{
public List<int> MediaItemIds { get; set; } = new();
}

8
ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs

@ -36,15 +36,13 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -36,15 +36,13 @@ namespace ErsatzTV.Application.MediaCollections.Commands
itemsToRemove.ForEach(m => collection.MediaItems.Remove(m));
var result = new CollectionUpdateResult();
if (itemsToRemove.Any() && await _mediaCollectionRepository.Update(collection))
{
return new CollectionUpdateResult
{
ModifiedPlayoutIds = await _mediaCollectionRepository.PlayoutIdsUsingCollection(collection.Id)
};
result.ModifiedPlayoutIds = await _mediaCollectionRepository.PlayoutIdsUsingCollection(collection.Id);
}
return new CollectionUpdateResult();
return result;
}
private Task<Validation<BaseError, Collection>> Validate(

2
ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs

@ -15,7 +15,7 @@ namespace ErsatzTV.Core.Tests.Fakes @@ -15,7 +15,7 @@ namespace ErsatzTV.Core.Tests.Fakes
public FakeMediaCollectionRepository(Map<int, List<MediaItem>> data) => _data = data;
public Task<Collection> Add(Collection collection) => throw new NotSupportedException();
public Task<Unit> AddMediaItem(int collectionId, int mediaItemId) => throw new NotSupportedException();
public Task<bool> AddMediaItem(int collectionId, int mediaItemId) => throw new NotSupportedException();
public Task<Option<Collection>> Get(int id) => throw new NotSupportedException();
public Task<Option<Collection>> GetCollectionWithItems(int id) => throw new NotSupportedException();
public Task<Option<Collection>> GetCollectionWithItemsUntracked(int id) => throw new NotSupportedException();

2
ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs

@ -8,7 +8,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories @@ -8,7 +8,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories
public interface IMediaCollectionRepository
{
Task<Collection> Add(Collection collection);
Task<Unit> AddMediaItem(int collectionId, int mediaItemId);
Task<bool> AddMediaItem(int collectionId, int mediaItemId);
Task<Option<Collection>> Get(int id);
Task<Option<Collection>> GetCollectionWithItems(int id);
Task<Option<Collection>> GetCollectionWithItemsUntracked(int id);

11
ErsatzTV.Core/Iptv/ChannelGuide.cs

@ -62,15 +62,18 @@ namespace ErsatzTV.Core.Iptv @@ -62,15 +62,18 @@ namespace ErsatzTV.Core.Iptv
string title = playoutItem.MediaItem switch
{
Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Title ?? string.Empty).IfNone("[unknown movie]"),
Episode e => e.EpisodeMetadata.HeadOrNone().Map(em => em.Title ?? string.Empty).IfNone("[unknown episode]"),
Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Title ?? string.Empty)
.IfNone("[unknown movie]"),
Episode e => e.EpisodeMetadata.HeadOrNone().Map(em => em.Title ?? string.Empty)
.IfNone("[unknown episode]"),
_ => "[unknown]"
};
string description = playoutItem.MediaItem switch
{
Movie m => m.MovieMetadata.HeadOrNone().Map(mm => mm.Plot ?? string.Empty).IfNone(string.Empty),
Episode e => e.EpisodeMetadata.HeadOrNone().Map(em => em.Plot ?? string.Empty).IfNone(string.Empty),
Episode e => e.EpisodeMetadata.HeadOrNone().Map(em => em.Plot ?? string.Empty)
.IfNone(string.Empty),
_ => string.Empty
};
@ -108,7 +111,7 @@ namespace ErsatzTV.Core.Iptv @@ -108,7 +111,7 @@ namespace ErsatzTV.Core.Iptv
xml.WriteAttributeString("system", "onscreen");
xml.WriteString($"S{s:00}E{e:00}");
xml.WriteEndElement(); // episode-num
xml.WriteStartElement("episode-num");
xml.WriteAttributeString("system", "xmltv_ns");
xml.WriteString($"{s - 1}.{e - 1}.0/1");

2
ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs

@ -34,7 +34,7 @@ namespace ErsatzTV.Core.Metadata @@ -34,7 +34,7 @@ namespace ErsatzTV.Core.Metadata
return fileName != null ? GetMovieMetadata(fileName, metadata) : metadata;
}
public string GetSortTitle(string title)
{
if (string.IsNullOrWhiteSpace(title))

8
ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs

@ -30,8 +30,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -30,8 +30,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
}
public async Task<Unit> AddMediaItem(int collectionId, int mediaItemId)
public async Task<bool> AddMediaItem(int collectionId, int mediaItemId)
{
var modified = false;
Option<Collection> maybeCollection = await _dbContext.Collections
.Include(c => c.MediaItems)
.OrderBy(c => c.Id)
@ -52,12 +54,12 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -52,12 +54,12 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
async mediaItem =>
{
collection.MediaItems.Add(mediaItem);
await _dbContext.SaveChangesAsync();
modified = await _dbContext.SaveChangesAsync() > 0;
});
}
});
return Unit.Default;
return modified;
}
public Task<Option<Collection>> Get(int id) =>

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

@ -173,7 +173,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -173,7 +173,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
await _dbConnection.ExecuteAsync(
"UPDATE PlexLibrary SET ShouldSyncItems = 0 WHERE Id IN @ids",
new { ids = libraryIds });
await _dbConnection.ExecuteAsync(
"UPDATE Library SET LastScan = null WHERE Id IN @ids",
new { ids = libraryIds });

5
ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs

@ -122,7 +122,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -122,7 +122,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
}
}
private async Task<Either<BaseError, PlexMovie>> AddPlexMovie(TvContext context, PlexLibrary library, PlexMovie item)
private async Task<Either<BaseError, PlexMovie>> AddPlexMovie(
TvContext context,
PlexLibrary library,
PlexMovie item)
{
try
{

8
ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs

@ -18,10 +18,8 @@ namespace ErsatzTV.Infrastructure.Plex @@ -18,10 +18,8 @@ namespace ErsatzTV.Infrastructure.Plex
{
private readonly IFallbackMetadataProvider _fallbackMetadataProvider;
public PlexServerApiClient(IFallbackMetadataProvider fallbackMetadataProvider)
{
public PlexServerApiClient(IFallbackMetadataProvider fallbackMetadataProvider) =>
_fallbackMetadataProvider = fallbackMetadataProvider;
}
public async Task<Either<BaseError, List<PlexLibrary>>> GetLibraries(
PlexConnection connection,
@ -150,7 +148,7 @@ namespace ErsatzTV.Infrastructure.Plex @@ -150,7 +148,7 @@ namespace ErsatzTV.Infrastructure.Plex
}
private static string ConvertToSAR(double aspectRatio) => "1:1";
// TODO: fix this with more detailed stats pull from plex for each item
// Math.Abs(aspectRatio - 1) < 0.01 ? "1:1" : $"{(int) (aspectRatio * 100)}:100";
// TODO: fix this with more detailed stats pull from plex for each item
// Math.Abs(aspectRatio - 1) < 0.01 ? "1:1" : $"{(int) (aspectRatio * 100)}:100";
}
}

5
ErsatzTV/Extensions/HostExtensions.cs

@ -36,7 +36,10 @@ namespace ErsatzTV.Extensions @@ -36,7 +36,10 @@ namespace ErsatzTV.Extensions
.IfFail(
ex =>
{
LogException(ex, "Error occured while migrating database; shutting down.", scope.ServiceProvider);
LogException(
ex,
"Error occured while migrating database; shutting down.",
scope.ServiceProvider);
Environment.Exit(13);
return unit;
});

3
ErsatzTV/Pages/CollectionItems.razor

@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
@inject ILogger<CollectionItems> Logger
@inject ISnackbar Snackbar
@inject IDialogService Dialog
@inject ChannelWriter<IBackgroundServiceRequest> Channel
<div class="mb-6" style="display: flex; flex-direction: row;">
<MudText GutterBottom="true" Typo="Typo.h2">@_data.Name</MudText>
@ -169,7 +170,7 @@ @@ -169,7 +170,7 @@
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Mediator.Send(new BuildPlayout(playoutId, true));
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
},
_ => Task.CompletedTask);

17
ErsatzTV/Pages/MovieList.razor

@ -4,12 +4,13 @@ @@ -4,12 +4,13 @@
@using ErsatzTV.Application.MediaCards.Queries
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using Unit = LanguageExt.Unit
@using ErsatzTV.Application.Playouts.Commands
@inject ILogger<MovieList> Logger
@inject ISnackbar Snackbar
@inject IMediator Mediator
@inject IDialogService Dialog
@inject NavigationManager NavigationManager
@inject ChannelWriter<IBackgroundServiceRequest> Channel
<MudContainer MaxWidth="MaxWidth.Small" Class="mb-6" Style="max-width: 300px">
<MudPaper Style="align-items: center; display: flex; justify-content: center;">
@ -73,14 +74,22 @@ @@ -73,14 +74,22 @@
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
{
var request = new AddMovieToCollection(collection.Id, movie.MovieId);
Either<BaseError, Unit> addResult = await Mediator.Send(request);
addResult.Match(
Either<BaseError, CollectionUpdateResult> addResult = await Mediator.Send(request);
await addResult.Match(
Left: error =>
{
Snackbar.Add($"Unexpected error adding movie to collection: {error.Value}");
Logger.LogError("Unexpected error adding movie to collection: {Error}", error.Value);
return Task.CompletedTask;
},
Right: _ => Snackbar.Add($"Added {movie.Title} to collection {collection.Name}", Severity.Success));
Right: async collectionUpdateResult =>
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
Snackbar.Add($"Added {movie.Title} to collection {collection.Name}", Severity.Success);
});
}
}
}

25
ErsatzTV/Pages/Search.razor

@ -3,14 +3,15 @@ @@ -3,14 +3,15 @@
@using ErsatzTV.Application.MediaCards.Queries
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Playouts.Commands
@using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Primitives
@using Unit = LanguageExt.Unit
@inject NavigationManager NavigationManager
@inject IMediator Mediator
@inject ILogger<Search> Logger
@inject ISnackbar Snackbar
@inject IDialogService Dialog
@inject ChannelWriter<IBackgroundServiceRequest> Channel
<MudContainer MaxWidth="MaxWidth.ExtraLarge">
<div class="mb-6" style="display: flex; flex-direction: row;">
@ -74,14 +75,21 @@ @@ -74,14 +75,21 @@
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, CollectionUpdateResult> addResult = await Mediator.Send(request);
addResult.Match(
Left: error =>
{
Snackbar.Add($"Unexpected error adding movie to collection: {error.Value}");
Logger.LogError("Unexpected error adding movie to collection: {Error}", error.Value);
},
Right: _ => Snackbar.Add($"Added {movie.Title} to collection {collection.Name}", Severity.Success));
Right: async collectionUpdateResult =>
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
Snackbar.Add($"Added {movie.Title} to collection {collection.Name}", Severity.Success);
});
}
}
@ -95,14 +103,21 @@ @@ -95,14 +103,21 @@
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, CollectionUpdateResult> addResult = await Mediator.Send(request);
addResult.Match(
Left: error =>
{
Snackbar.Add($"Unexpected error adding show to collection: {error.Value}");
Logger.LogError("Unexpected error adding show to collection: {Error}", error.Value);
},
Right: _ => Snackbar.Add($"Added {show.Title} to collection {collection.Name}", Severity.Success));
Right: async collectionUpdateResult =>
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
Snackbar.Add($"Added {show.Title} to collection {collection.Name}", Severity.Success);
});
}
}
}

16
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -5,14 +5,15 @@ @@ -5,14 +5,15 @@
@using ErsatzTV.Application.MediaCards.Queries
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Playouts.Commands
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands
@using Unit=LanguageExt.Unit;
@inject IMediator Mediator
@inject ILogger<TelevisionEpisodeList> Logger
@inject ISnackbar Snackbar
@inject IDialogService Dialog
@inject NavigationManager NavigationManager
@inject ChannelWriter<IBackgroundServiceRequest> Channel
<MudContainer MaxWidth="MaxWidth.Large">
<MudBreadcrumbs Items="_breadcrumbs" Class="mb-6"></MudBreadcrumbs>
@ -122,7 +123,7 @@ @@ -122,7 +123,7 @@
NavigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
}
}
private async Task AddEpisodeToCollection(MediaCardViewModel card)
{
if (card is TelevisionEpisodeCardViewModel episode)
@ -135,14 +136,21 @@ @@ -135,14 +136,21 @@
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, CollectionUpdateResult> addResult = await Mediator.Send(request);
addResult.Match(
Left: error =>
{
Snackbar.Add($"Unexpected error adding episode to collection: {error.Value}");
Logger.LogError("Unexpected error adding episode to collection: {Error}", error.Value);
},
Right: _ => Snackbar.Add($"Added {episode.Title} to collection {collection.Name}", Severity.Success));
Right: async collectionUpdateResult =>
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
Snackbar.Add($"Added {episode.Title} to collection {collection.Name}", Severity.Success);
});
}
}
}

16
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -5,14 +5,15 @@ @@ -5,14 +5,15 @@
@using ErsatzTV.Application.MediaCards.Queries
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.Playouts.Commands
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands
@using Unit=LanguageExt.Unit;
@inject IMediator Mediator
@inject ILogger<TelevisionSeasonList> Logger
@inject ISnackbar Snackbar
@inject IDialogService Dialog
@inject NavigationManager NavigationManager
@inject ChannelWriter<IBackgroundServiceRequest> Channel
<MudContainer MaxWidth="MaxWidth.Large">
<MudBreadcrumbs Items="_breadcrumbs" Class="mb-6"></MudBreadcrumbs>
@ -116,7 +117,7 @@ @@ -116,7 +117,7 @@
NavigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
}
}
private async Task AddSeasonToCollection(MediaCardViewModel card)
{
if (card is TelevisionSeasonCardViewModel season)
@ -129,14 +130,21 @@ @@ -129,14 +130,21 @@
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, CollectionUpdateResult> addResult = await Mediator.Send(request);
addResult.Match(
Left: error =>
{
Snackbar.Add($"Unexpected error adding season to collection: {error.Value}");
Logger.LogError("Unexpected error adding season to collection: {Error}", error.Value);
},
Right: _ => Snackbar.Add($"Added {season.Title} to collection {collection.Name}", Severity.Success));
Right: async collectionUpdateResult =>
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
Snackbar.Add($"Added {season.Title} to collection {collection.Name}", Severity.Success);
});
}
}
}

14
ErsatzTV/Pages/TelevisionShowList.razor

@ -3,11 +3,12 @@ @@ -3,11 +3,12 @@
@using ErsatzTV.Application.MediaCards.Queries
@using ErsatzTV.Application.MediaCollections
@using ErsatzTV.Application.MediaCollections.Commands
@using Unit = LanguageExt.Unit
@using ErsatzTV.Application.Playouts.Commands
@inject ILogger<TelevisionShowList> Logger
@inject ISnackbar Snackbar
@inject IMediator Mediator
@inject IDialogService Dialog
@inject ChannelWriter<IBackgroundServiceRequest> Channel
<MudContainer MaxWidth="MaxWidth.Small" Class="mb-6" Style="max-width: 300px">
<MudPaper Style="align-items: center; display: flex; justify-content: center;">
@ -69,14 +70,21 @@ @@ -69,14 +70,21 @@
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, CollectionUpdateResult> addResult = await Mediator.Send(request);
addResult.Match(
Left: error =>
{
Snackbar.Add($"Unexpected error adding show to collection: {error.Value}");
Logger.LogError("Unexpected error adding show to collection: {Error}", error.Value);
},
Right: _ => Snackbar.Add($"Added {show.Title} to collection {collection.Name}", Severity.Success));
Right: async collectionUpdateResult =>
{
foreach (int playoutId in collectionUpdateResult.ModifiedPlayoutIds)
{
await Channel.WriteAsync(new BuildPlayout(playoutId, true));
}
Snackbar.Add($"Added {show.Title} to collection {collection.Name}", Severity.Success);
});
}
}
}

2
ErsatzTV/Shared/MainLayout.razor

@ -67,7 +67,7 @@ @@ -67,7 +67,7 @@
private static readonly string InfoVersion = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "unknown";
private MudTextField<string> _textField;
private MudTheme _ersatzTvTheme
{
get

2
ErsatzTV/Shared/MediaCard.razor

@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
{
<MudIconButton Color="Color.Tertiary"
Icon="@Icons.Material.Filled.PlaylistAdd"
Style="bottom: 0; position: absolute; left: 0;"
Style="bottom: 0; left: 0; position: absolute;"
OnClick="@(() => AddToCollectionClicked.InvokeAsync(Data))"/>
}
@if (DeleteClicked.HasDelegate)

5
ErsatzTV/wwwroot/browserconfig.xml

@ -1,9 +1,10 @@ @@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<square150x150logo src="/mstile-150x150.png" />
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>
</browserconfig>

41
ErsatzTV/wwwroot/css/site.css

@ -4,13 +4,9 @@ @@ -4,13 +4,9 @@
flex-wrap: wrap;
}
.media-card-container {
width: 152px;
}
.media-card-container { width: 152px; }
.media-card-episode-container {
width: 392px;
}
.media-card-episode-container { width: 392px; }
.media-card {
display: flex;
@ -22,12 +18,9 @@ @@ -22,12 +18,9 @@
width: 152px;
}
.media-card-episode {
width: 392px;
}
.media-card-episode { width: 392px; }
.media-card:hover { /*filter: brightness(75%);*/
}
.media-card:hover { /*filter: brightness(75%);*/ }
.media-card-title {
overflow: hidden;
@ -36,9 +29,7 @@ @@ -36,9 +29,7 @@
width: 100%;
}
.media-card-poster-placeholder {
font-weight: bold;
}
.media-card-poster-placeholder { font-weight: bold; }
.media-card-menu {
bottom: 0;
@ -47,9 +38,7 @@ @@ -47,9 +38,7 @@
right: 0;
}
.media-card:hover .media-card-menu {
display: block;
}
.media-card:hover .media-card-menu { display: block; }
.media-card-overlay {
background: rgba(0, 0, 0, 0.4);
@ -63,26 +52,20 @@ @@ -63,26 +52,20 @@
transition: opacity 0.2s;
}
.media-card-overlay:hover {
opacity: 1;
}
.media-card-overlay:hover { opacity: 1; }
.search-bar .mud-input {
height: 42px;
}
.search-bar .mud-input { height: 42px; }
.search-bar {
background-color: rgba(255, 255, 255, .15);
margin-bottom: 5px;
height: 42px;
border-radius: 4px;
height: 42px;
margin-bottom: 5px;
}
.search-bar div .mud-input-root {
color: #fafafa;
}
.search-bar div .mud-input-root { color: #fafafa; }
.search-bar .mud-input.mud-input-outlined .mud-input-outlined-border {
border: none;
border-radius: 4px;
}
}
Loading…
Cancel
Save