Browse Source

add collection type search query (#2598)

pull/2599/head
Jason Dove 2 months ago committed by GitHub
parent
commit
dd38ba19ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 4
      ErsatzTV.Application/ProgramSchedules/Commands/AddProgramScheduleItem.cs
  3. 2
      ErsatzTV.Application/ProgramSchedules/Commands/IProgramScheduleItemRequest.cs
  4. 15
      ErsatzTV.Application/ProgramSchedules/Commands/ProgramScheduleItemCommandBase.cs
  5. 2
      ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItems.cs
  6. 25
      ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItemsHandler.cs
  7. 8
      ErsatzTV.Application/ProgramSchedules/Mapper.cs
  8. 4
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs
  9. 4
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs
  10. 4
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs
  11. 4
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs
  12. 4
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs
  13. 1
      ErsatzTV.Core/Domain/CollectionType.cs
  14. 1
      ErsatzTV.Core/Domain/PlayoutProgramScheduleAnchor.cs
  15. 2
      ErsatzTV.Core/Domain/ProgramScheduleItem.cs
  16. 7
      ErsatzTV.Core/Scheduling/CollectionKey.cs
  17. 7
      ErsatzTV.Core/Scheduling/MediaItemsForCollection.cs
  18. 5
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  19. 6864
      ErsatzTV.Infrastructure.MySql/Migrations/20251104180803_Add_CollectionTypeSearchQuery.Designer.cs
  20. 51
      ErsatzTV.Infrastructure.MySql/Migrations/20251104180803_Add_CollectionTypeSearchQuery.cs
  21. 9
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  22. 6691
      ErsatzTV.Infrastructure.Sqlite/Migrations/20251104180529_Add_CollectionTypeSearchQuery.Designer.cs
  23. 48
      ErsatzTV.Infrastructure.Sqlite/Migrations/20251104180529_Add_CollectionTypeSearchQuery.cs
  24. 9
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  25. 26
      ErsatzTV/Pages/ScheduleItemsEditor.razor
  26. 7
      ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

5
CHANGELOG.md

@ -10,6 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -10,6 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `MediaItem_Resolution` template data (the current `Resolution` variable is the FFmpeg Profile resolution)
- Add `MediaItem_Start` template data (DateTimeOffset)
- Add `MediaItem_Stop` template data (DateTimeOffset)
- Classic schedules: add collection type `Search Query`
- This allows defining search queries directly on schedule items without creating smart collections beforehand
- As an example, this can be used to filter or combine existing smart collections
- Filter: `smart_collection:"sd movies" AND plot:"christmas"`
- Combine: `smart_collection:"old commercials" AND smart_collection:"nick promos"`
### Fixed
- Fix HLS Direct playback with Jellyfin 10.11

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

@ -17,6 +17,8 @@ public record AddProgramScheduleItem( @@ -17,6 +17,8 @@ public record AddProgramScheduleItem(
int? RerunCollectionId,
int? MediaItemId,
int? PlaylistId,
string SearchTitle,
string SearchQuery,
PlaybackOrder PlaybackOrder,
MarathonGroupBy MarathonGroupBy,
bool MarathonShuffleGroups,
@ -57,6 +59,8 @@ public record AddProgramScheduleItem( @@ -57,6 +59,8 @@ public record AddProgramScheduleItem(
RerunCollectionId: null,
MediaItemId: mediaItemId,
PlaylistId: null,
SearchTitle: null,
SearchQuery: null,
PlaybackOrder.Shuffle,
MarathonGroupBy.None,
MarathonShuffleGroups: false,

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

@ -14,6 +14,8 @@ public interface IProgramScheduleItemRequest @@ -14,6 +14,8 @@ public interface IProgramScheduleItemRequest
int? RerunCollectionId { get; }
int? MediaItemId { get; }
int? PlaylistId { get; }
string SearchTitle { get; }
string SearchQuery { get; }
PlayoutMode PlayoutMode { get; }
PlaybackOrder PlaybackOrder { get; }
MarathonGroupBy MarathonGroupBy { get; }

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

@ -188,6 +188,13 @@ public abstract class ProgramScheduleItemCommandBase @@ -188,6 +188,13 @@ public abstract class ProgramScheduleItemCommandBase
return BaseError.New("[Playlist] is required for collection type 'Playlist'");
}
break;
case CollectionType.SearchQuery:
if (string.IsNullOrWhiteSpace(item.SearchQuery))
{
return BaseError.New("[SearchQuery] is required for collection type 'SearchQuery'");
}
break;
default:
return BaseError.New("[CollectionType] is invalid");
@ -216,6 +223,8 @@ public abstract class ProgramScheduleItemCommandBase @@ -216,6 +223,8 @@ public abstract class ProgramScheduleItemCommandBase
RerunCollectionId = item.RerunCollectionId,
MediaItemId = item.MediaItemId,
PlaylistId = item.PlaylistId,
SearchTitle = item.SearchTitle,
SearchQuery = item.SearchQuery,
PlaybackOrder = item.PlaybackOrder,
MarathonGroupBy = item.MarathonGroupBy,
MarathonShuffleGroups = item.MarathonShuffleGroups,
@ -247,6 +256,8 @@ public abstract class ProgramScheduleItemCommandBase @@ -247,6 +256,8 @@ public abstract class ProgramScheduleItemCommandBase
RerunCollectionId = item.RerunCollectionId,
MediaItemId = item.MediaItemId,
PlaylistId = item.PlaylistId,
SearchTitle = item.SearchTitle,
SearchQuery = item.SearchQuery,
PlaybackOrder = item.PlaybackOrder,
MarathonGroupBy = item.MarathonGroupBy,
MarathonShuffleGroups = item.MarathonShuffleGroups,
@ -278,6 +289,8 @@ public abstract class ProgramScheduleItemCommandBase @@ -278,6 +289,8 @@ public abstract class ProgramScheduleItemCommandBase
RerunCollectionId = item.RerunCollectionId,
MediaItemId = item.MediaItemId,
PlaylistId = item.PlaylistId,
SearchTitle = item.SearchTitle,
SearchQuery = item.SearchQuery,
PlaybackOrder = item.PlaybackOrder,
MarathonGroupBy = item.MarathonGroupBy,
MarathonShuffleGroups = item.MarathonShuffleGroups,
@ -311,6 +324,8 @@ public abstract class ProgramScheduleItemCommandBase @@ -311,6 +324,8 @@ public abstract class ProgramScheduleItemCommandBase
RerunCollectionId = item.RerunCollectionId,
MediaItemId = item.MediaItemId,
PlaylistId = item.PlaylistId,
SearchTitle = item.SearchTitle,
SearchQuery = item.SearchQuery,
PlaybackOrder = item.PlaybackOrder,
MarathonGroupBy = item.MarathonGroupBy,
MarathonShuffleGroups = item.MarathonShuffleGroups,

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

@ -17,6 +17,8 @@ public record ReplaceProgramScheduleItem( @@ -17,6 +17,8 @@ public record ReplaceProgramScheduleItem(
int? RerunCollectionId,
int? MediaItemId,
int? PlaylistId,
string SearchTitle,
string SearchQuery,
PlaybackOrder PlaybackOrder,
MarathonGroupBy MarathonGroupBy,
bool MarathonShuffleGroups,

25
ErsatzTV.Application/ProgramSchedules/Commands/ReplaceProgramScheduleItemsHandler.cs

@ -9,25 +9,16 @@ using static ErsatzTV.Application.ProgramSchedules.Mapper; @@ -9,25 +9,16 @@ using static ErsatzTV.Application.ProgramSchedules.Mapper;
namespace ErsatzTV.Application.ProgramSchedules;
public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase,
IRequestHandler<ReplaceProgramScheduleItems, Either<BaseError, IEnumerable<ProgramScheduleItemViewModel>>>
{
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public ReplaceProgramScheduleItemsHandler(
public class ReplaceProgramScheduleItemsHandler(
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> channel)
ChannelWriter<IBackgroundServiceRequest> channel) : ProgramScheduleItemCommandBase,
IRequestHandler<ReplaceProgramScheduleItems, Either<BaseError, IEnumerable<ProgramScheduleItemViewModel>>>
{
_dbContextFactory = dbContextFactory;
_channel = channel;
}
public async Task<Either<BaseError, IEnumerable<ProgramScheduleItemViewModel>>> Handle(
ReplaceProgramScheduleItems request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, ProgramSchedule> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(ps => PersistItems(dbContext, request, ps, cancellationToken));
}
@ -53,7 +44,7 @@ public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase @@ -53,7 +44,7 @@ public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase
// refresh any playouts that use this schedule
foreach (Playout playout in programSchedule.Playouts)
{
await _channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Refresh), cancellationToken);
await channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Refresh), cancellationToken);
}
return programSchedule.Items.Map(ProjectToViewModel);
@ -121,7 +112,8 @@ public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase @@ -121,7 +112,8 @@ public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase
item.MultiCollectionId,
item.SmartCollectionId,
item.RerunCollectionId,
item.PlaylistId);
item.PlaylistId,
item.SearchQuery);
if (keyOrders.TryGetValue(key, out System.Collections.Generic.HashSet<PlaybackOrder> playbackOrders))
{
@ -147,5 +139,6 @@ public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase @@ -147,5 +139,6 @@ public class ReplaceProgramScheduleItemsHandler : ProgramScheduleItemCommandBase
int? MultiCollectionId,
int? SmartCollectionId,
int? RerunCollectionId,
int? PlaylistId);
int? PlaylistId,
string SearchQuery);
}

