Browse Source

add guide mode to schedule items (#430)

pull/431/head
Jason Dove 4 years ago committed by GitHub
parent
commit
3ecdd741a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 3
      ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs
  3. 1
      ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs
  4. 12
      ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs
  5. 3
      ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs
  6. 12
      ErsatzTV.Application/ProgramSchedules/Mapper.cs
  7. 6
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs
  8. 6
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs
  9. 6
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs
  10. 6
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs
  11. 3
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs
  12. 8
      ErsatzTV.Core/Domain/GuideMode.cs
  13. 1
      ErsatzTV.Core/Domain/ProgramScheduleItem.cs
  14. 2
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  15. 3510
      ErsatzTV.Infrastructure/Migrations/20211014180849_Add_ProgramScheduleItem_GuideMode.Designer.cs
  16. 24
      ErsatzTV.Infrastructure/Migrations/20211014180849_Add_ProgramScheduleItem_GuideMode.cs
  17. 3
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs
  18. 2
      ErsatzTV/Pages/Artist.razor
  19. 8
      ErsatzTV/Pages/ScheduleItemsEditor.razor
  20. 2
      ErsatzTV/Pages/TelevisionEpisodeList.razor
  21. 2
      ErsatzTV/Pages/TelevisionSeasonList.razor
  22. 2
      ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

3
CHANGELOG.md

@ -16,6 +16,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Filler collection will always be randomized (to fill as much time as possible) - Filler collection will always be randomized (to fill as much time as possible)
- Filler will be hidden from channel guide, but visible in playout details in ErsatzTV - Filler will be hidden from channel guide, but visible in playout details in ErsatzTV
- Unfilled time will show offline image - Unfilled time will show offline image
- Add `Guide Mode` option to all schedule items
- `Normal` guide mode will show all scheduled items in the channel guide (xmltv)
- `Filler` guide mode will hide all scheduled items from the channel guide, and extend the end time for the previous item in the guide
## [0.1.3-alpha] - 2021-10-12 ## [0.1.3-alpha] - 2021-10-12
### Fixed ### Fixed

3
ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs

@ -25,5 +25,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
int? TailMultiCollectionId, int? TailMultiCollectionId,
int? TailSmartCollectionId, int? TailSmartCollectionId,
int? TailMediaItemId, int? TailMediaItemId,
string CustomTitle) : IRequest<Either<BaseError, ProgramScheduleItemViewModel>>, IProgramScheduleItemRequest; string CustomTitle,
GuideMode GuideMode) : IRequest<Either<BaseError, ProgramScheduleItemViewModel>>, IProgramScheduleItemRequest;
} }

1
ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs

@ -22,5 +22,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
int? TailSmartCollectionId { get; } int? TailSmartCollectionId { get; }
int? TailMediaItemId { get; } int? TailMediaItemId { get; }
string CustomTitle { get; } string CustomTitle { get; }
GuideMode GuideMode { get; }
} }
} }

12
ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs

@ -135,7 +135,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
SmartCollectionId = item.SmartCollectionId, SmartCollectionId = item.SmartCollectionId,
MediaItemId = item.MediaItemId, MediaItemId = item.MediaItemId,
PlaybackOrder = item.PlaybackOrder, PlaybackOrder = item.PlaybackOrder,
CustomTitle = item.CustomTitle CustomTitle = item.CustomTitle,
GuideMode = item.GuideMode
}, },
PlayoutMode.One => new ProgramScheduleItemOne PlayoutMode.One => new ProgramScheduleItemOne
{ {
@ -148,7 +149,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
SmartCollectionId = item.SmartCollectionId, SmartCollectionId = item.SmartCollectionId,
MediaItemId = item.MediaItemId, MediaItemId = item.MediaItemId,
PlaybackOrder = item.PlaybackOrder, PlaybackOrder = item.PlaybackOrder,
CustomTitle = item.CustomTitle CustomTitle = item.CustomTitle,
GuideMode = item.GuideMode
}, },
PlayoutMode.Multiple => new ProgramScheduleItemMultiple PlayoutMode.Multiple => new ProgramScheduleItemMultiple
{ {
@ -162,7 +164,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
MediaItemId = item.MediaItemId, MediaItemId = item.MediaItemId,
PlaybackOrder = item.PlaybackOrder, PlaybackOrder = item.PlaybackOrder,
Count = item.MultipleCount.GetValueOrDefault(), Count = item.MultipleCount.GetValueOrDefault(),
CustomTitle = item.CustomTitle CustomTitle = item.CustomTitle,
GuideMode = item.GuideMode
}, },
PlayoutMode.Duration => new ProgramScheduleItemDuration PlayoutMode.Duration => new ProgramScheduleItemDuration
{ {
@ -182,7 +185,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
TailMultiCollectionId = item.TailMultiCollectionId, TailMultiCollectionId = item.TailMultiCollectionId,
TailSmartCollectionId = item.TailSmartCollectionId, TailSmartCollectionId = item.TailSmartCollectionId,
TailMediaItemId = item.TailMediaItemId, TailMediaItemId = item.TailMediaItemId,
CustomTitle = item.CustomTitle CustomTitle = item.CustomTitle,
GuideMode = item.GuideMode
}, },
_ => throw new NotSupportedException($"Unsupported playout mode {item.PlayoutMode}") _ => throw new NotSupportedException($"Unsupported playout mode {item.PlayoutMode}")
}; };

