Browse Source

Rebuild playouts with modified collections (#39)

* rebuild playouts when items are removed from collections

* rebuild playouts when items are added to collections

* simplify logic
pull/1213/head
Jason Dove 5 years ago committed by GitHub
parent
commit
187f24ca6c
  1. 23
      ErsatzTV.Application/MediaCollections/Commands/AddEpisodeToCollectionHandler.cs
  2. 26
      ErsatzTV.Application/MediaCollections/Commands/AddMovieToCollectionHandler.cs
  3. 26
      ErsatzTV.Application/MediaCollections/Commands/AddSeasonToCollectionHandler.cs
  4. 25
      ErsatzTV.Application/MediaCollections/Commands/AddShowToCollectionHandler.cs
  5. 26
      ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs
  6. 14
      ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs
  7. 5
      ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs
  8. 11
      ErsatzTV.Core/Iptv/ChannelGuide.cs
  9. 2
      ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs
  10. 22
      ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs
  11. 2
      ErsatzTV.Infrastructure/Data/Repositories/MediaSourceRepository.cs
  12. 5
      ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs
  13. 8
      ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs
  14. 5
      ErsatzTV/Extensions/HostExtensions.cs
  15. 1
      ErsatzTV/Pages/CollectionItems.razor
  16. 1
      ErsatzTV/Pages/MovieList.razor
  17. 1
      ErsatzTV/Pages/Search.razor
  18. 5
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  19. 5
      ErsatzTV/Pages/TelevisionSeasonList.razor
  20. 1
      ErsatzTV/Pages/TelevisionShowList.razor
  21. 2
      ErsatzTV/Shared/MainLayout.razor
  22. 2
      ErsatzTV/Shared/MediaCard.razor
  23. 5
      ErsatzTV/wwwroot/browserconfig.xml
  24. 41
      ErsatzTV/wwwroot/css/site.css

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

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
@ -9,15 +11,18 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -9,15 +11,18 @@ namespace ErsatzTV.Application.MediaCollections.Commands
public class
AddEpisodeToCollectionHandler : MediatR.IRequestHandler<AddEpisodeToCollection, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly ITelevisionRepository _televisionRepository;
public AddEpisodeToCollectionHandler(
IMediaCollectionRepository mediaCollectionRepository,
ITelevisionRepository televisionRepository)
ITelevisionRepository televisionRepository,
ChannelWriter<IBackgroundServiceRequest> channel)
{
_mediaCollectionRepository = mediaCollectionRepository;
_televisionRepository = televisionRepository;
_channel = channel;
}
public Task<Either<BaseError, Unit>> Handle(
@ -27,8 +32,20 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -27,8 +32,20 @@ namespace ErsatzTV.Application.MediaCollections.Commands
.MapT(_ => ApplyAddTelevisionEpisodeRequest(request))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddTelevisionEpisodeRequest(AddEpisodeToCollection request) =>
_mediaCollectionRepository.AddMediaItem(request.CollectionId, request.EpisodeId);
private async Task<Unit> ApplyAddTelevisionEpisodeRequest(AddEpisodeToCollection request)
{
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.EpisodeId))
{
// rebuild all playouts that use this collection
foreach (int playoutId in await _mediaCollectionRepository
.PlayoutIdsUsingCollection(request.CollectionId))
{
await _channel.WriteAsync(new BuildPlayout(playoutId, true));
}
}
return Unit.Default;
}
private async Task<Validation<BaseError, Unit>> Validate(AddEpisodeToCollection request) =>
(await CollectionMustExist(request), await ValidateEpisode(request))

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

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -7,17 +9,21 @@ using LanguageExt; @@ -7,17 +9,21 @@ using LanguageExt;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public class AddMovieToCollectionHandler : MediatR.IRequestHandler<AddMovieToCollection, Either<BaseError, Unit>>
public class
AddMovieToCollectionHandler : MediatR.IRequestHandler<AddMovieToCollection, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly IMovieRepository _movieRepository;
public AddMovieToCollectionHandler(
IMediaCollectionRepository mediaCollectionRepository,
IMovieRepository movieRepository)
IMovieRepository movieRepository,
ChannelWriter<IBackgroundServiceRequest> channel)
{
_mediaCollectionRepository = mediaCollectionRepository;
_movieRepository = movieRepository;
_channel = channel;
}
public Task<Either<BaseError, Unit>> Handle(
@ -27,8 +33,20 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -27,8 +33,20 @@ namespace ErsatzTV.Application.MediaCollections.Commands
.MapT(_ => ApplyAddMoviesRequest(request))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddMoviesRequest(AddMovieToCollection request) =>
_mediaCollectionRepository.AddMediaItem(request.CollectionId, request.MovieId);
private async Task<Unit> ApplyAddMoviesRequest(AddMovieToCollection request)
{
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.MovieId))
{
// rebuild all playouts that use this collection
foreach (int playoutId in await _mediaCollectionRepository
.PlayoutIdsUsingCollection(request.CollectionId))
{
await _channel.WriteAsync(new BuildPlayout(playoutId, true));
}
}
return Unit.Default;
}
private async Task<Validation<BaseError, Unit>> Validate(AddMovieToCollection request) =>
(await CollectionMustExist(request), await ValidateMovies(request))

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

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -7,17 +9,21 @@ using LanguageExt; @@ -7,17 +9,21 @@ using LanguageExt;
namespace ErsatzTV.Application.MediaCollections.Commands
{
public class AddSeasonToCollectionHandler : MediatR.IRequestHandler<AddSeasonToCollection, Either<BaseError, Unit>>
public class
AddSeasonToCollectionHandler : MediatR.IRequestHandler<AddSeasonToCollection, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly ITelevisionRepository _televisionRepository;
public AddSeasonToCollectionHandler(
IMediaCollectionRepository mediaCollectionRepository,
ITelevisionRepository televisionRepository)
ITelevisionRepository televisionRepository,
ChannelWriter<IBackgroundServiceRequest> channel)
{
_mediaCollectionRepository = mediaCollectionRepository;
_televisionRepository = televisionRepository;
_channel = channel;
}
public Task<Either<BaseError, Unit>> Handle(
@ -27,8 +33,20 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -27,8 +33,20 @@ namespace ErsatzTV.Application.MediaCollections.Commands
.MapT(_ => ApplyAddTelevisionSeasonRequest(request))
.Bind(v => v.ToEitherAsync());
private async Task<Unit> ApplyAddTelevisionSeasonRequest(AddSeasonToCollection request) =>
await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.SeasonId);
private async Task<Unit> ApplyAddTelevisionSeasonRequest(AddSeasonToCollection request)
{
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.SeasonId))
{
// rebuild all playouts that use this collection
foreach (int playoutId in await _mediaCollectionRepository
.PlayoutIdsUsingCollection(request.CollectionId))
{
await _channel.WriteAsync(new BuildPlayout(playoutId, true));
}
}
return Unit.Default;
}
private async Task<Validation<BaseError, Unit>> Validate(AddSeasonToCollection request) =>
(await CollectionMustExist(request), await ValidateSeason(request))

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

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -9,15 +11,18 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -9,15 +11,18 @@ namespace ErsatzTV.Application.MediaCollections.Commands
{
public class AddShowToCollectionHandler : MediatR.IRequestHandler<AddShowToCollection, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
private readonly ITelevisionRepository _televisionRepository;
public AddShowToCollectionHandler(
IMediaCollectionRepository mediaCollectionRepository,
ITelevisionRepository televisionRepository)
ITelevisionRepository televisionRepository,
ChannelWriter<IBackgroundServiceRequest> channel)
{
_mediaCollectionRepository = mediaCollectionRepository;
_televisionRepository = televisionRepository;
_channel = channel;
}
public Task<Either<BaseError, Unit>> Handle(
@ -27,8 +32,22 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -27,8 +32,22 @@ namespace ErsatzTV.Application.MediaCollections.Commands
.MapT(_ => ApplyAddTelevisionShowRequest(request))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddTelevisionShowRequest(AddShowToCollection request)
=> _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.ShowId);
private async Task<Unit> ApplyAddTelevisionShowRequest(AddShowToCollection request)
{
var result = new Unit();
if (await _mediaCollectionRepository.AddMediaItem(request.CollectionId, request.ShowId))
{
// rebuild all playouts that use this collection
foreach (int playoutId in await _mediaCollectionRepository
.PlayoutIdsUsingCollection(request.CollectionId))
{
await _channel.WriteAsync(new BuildPlayout(playoutId, true));
}
}
return result;
}
private async Task<Validation<BaseError, Unit>> Validate(AddShowToCollection request) =>
(await CollectionMustExist(request), await ValidateShow(request))

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

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
using System.Linq;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
@ -11,20 +13,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -11,20 +13,25 @@ namespace ErsatzTV.Application.MediaCollections.Commands
public class
RemoveItemsFromCollectionHandler : MediatR.IRequestHandler<RemoveItemsFromCollection, Either<BaseError, Unit>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IMediaCollectionRepository _mediaCollectionRepository;
public RemoveItemsFromCollectionHandler(
IMediaCollectionRepository mediaCollectionRepository) =>
IMediaCollectionRepository mediaCollectionRepository,
ChannelWriter<IBackgroundServiceRequest> channel)
{
_mediaCollectionRepository = mediaCollectionRepository;
_channel = channel;
}
public Task<Either<BaseError, Unit>> Handle(
RemoveItemsFromCollection request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(collection => ApplyAddTelevisionEpisodeRequest(request, collection))
.MapT(collection => ApplyRemoveItemsRequest(request, collection))
.Bind(v => v.ToEitherAsync());
private Task<Unit> ApplyAddTelevisionEpisodeRequest(
private async Task<Unit> ApplyRemoveItemsRequest(
RemoveItemsFromCollection request,
Collection collection)
{
@ -34,9 +41,16 @@ namespace ErsatzTV.Application.MediaCollections.Commands @@ -34,9 +41,16 @@ namespace ErsatzTV.Application.MediaCollections.Commands
itemsToRemove.ForEach(m => collection.MediaItems.Remove(m));
return itemsToRemove.Any()
? _mediaCollectionRepository.Update(collection).ToUnit()
: Task.FromResult(Unit.Default);
if (itemsToRemove.Any() && await _mediaCollectionRepository.Update(collection))
{
// rebuild all playouts that use this collection
foreach (int playoutId in await _mediaCollectionRepository.PlayoutIdsUsingCollection(collection.Id))
{
await _channel.WriteAsync(new BuildPlayout(playoutId, true));
}
}
return Unit.Default;
}
private Task<Validation<BaseError, Collection>> Validate(

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

@ -14,23 +14,15 @@ namespace ErsatzTV.Core.Tests.Fakes @@ -14,23 +14,15 @@ namespace ErsatzTV.Core.Tests.Fakes
private readonly Map<int, List<MediaItem>> _data;
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();
public Task<List<Collection>> GetAll() => throw new NotSupportedException();
public Task<Option<List<MediaItem>>> GetItems(int id) => Some(_data[id].ToList()).AsTask();
public Task Update(Collection collection) => throw new NotSupportedException();
Task<bool> IMediaCollectionRepository.Update(Collection collection) => throw new NotSupportedException();
public Task Delete(int collectionId) => throw new NotSupportedException();
public Task<Option<List<MediaItem>>> GetSimpleMediaCollectionItems(int id) => throw new NotSupportedException();
public Task<List<int>> PlayoutIdsUsingCollection(int collectionId) => throw new NotSupportedException();
}
}

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

@ -8,13 +8,14 @@ namespace ErsatzTV.Core.Interfaces.Repositories @@ -8,13 +8,14 @@ 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);
Task<List<Collection>> GetAll();
Task<Option<List<MediaItem>>> GetItems(int id);
Task Update(Collection collection);
Task<bool> Update(Collection collection);
Task Delete(int collectionId);
Task<List<int>> PlayoutIdsUsingCollection(int collectionId);
}
}

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))