8
ErsatzTV.Application/ProgramSchedules/Mapper.cs

@ -47,6 +47,8 @@ internal static class Mapper @@ -47,6 +47,8 @@ internal static class Mapper
Artist artist => MediaItems.Mapper.ProjectToViewModel(artist),
_ => null
},
duration.SearchTitle,
duration.SearchQuery,
duration.PlaybackOrder,
duration.MarathonGroupBy,
duration.MarathonShuffleGroups,
@ -111,6 +113,8 @@ internal static class Mapper @@ -111,6 +113,8 @@ internal static class Mapper
Artist artist => MediaItems.Mapper.ProjectToViewModel(artist),
_ => null
},
flood.SearchTitle,
flood.SearchQuery,
flood.PlaybackOrder,
flood.MarathonGroupBy,
flood.MarathonShuffleGroups,
@ -172,6 +176,8 @@ internal static class Mapper @@ -172,6 +176,8 @@ internal static class Mapper
Artist artist => MediaItems.Mapper.ProjectToViewModel(artist),
_ => null
},
multiple.SearchTitle,
multiple.SearchQuery,
multiple.PlaybackOrder,
multiple.MarathonGroupBy,
multiple.MarathonShuffleGroups,
@ -235,6 +241,8 @@ internal static class Mapper @@ -235,6 +241,8 @@ internal static class Mapper
Artist artist => MediaItems.Mapper.ProjectToViewModel(artist),
_ => null
},
one.SearchTitle,
one.SearchQuery,
one.PlaybackOrder,
one.MarathonGroupBy,
one.MarathonShuffleGroups,