3
ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs

@ -26,7 +26,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
int? TailMultiCollectionId, int? TailMultiCollectionId,
int? TailSmartCollectionId, int? TailSmartCollectionId,
int? TailMediaItemId, int? TailMediaItemId,
string CustomTitle) : IProgramScheduleItemRequest; string CustomTitle,
GuideMode GuideMode) : IProgramScheduleItemRequest;
public record ReplaceProgramScheduleItems public record ReplaceProgramScheduleItems
(int ProgramScheduleId, List<ReplaceProgramScheduleItem> Items) : IRequest< (int ProgramScheduleId, List<ReplaceProgramScheduleItem> Items) : IRequest<

12
ErsatzTV.Application/ProgramSchedules/Mapper.cs

@ -58,7 +58,8 @@ namespace ErsatzTV.Application.ProgramSchedules
Artist artist => MediaItems.Mapper.ProjectToViewModel(artist), Artist artist => MediaItems.Mapper.ProjectToViewModel(artist),
_ => null _ => null
}, },
duration.CustomTitle), duration.CustomTitle,
duration.GuideMode),
ProgramScheduleItemFlood flood => ProgramScheduleItemFlood flood =>
new ProgramScheduleItemFloodViewModel( new ProgramScheduleItemFloodViewModel(
flood.Id, flood.Id,
@ -83,7 +84,8 @@ namespace ErsatzTV.Application.ProgramSchedules
_ => null _ => null
}, },
flood.PlaybackOrder, flood.PlaybackOrder,
flood.CustomTitle), flood.CustomTitle,
flood.GuideMode),
ProgramScheduleItemMultiple multiple => ProgramScheduleItemMultiple multiple =>
new ProgramScheduleItemMultipleViewModel( new ProgramScheduleItemMultipleViewModel(
multiple.Id, multiple.Id,
@ -109,7 +111,8 @@ namespace ErsatzTV.Application.ProgramSchedules
}, },
multiple.PlaybackOrder, multiple.PlaybackOrder,
multiple.Count, multiple.Count,
multiple.CustomTitle), multiple.CustomTitle,
multiple.GuideMode),
ProgramScheduleItemOne one => ProgramScheduleItemOne one =>
new ProgramScheduleItemOneViewModel( new ProgramScheduleItemOneViewModel(
one.Id, one.Id,
@ -134,7 +137,8 @@ namespace ErsatzTV.Application.ProgramSchedules
_ => null _ => null
}, },
one.PlaybackOrder, one.PlaybackOrder,
one.CustomTitle), one.CustomTitle,
one.GuideMode),
_ => throw new NotSupportedException( _ => throw new NotSupportedException(
$"Unsupported program schedule item type {programScheduleItem.GetType().Name}") $"Unsupported program schedule item type {programScheduleItem.GetType().Name}")
}; };

6
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs

@ -25,7 +25,8 @@ namespace ErsatzTV.Application.ProgramSchedules
MultiCollectionViewModel tailMultiCollection, MultiCollectionViewModel tailMultiCollection,
SmartCollectionViewModel tailSmartCollection, SmartCollectionViewModel tailSmartCollection,
NamedMediaItemViewModel tailMediaItem, NamedMediaItemViewModel tailMediaItem,
string customTitle) : base( string customTitle,
GuideMode guideMode) : base(
id, id,
index, index,
startType, startType,
@ -37,7 +38,8 @@ namespace ErsatzTV.Application.ProgramSchedules
smartCollection, smartCollection,
mediaItem, mediaItem,
playbackOrder, playbackOrder,
customTitle) customTitle,
guideMode)
{ {
PlayoutDuration = playoutDuration; PlayoutDuration = playoutDuration;
TailMode = tailMode; TailMode = tailMode;

6
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs

@ -18,7 +18,8 @@ namespace ErsatzTV.Application.ProgramSchedules
SmartCollectionViewModel smartCollection, SmartCollectionViewModel smartCollection,
NamedMediaItemViewModel mediaItem, NamedMediaItemViewModel mediaItem,
PlaybackOrder playbackOrder, PlaybackOrder playbackOrder,
string customTitle) : base( string customTitle,
GuideMode guideMode) : base(
id, id,
index, index,
startType, startType,
@ -30,7 +31,8 @@ namespace ErsatzTV.Application.ProgramSchedules
smartCollection, smartCollection,
mediaItem, mediaItem,
playbackOrder, playbackOrder,
customTitle) customTitle,
guideMode)
{ {
} }
} }

6
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs

@ -19,7 +19,8 @@ namespace ErsatzTV.Application.ProgramSchedules
NamedMediaItemViewModel mediaItem, NamedMediaItemViewModel mediaItem,
PlaybackOrder playbackOrder, PlaybackOrder playbackOrder,
int count, int count,
string customTitle) : base( string customTitle,
GuideMode guideMode) : base(
id, id,
index, index,
startType, startType,
@ -31,7 +32,8 @@ namespace ErsatzTV.Application.ProgramSchedules
smartCollection, smartCollection,
mediaItem, mediaItem,
playbackOrder, playbackOrder,
customTitle) => customTitle,
guideMode) =>
Count = count; Count = count;
public int Count { get; } public int Count { get; }

6
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs

@ -18,7 +18,8 @@ namespace ErsatzTV.Application.ProgramSchedules
SmartCollectionViewModel smartCollection, SmartCollectionViewModel smartCollection,
NamedMediaItemViewModel mediaItem, NamedMediaItemViewModel mediaItem,
PlaybackOrder playbackOrder, PlaybackOrder playbackOrder,
string customTitle) : base( string customTitle,
GuideMode guideMode) : base(
id, id,
index, index,
startType, startType,
@ -30,7 +31,8 @@ namespace ErsatzTV.Application.ProgramSchedules
smartCollection, smartCollection,
mediaItem, mediaItem,
playbackOrder, playbackOrder,
customTitle) customTitle,
guideMode)
{ {
} }
} }

3
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs

@ -17,7 +17,8 @@ namespace ErsatzTV.Application.ProgramSchedules
SmartCollectionViewModel SmartCollection, SmartCollectionViewModel SmartCollection,
NamedMediaItemViewModel MediaItem, NamedMediaItemViewModel MediaItem,
PlaybackOrder PlaybackOrder, PlaybackOrder PlaybackOrder,
string CustomTitle) string CustomTitle,
GuideMode GuideMode)
{ {
public string Name => CollectionType switch public string Name => CollectionType switch
{ {

8
ErsatzTV.Core/Domain/GuideMode.cs

@ -0,0 +1,8 @@
namespace ErsatzTV.Core.Domain
{
public enum GuideMode
{
Normal = 0,
Filler = 1
}
}

1
ErsatzTV.Core/Domain/ProgramScheduleItem.cs

@ -9,6 +9,7 @@ namespace ErsatzTV.Core.Domain
public StartType StartType => StartTime.HasValue ? StartType.Fixed : StartType.Dynamic; public StartType StartType => StartTime.HasValue ? StartType.Fixed : StartType.Dynamic;
public TimeSpan? StartTime { get; set; } public TimeSpan? StartTime { get; set; }
public ProgramScheduleItemCollectionType CollectionType { get; set; } public ProgramScheduleItemCollectionType CollectionType { get; set; }
public GuideMode GuideMode { get; set; }
public string CustomTitle { get; set; } public string CustomTitle { get; set; }
public int ProgramScheduleId { get; set; } public int ProgramScheduleId { get; set; }
public ProgramSchedule ProgramSchedule { get; set; } public ProgramSchedule ProgramSchedule { get; set; }

2
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -285,7 +285,7 @@ namespace ErsatzTV.Core.Scheduling
Start = itemStartTime.UtcDateTime, Start = itemStartTime.UtcDateTime,
Finish = itemStartTime.UtcDateTime + version.Duration, Finish = itemStartTime.UtcDateTime + version.Duration,
CustomGroup = customGroup, CustomGroup = customGroup,
IsFiller = inDurationFiller IsFiller = inDurationFiller || scheduleItem.GuideMode == GuideMode.Filler
}; };
if (!string.IsNullOrWhiteSpace(scheduleItem.CustomTitle)) if (!string.IsNullOrWhiteSpace(scheduleItem.CustomTitle))

3510
ErsatzTV.Infrastructure/Migrations/20211014180849_Add_ProgramScheduleItem_GuideMode.Designer.cs generated

File diff suppressed because it is too large Load Diff

24
ErsatzTV.Infrastructure/Migrations/20211014180849_Add_ProgramScheduleItem_GuideMode.cs

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_ProgramScheduleItem_GuideMode : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "GuideMode",
table: "ProgramScheduleItem",
type: "INTEGER",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "GuideMode",
table: "ProgramScheduleItem");
}
}
}

