filler rework (#449)

* add chapter statistics and new filler options

* refactor playout builder

* more refactor prep for filler

* rewrite schedulers

* refactor collectionkey

* add tail filler kind

* migrate tail filler to filler preset

* optionally show filler

* fix playout detail row count

* remove duration tail filler options

* implement tail and fallback in flood scheduler

* implement tail and fallback in one scheduler

* implement tail and fallback in multiple scheduler

* implement looping fallback filler

* more duration tests

* start to add post-roll filler to flood

* rework playoutitem filler tagging

* rework scheduler logging

* calculate whether configured filler will fit

* implement pre-roll and post-roll duration and count filler

* improve duration filler calculation

* add minutes to search index

* update channel guide to work with new filler

* add mid-roll filler

* don't clone enumerators for filler calculations

* support pre-roll and post-roll pad filler

* implement mid-roll pad filler

* allow clearing filler selections in schedule editor

* fix tests

* filler config validation

* use consistent time zone for tests
This commit is contained in:
Jason Dove
2021-10-21 20:23:14 -05:00
committed by GitHub
parent f4a63a1a1a
commit 6d147de2f3
133 changed files with 54673 additions and 990 deletions
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers.Classic;
using Lucene.Net.Search;
using Lucene.Net.Util;
@@ -31,6 +32,13 @@ namespace ErsatzTV.Infrastructure.Search
var todayString = DateTime.Today.ToString("*MMdd");
return base.GetWildcardQuery("release_date", todayString);
}
if (field == "minutes" && int.TryParse(queryText, out int val))
{
var bytesRef = new BytesRef();
NumericUtils.Int32ToPrefixCoded(val, 0, bytesRef);
return NewTermQuery(new Term("minutes", bytesRef));
}
return base.GetFieldQuery(field, queryText, quoted);
}
@@ -51,8 +59,18 @@ namespace ErsatzTV.Infrastructure.Search
return base.GetRangeQuery("release_date", "00000000", dateString, false, false);
}
return base.GetFieldQuery(field, queryText, slop);
}
protected override Query GetRangeQuery(string field, string part1, string part2, bool startInclusive, bool endInclusive)
{
if (field == "minutes" && int.TryParse(part1, out int min) && int.TryParse(part2, out int max))
{
return NumericRangeQuery.NewInt32Range(field, min, max, startInclusive, endInclusive);
}
return base.GetRangeQuery(field, part1, part2, startInclusive, endInclusive);
}
}
}
@@ -1,6 +1,7 @@
using System;
using ErsatzTV.Core;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers.Classic;
using Lucene.Net.Search;
using Lucene.Net.Util;
@@ -28,6 +29,13 @@ namespace ErsatzTV.Infrastructure.Search
var todayString = DateTime.Today.ToString("*MMdd");
return base.GetWildcardQuery("release_date", todayString);
}
if (field == "minutes" && int.TryParse(queryText, out int val))
{
var bytesRef = new BytesRef();
NumericUtils.Int32ToPrefixCoded(val, 0, bytesRef);
return NewTermQuery(new Term("minutes", bytesRef));
}
return base.GetFieldQuery(field, queryText, quoted);
}
@@ -52,6 +60,16 @@ namespace ErsatzTV.Infrastructure.Search
return base.GetFieldQuery(field, queryText, slop);
}
protected override Query GetRangeQuery(string field, string part1, string part2, bool startInclusive, bool endInclusive)
{
if (field == "minutes" && int.TryParse(part1, out int min) && int.TryParse(part2, out int max))
{
return NumericRangeQuery.NewInt32Range(field, 1, min, max, startInclusive, endInclusive);
}
return base.GetRangeQuery(field, part1, part2, startInclusive, endInclusive);
}
internal static bool ParseStart(string text, out DateTime start)
{
start = SystemTime.MinValueUtc;
+35 -12
View File
@@ -53,6 +53,7 @@ namespace ErsatzTV.Infrastructure.Search
private const string WriterField = "writer";
private const string TraktListField = "trakt_list";
private const string AlbumField = "album";
private const string MinutesField = "minutes";
public const string MovieType = "movie";
public const string ShowType = "show";
@@ -76,7 +77,7 @@ namespace ErsatzTV.Infrastructure.Search
_initialized = false;
}
public int Version => 17;
public int Version => 18;
public Task<bool> Initialize(ILocalFileSystem localFileSystem)
{
@@ -301,6 +302,11 @@ namespace ErsatzTV.Infrastructure.Search
};
await AddLanguages(searchRepository, doc, movie.MediaVersions);
foreach (MediaVersion version in movie.MediaVersions.HeadOrNone())
{
doc.Add(new Int32Field(MinutesField, (int)Math.Ceiling(version.Duration.TotalMinutes), Field.Store.NO));
}
if (!string.IsNullOrWhiteSpace(metadata.ContentRating))
{
@@ -574,7 +580,7 @@ namespace ErsatzTV.Infrastructure.Search
List<string> languages = await searchRepository.GetLanguagesForArtist(artist);
await AddLanguages(searchRepository, doc, languages);
foreach (Genre genre in metadata.Genres)
{
doc.Add(new TextField(GenreField, genre.Name, Field.Store.NO));
@@ -622,6 +628,11 @@ namespace ErsatzTV.Infrastructure.Search
};
await AddLanguages(searchRepository, doc, musicVideo.MediaVersions);
foreach (MediaVersion version in musicVideo.MediaVersions.HeadOrNone())
{
doc.Add(new Int32Field(MinutesField, (int)Math.Ceiling(version.Duration.TotalMinutes), Field.Store.NO));
}
if (metadata.ReleaseDate.HasValue)
{
@@ -684,17 +695,24 @@ namespace ErsatzTV.Infrastructure.Search
continue;
}
var doc = new Document();
doc.Add(new StringField(IdField, episode.Id.ToString(), Field.Store.YES));
doc.Add(new StringField(TypeField, EpisodeType, Field.Store.YES));
doc.Add(new TextField(TitleField, metadata.Title, Field.Store.NO));
doc.Add(new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO));
doc.Add(new TextField(LibraryNameField, episode.LibraryPath.Library.Name, Field.Store.NO));
doc.Add(new StringField(LibraryIdField, episode.LibraryPath.Library.Id.ToString(), Field.Store.NO));
doc.Add(new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO));
doc.Add(new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES));
var doc = new Document
{
new StringField(IdField, episode.Id.ToString(), Field.Store.YES),
new StringField(TypeField, EpisodeType, Field.Store.YES),
new TextField(TitleField, metadata.Title, Field.Store.NO),
new StringField(SortTitleField, metadata.SortTitle.ToLowerInvariant(), Field.Store.NO),
new TextField(LibraryNameField, episode.LibraryPath.Library.Name, Field.Store.NO),
new StringField(LibraryIdField, episode.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
};
await AddLanguages(searchRepository, doc, episode.MediaVersions);
foreach (MediaVersion version in episode.MediaVersions.HeadOrNone())
{
doc.Add(new Int32Field(MinutesField, (int)Math.Ceiling(version.Duration.TotalMinutes), Field.Store.NO));
}
if (metadata.ReleaseDate.HasValue)
{
@@ -773,10 +791,15 @@ namespace ErsatzTV.Infrastructure.Search
new TextField(LibraryNameField, otherVideo.LibraryPath.Library.Name, Field.Store.NO),
new StringField(LibraryIdField, otherVideo.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES)
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
};
await AddLanguages(searchRepository, doc, otherVideo.MediaVersions);
foreach (MediaVersion version in otherVideo.MediaVersions.HeadOrNone())
{
doc.Add(new Int32Field(MinutesField, (int)Math.Ceiling(version.Duration.TotalMinutes), Field.Store.NO));
}
foreach (Tag tag in metadata.Tags)
{