4
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemDurationViewModel.cs

@ -23,6 +23,8 @@ public record ProgramScheduleItemDurationViewModel : ProgramScheduleItemViewMode @@ -23,6 +23,8 @@ public record ProgramScheduleItemDurationViewModel : ProgramScheduleItemViewMode
RerunCollectionViewModel rerunCollection,
PlaylistViewModel playlist,
NamedMediaItemViewModel mediaItem,
string searchTitle,
string searchQuery,
PlaybackOrder playbackOrder,
MarathonGroupBy marathonGroupBy,
bool marathonShuffleGroups,
@ -58,6 +60,8 @@ public record ProgramScheduleItemDurationViewModel : ProgramScheduleItemViewMode @@ -58,6 +60,8 @@ public record ProgramScheduleItemDurationViewModel : ProgramScheduleItemViewMode
rerunCollection,
playlist,
mediaItem,
searchTitle,
searchQuery,
playbackOrder,
marathonGroupBy,
marathonShuffleGroups,

4
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemFloodViewModel.cs

@ -23,6 +23,8 @@ public record ProgramScheduleItemFloodViewModel : ProgramScheduleItemViewModel @@ -23,6 +23,8 @@ public record ProgramScheduleItemFloodViewModel : ProgramScheduleItemViewModel
RerunCollectionViewModel rerunCollection,
PlaylistViewModel playlist,
NamedMediaItemViewModel mediaItem,
string searchTitle,
string searchQuery,
PlaybackOrder playbackOrder,
MarathonGroupBy marathonGroupBy,
bool marathonShuffleGroups,
@ -55,6 +57,8 @@ public record ProgramScheduleItemFloodViewModel : ProgramScheduleItemViewModel @@ -55,6 +57,8 @@ public record ProgramScheduleItemFloodViewModel : ProgramScheduleItemViewModel
rerunCollection,
playlist,
mediaItem,
searchTitle,
searchQuery,
playbackOrder,
marathonGroupBy,
marathonShuffleGroups,