22
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) =>
@ -121,10 +123,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -121,10 +123,10 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
public Task<Option<List<MediaItem>>> GetItems(int id) =>
Get(id).MapT(GetItemsForCollection).Bind(x => x.Sequence());
public Task Update(Collection collection)
public Task<bool> Update(Collection collection)
{
_dbContext.Collections.Update(collection);
return _dbContext.SaveChangesAsync();
return _dbContext.SaveChangesAsync().Map(result => result > 0);
}
public async Task Delete(int collectionId)
@ -134,6 +136,16 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -134,6 +136,16 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
await _dbContext.SaveChangesAsync();
}
public Task<List<int>> PlayoutIdsUsingCollection(int collectionId) =>
_dbConnection.QueryAsync<int>(
@"SELECT DISTINCT p.Id
FROM Playout p
INNER JOIN ProgramSchedule PS on p.ProgramScheduleId = PS.Id
INNER JOIN ProgramScheduleItem PSI on p.Anchor_NextScheduleItemId = PSI.Id
WHERE PSI.CollectionId = @CollectionId",
new { CollectionId = collectionId })
.Map(result => result.ToList());
private async Task<List<MediaItem>> GetItemsForCollection(Collection collection)
{
var result = new List<MediaItem>();

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;
});

1
ErsatzTV/Pages/CollectionItems.razor

@ -7,6 +7,7 @@ @@ -7,6 +7,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>

1
ErsatzTV/Pages/MovieList.razor

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
@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;">

1
ErsatzTV/Pages/Search.razor

@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
@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;">

5
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -7,12 +7,13 @@ @@ -7,12 +7,13 @@
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands
@using Unit=LanguageExt.Unit;
@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)

5
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -7,12 +7,13 @@ @@ -7,12 +7,13 @@
@using ErsatzTV.Application.MediaCollections.Commands
@using ErsatzTV.Application.ProgramSchedules
@using ErsatzTV.Application.ProgramSchedules.Commands
@using Unit=LanguageExt.Unit;
@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)

1
ErsatzTV/Pages/TelevisionShowList.razor

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
@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;">

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