3
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -1312,6 +1312,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<string>("CustomTitle") b.Property<string>("CustomTitle")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<int>("GuideMode")
.HasColumnType("INTEGER");
b.Property<int>("Index") b.Property<int>("Index")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");

2
ErsatzTV/Pages/Artist.razor

@ -213,7 +213,7 @@
DialogResult result = await dialog.Result; DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) 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, ProgramScheduleItemCollectionType.Collection, 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, ProgramScheduleItemCollectionType.Collection, null, null, null, null, null, GuideMode.Normal));
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); _navigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
} }
} }

8
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -255,6 +255,10 @@
Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration || _selectedItem.TailMode != TailMode.Filler)"/> Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration || _selectedItem.TailMode != TailMode.Filler)"/>
} }
<MudTextField Class="mt-3" Label="Custom Title" @bind-Value="@_selectedItem.CustomTitle" For="@(() => _selectedItem.CustomTitle)"/> <MudTextField Class="mt-3" Label="Custom Title" @bind-Value="@_selectedItem.CustomTitle" For="@(() => _selectedItem.CustomTitle)"/>
<MudSelect Class="mt-3" Label="Guide Mode" @bind-Value="@_selectedItem.GuideMode" For="@(() => _selectedItem.GuideMode)">
<MudSelectItem Value="@GuideMode.Normal">Normal</MudSelectItem>
<MudSelectItem Value="@GuideMode.Filler">Filler</MudSelectItem>
</MudSelect>
</MudCardContent> </MudCardContent>
</MudCard> </MudCard>
</EditForm> </EditForm>
@ -343,6 +347,7 @@
MediaItem = item.MediaItem, MediaItem = item.MediaItem,
PlaybackOrder = item.PlaybackOrder, PlaybackOrder = item.PlaybackOrder,
CustomTitle = item.CustomTitle, CustomTitle = item.CustomTitle,
GuideMode = item.GuideMode
}; };
switch (item) switch (item)
@ -438,7 +443,8 @@
item.TailMultiCollection?.Id, item.TailMultiCollection?.Id,
item.TailSmartCollection?.Id, item.TailSmartCollection?.Id,
item.TailMediaItem?.MediaItemId, item.TailMediaItem?.MediaItemId,
item.CustomTitle)).ToList(); item.CustomTitle,
item.GuideMode)).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)).Map(e => e.LeftToSeq());

2
ErsatzTV/Pages/TelevisionEpisodeList.razor

@ -197,7 +197,7 @@
DialogResult result = await dialog.Result; DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) 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, ProgramScheduleItemCollectionType.Collection, 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, ProgramScheduleItemCollectionType.Collection, null, null, null, null, null, GuideMode.Normal));
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); _navigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
} }
} }

2
ErsatzTV/Pages/TelevisionSeasonList.razor

@ -225,7 +225,7 @@
DialogResult result = await dialog.Result; DialogResult result = await dialog.Result;
if (!result.Cancelled && result.Data is ProgramScheduleViewModel schedule) 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, ProgramScheduleItemCollectionType.Collection, 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, ProgramScheduleItemCollectionType.Collection, null, null, null, null, null, GuideMode.Normal));
_navigationManager.NavigateTo($"/schedules/{schedule.Id}/items"); _navigationManager.NavigateTo($"/schedules/{schedule.Id}/items");
} }
} }

2
ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

@ -116,6 +116,8 @@ namespace ErsatzTV.ViewModels
public string CustomTitle { get; set; } public string CustomTitle { get; set; }
public GuideMode GuideMode { get; set; }
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] [NotifyPropertyChangedInvocator]

Loading…
Cancel
Save