4
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemMultipleViewModel.cs

@ -23,6 +23,8 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode @@ -23,6 +23,8 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
RerunCollectionViewModel rerunCollection,
PlaylistViewModel playlist,
NamedMediaItemViewModel mediaItem,
string searchTitle,
string searchQuery,
PlaybackOrder playbackOrder,
MarathonGroupBy marathonGroupBy,
bool marathonShuffleGroups,
@ -57,6 +59,8 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode @@ -57,6 +59,8 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
rerunCollection,
playlist,
mediaItem,
searchTitle,
searchQuery,
playbackOrder,
marathonGroupBy,
marathonShuffleGroups,

4
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemOneViewModel.cs

@ -23,6 +23,8 @@ public record ProgramScheduleItemOneViewModel : ProgramScheduleItemViewModel @@ -23,6 +23,8 @@ public record ProgramScheduleItemOneViewModel : ProgramScheduleItemViewModel
RerunCollectionViewModel rerunCollection,
PlaylistViewModel playlist,
NamedMediaItemViewModel mediaItem,
string searchTitle,
string searchQuery,
PlaybackOrder playbackOrder,
MarathonGroupBy marathonGroupBy,
bool marathonShuffleGroups,
@ -55,6 +57,8 @@ public record ProgramScheduleItemOneViewModel : ProgramScheduleItemViewModel @@ -55,6 +57,8 @@ public record ProgramScheduleItemOneViewModel : ProgramScheduleItemViewModel
rerunCollection,
playlist,
mediaItem,
searchTitle,
searchQuery,
playbackOrder,
marathonGroupBy,
marathonShuffleGroups,

4
ErsatzTV.Application/ProgramSchedules/ProgramScheduleItemViewModel.cs

@ -22,6 +22,8 @@ public abstract record ProgramScheduleItemViewModel( @@ -22,6 +22,8 @@ public abstract record ProgramScheduleItemViewModel(
RerunCollectionViewModel RerunCollection,
PlaylistViewModel Playlist,
NamedMediaItemViewModel MediaItem,
string SearchTitle,
string SearchQuery,
PlaybackOrder PlaybackOrder,
MarathonGroupBy MarathonGroupBy,
bool MarathonShuffleGroups,
@ -55,6 +57,8 @@ public abstract record ProgramScheduleItemViewModel( @@ -55,6 +57,8 @@ public abstract record ProgramScheduleItemViewModel(
MultiCollection?.Name,
CollectionType.SmartCollection =>
SmartCollection?.Name,
CollectionType.SearchQuery =>
string.IsNullOrWhiteSpace(SearchTitle) ? SearchQuery : SearchTitle,
CollectionType.Playlist =>
Playlist?.Name,
CollectionType.RerunFirstRun or CollectionType.RerunRerun =>

1
ErsatzTV.Core/Domain/CollectionType.cs

@ -11,6 +11,7 @@ public enum CollectionType @@ -11,6 +11,7 @@ public enum CollectionType
Playlist = 6,
RerunFirstRun = 7,
RerunRerun = 8,
SearchQuery = 9,
Movie = 10,
Episode = 20,

1
ErsatzTV.Core/Domain/PlayoutProgramScheduleAnchor.cs

@ -29,6 +29,7 @@ public class PlayoutProgramScheduleAnchor @@ -29,6 +29,7 @@ public class PlayoutProgramScheduleAnchor
public MediaItem MediaItem { get; set; }
public int? PlaylistId { get; set; }
public Playlist Playlist { get; set; }
public string SearchQuery { get; set; }
public string FakeCollectionKey { get; set; }
public CollectionEnumeratorState EnumeratorState { get; set; }
}

2
ErsatzTV.Core/Domain/ProgramScheduleItem.cs

@ -27,6 +27,8 @@ public abstract class ProgramScheduleItem @@ -27,6 +27,8 @@ public abstract class ProgramScheduleItem
public MultiCollection MultiCollection { get; set; }
public int? SmartCollectionId { get; set; }
public SmartCollection SmartCollection { get; set; }
public string SearchTitle { get; set; }
public string SearchQuery { get; set; }
public int? RerunCollectionId { get; set; }
public RerunCollection RerunCollection { get; set; }
public int? PlaylistId { get; set; }

7
ErsatzTV.Core/Scheduling/CollectionKey.cs

@ -13,6 +13,7 @@ public class CollectionKey : Record<CollectionKey> @@ -13,6 +13,7 @@ public class CollectionKey : Record<CollectionKey>
public int? RerunCollectionId { get; set; }
public int? MediaItemId { get; set; }
public int? PlaylistId { get; set; }
public string SearchQuery { get; set; }
public string FakeCollectionKey { get; set; }
public static CollectionKey ForPlaylistItem(PlaylistItem item) =>
@ -362,6 +363,12 @@ public class CollectionKey : Record<CollectionKey> @@ -362,6 +363,12 @@ public class CollectionKey : Record<CollectionKey>
PlaylistId = item.PlaylistId,
FakeCollectionKey = item.FakeCollectionKey
},
CollectionType.SearchQuery => new CollectionKey
{
CollectionType = item.CollectionType,
SearchQuery = item.SearchQuery,
FakeCollectionKey = item.FakeCollectionKey
},
CollectionType.FakeCollection => new CollectionKey
{
CollectionType = item.CollectionType,

7
ErsatzTV.Core/Scheduling/MediaItemsForCollection.cs

@ -52,6 +52,13 @@ public static class MediaItemsForCollection @@ -52,6 +52,13 @@ public static class MediaItemsForCollection
result.AddRange(
await mediaCollectionRepository.GetPlaylistItems(collectionKey.PlaylistId ?? 0, cancellationToken));
break;
case CollectionType.SearchQuery:
result.AddRange(
await mediaCollectionRepository.GetSmartCollectionItems(
collectionKey.SearchQuery,
string.Empty,
cancellationToken));
break;
case CollectionType.Movie:
foreach (int mediaItemId in Optional(collectionKey.MediaItemId))
{

5
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -1214,6 +1214,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -1214,6 +1214,7 @@ public class PlayoutBuilder : IPlayoutBuilder
&& a.RerunCollectionId == collectionKey.RerunCollectionId
&& a.MultiCollectionId == collectionKey.MultiCollectionId
&& a.PlaylistId == collectionKey.PlaylistId
&& a.SearchQuery == collectionKey.SearchQuery
&& a.AnchorDate is null);
var maybeEnumeratorState = collectionEnumerators.ToDictionary(e => e.Key, e => e.Value.State);
@ -1235,6 +1236,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -1235,6 +1236,7 @@ public class PlayoutBuilder : IPlayoutBuilder
RerunCollectionId = collectionKey.RerunCollectionId,
MediaItemId = collectionKey.MediaItemId,
PlaylistId = collectionKey.PlaylistId,
SearchQuery = collectionKey.SearchQuery,
FakeCollectionKey = collectionKey.FakeCollectionKey,
EnumeratorState = maybeEnumeratorState[collectionKey]
});
@ -1277,7 +1279,8 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -1277,7 +1279,8 @@ public class PlayoutBuilder : IPlayoutBuilder
&& a.SmartCollectionId == collectionKey.SmartCollectionId
&& a.RerunCollectionId == collectionKey.RerunCollectionId
&& a.MediaItemId == collectionKey.MediaItemId
&& a.PlaylistId == collectionKey.PlaylistId);
&& a.PlaylistId == collectionKey.PlaylistId
&& a.SearchQuery == collectionKey.SearchQuery);
CollectionEnumeratorState state = null;

6864
ErsatzTV.Infrastructure.MySql/Migrations/20251104180803_Add_CollectionTypeSearchQuery.Designer.cs generated

File diff suppressed because it is too large Load Diff

51
ErsatzTV.Infrastructure.MySql/Migrations/20251104180803_Add_CollectionTypeSearchQuery.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.MySql.Migrations
{
/// <inheritdoc />
public partial class Add_CollectionTypeSearchQuery : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "SearchQuery",
table: "ProgramScheduleItem",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "SearchTitle",
table: "ProgramScheduleItem",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "SearchQuery",
table: "PlayoutProgramScheduleAnchor",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SearchQuery",
table: "ProgramScheduleItem");
migrationBuilder.DropColumn(
name: "SearchTitle",
table: "ProgramScheduleItem");
migrationBuilder.DropColumn(
name: "SearchQuery",
table: "PlayoutProgramScheduleAnchor");
}
}
}

9
ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs

@ -2104,6 +2104,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2104,6 +2104,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Property<int?>("RerunCollectionId")
.HasColumnType("int");
b.Property<string>("SearchQuery")
.HasColumnType("longtext");
b.Property<int?>("SmartCollectionId")
.HasColumnType("int");
@ -2371,6 +2374,12 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -2371,6 +2374,12 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Property<int?>("RerunCollectionId")
.HasColumnType("int");
b.Property<string>("SearchQuery")
.HasColumnType("longtext");
b.Property<string>("SearchTitle")
.HasColumnType("longtext");
b.Property<int?>("SmartCollectionId")
.HasColumnType("int");

6691
ErsatzTV.Infrastructure.Sqlite/Migrations/20251104180529_Add_CollectionTypeSearchQuery.Designer.cs generated

File diff suppressed because it is too large Load Diff

48
ErsatzTV.Infrastructure.Sqlite/Migrations/20251104180529_Add_CollectionTypeSearchQuery.cs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
{
/// <inheritdoc />
public partial class Add_CollectionTypeSearchQuery : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "SearchQuery",
table: "ProgramScheduleItem",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "SearchTitle",
table: "ProgramScheduleItem",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "SearchQuery",
table: "PlayoutProgramScheduleAnchor",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SearchQuery",
table: "ProgramScheduleItem");
migrationBuilder.DropColumn(
name: "SearchTitle",
table: "ProgramScheduleItem");
migrationBuilder.DropColumn(
name: "SearchQuery",
table: "PlayoutProgramScheduleAnchor");
}
}
}

9
ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs

@ -2009,6 +2009,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2009,6 +2009,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Property<int?>("RerunCollectionId")
.HasColumnType("INTEGER");
b.Property<string>("SearchQuery")
.HasColumnType("TEXT");
b.Property<int?>("SmartCollectionId")
.HasColumnType("INTEGER");
@ -2262,6 +2265,12 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -2262,6 +2265,12 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Property<int?>("RerunCollectionId")
.HasColumnType("INTEGER");
b.Property<string>("SearchQuery")
.HasColumnType("TEXT");
b.Property<string>("SearchTitle")
.HasColumnType("TEXT");
b.Property<int?>("SmartCollectionId")
.HasColumnType("INTEGER");

26
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -195,6 +195,7 @@ @@ -195,6 +195,7 @@
<MudSelectItem Value="CollectionType.Artist">Artist</MudSelectItem>
<MudSelectItem Value="CollectionType.MultiCollection">Multi Collection</MudSelectItem>
<MudSelectItem Value="CollectionType.SmartCollection">Smart Collection</MudSelectItem>
<MudSelectItem Value="CollectionType.SearchQuery">Search Query</MudSelectItem>
<MudSelectItem Value="CollectionType.Playlist">Playlist</MudSelectItem>
<MudSelectItem Value="CollectionType.RerunFirstRun">Rerun (First Run)</MudSelectItem>
<MudSelectItem Value="CollectionType.RerunRerun">Rerun (Rerun)</MudSelectItem>
@ -338,6 +339,24 @@ @@ -338,6 +339,24 @@
</MudStack>
}
@if (_selectedItem.CollectionType == CollectionType.SearchQuery)
{
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Search Title</MudText>
</div>
<MudTextField @bind-Value="@_selectedItem.SearchTitle"
For="@(() => _selectedItem.SearchTitle)"
HelperText="Optional title that will be displayed in schedule items tables"/>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Search Query</MudText>
</div>
<MudTextField @bind-Value="@_selectedItem.SearchQuery" For="@(() => _selectedItem.SearchQuery)"/>
</MudStack>
}
@if (_selectedItem.CollectionType == CollectionType.RerunFirstRun)
{
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
@ -389,6 +408,7 @@ @@ -389,6 +408,7 @@
break;
case CollectionType.Collection:
case CollectionType.SmartCollection:
case CollectionType.SearchQuery:
<MudSelectItem Value="PlaybackOrder.Chronological">Chronological</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Random">Random</MudSelectItem>
<MudSelectItem Value="PlaybackOrder.Shuffle">Shuffle</MudSelectItem>
@ -904,6 +924,8 @@ @@ -904,6 +924,8 @@
Collection = item.Collection,
MultiCollection = item.MultiCollection,
SmartCollection = item.SmartCollection,
SearchTitle = item.SearchTitle,
SearchQuery = item.SearchQuery,
RerunCollection = item.RerunCollection,
Playlist = item.Playlist,
MediaItem = item.MediaItem,
@ -980,6 +1002,8 @@ @@ -980,6 +1002,8 @@
Collection = item.Collection,
MultiCollection = item.MultiCollection,
SmartCollection = item.SmartCollection,
SearchTitle = item.SearchTitle,
SearchQuery = item.SearchQuery,
Playlist = item.Playlist,
MediaItem = item.MediaItem,
PlaybackOrder = item.PlaybackOrder,
@ -1057,6 +1081,8 @@ @@ -1057,6 +1081,8 @@
item.RerunCollection?.Id,
item.MediaItem?.MediaItemId,
item.Playlist?.Id,
item.SearchTitle,
item.SearchQuery,
item.PlaybackOrder,
item.MarathonGroupBy,
item.MarathonShuffleGroups,

7
ErsatzTV/ViewModels/ProgramScheduleItemEditViewModel.cs

@ -62,6 +62,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged @@ -62,6 +62,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
MultiCollection = null;
MediaItem = null;
SmartCollection = null;
SearchTitle = null;
SearchQuery = null;
RerunCollection = null;
if (_collectionType != CollectionType.Playlist &&
@ -81,6 +83,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged @@ -81,6 +83,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
OnPropertyChanged(nameof(MultiCollection));
OnPropertyChanged(nameof(MediaItem));
OnPropertyChanged(nameof(SmartCollection));
OnPropertyChanged(nameof(SearchTitle));
OnPropertyChanged(nameof(SearchQuery));
OnPropertyChanged(nameof(RerunCollection));
OnPropertyChanged(nameof(MultiCollection));
OnPropertyChanged(nameof(PlaybackOrder));
@ -99,6 +103,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged @@ -99,6 +103,8 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
public RerunCollectionViewModel RerunCollection { get; set; }
public NamedMediaItemViewModel MediaItem { get; set; }
public PlaylistViewModel Playlist { get; set; }
public string SearchTitle { get; set; }
public string SearchQuery { get; set; }
public FillerPresetViewModel PreRollFiller { get; set; }
public FillerPresetViewModel MidRollFiller { get; set; }
public FillerPresetViewModel PostRollFiller { get; set; }
@ -121,6 +127,7 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged @@ -121,6 +127,7 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
CollectionType.SmartCollection => SmartCollection?.Name,
CollectionType.Playlist => Playlist?.Name,
CollectionType.RerunFirstRun or CollectionType.RerunRerun => RerunCollection?.Name,
CollectionType.SearchQuery => string.IsNullOrWhiteSpace(SearchTitle) ? SearchQuery : SearchTitle,
_ => string.Empty
};

Loading…
Cancel
Save