mirror of https://github.com/ErsatzTV/ErsatzTV.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
6.1 KiB
187 lines
6.1 KiB
using System.Globalization; |
|
using ErsatzTV.Core; |
|
using Lucene.Net.Analysis; |
|
using Lucene.Net.Index; |
|
using Lucene.Net.QueryParsers.Classic; |
|
using Lucene.Net.QueryParsers.ComplexPhrase; |
|
using Lucene.Net.Search; |
|
using Lucene.Net.Util; |
|
using Query = Lucene.Net.Search.Query; |
|
|
|
namespace ErsatzTV.Infrastructure.Search; |
|
|
|
public class CustomMultiFieldQueryParser : MultiFieldQueryParser |
|
{ |
|
private static readonly List<string> NumericFields = |
|
[ |
|
LuceneSearchIndex.MinutesField, |
|
LuceneSearchIndex.SecondsField, |
|
LuceneSearchIndex.HeightField, |
|
LuceneSearchIndex.WidthField, |
|
LuceneSearchIndex.SeasonNumberField, |
|
LuceneSearchIndex.EpisodeNumberField, |
|
LuceneSearchIndex.VideoBitDepthField |
|
]; |
|
|
|
private readonly Analyzer _analyzer; |
|
private readonly LuceneVersion _matchVersion; |
|
|
|
public CustomMultiFieldQueryParser( |
|
LuceneVersion matchVersion, |
|
string[] fields, |
|
Analyzer analyzer, |
|
IDictionary<string, float> boosts) : base(matchVersion, fields, analyzer, boosts) |
|
{ |
|
_matchVersion = matchVersion; |
|
_analyzer = analyzer; |
|
} |
|
|
|
public CustomMultiFieldQueryParser(LuceneVersion matchVersion, string[] fields, Analyzer analyzer) : base( |
|
matchVersion, |
|
fields, |
|
analyzer) |
|
{ |
|
_matchVersion = matchVersion; |
|
_analyzer = analyzer; |
|
} |
|
|
|
protected override Query GetFieldQuery(string field, string queryText, bool quoted) |
|
{ |
|
if (field == "released_onthisday") |
|
{ |
|
var todayString = DateTime.Today.ToString("*MMdd", CultureInfo.InvariantCulture); |
|
return base.GetWildcardQuery(LuceneSearchIndex.ReleaseDateField, todayString); |
|
} |
|
|
|
if (NumericFields.Contains(field) && int.TryParse(queryText, out int val)) |
|
{ |
|
var bytesRef = new BytesRef(); |
|
NumericUtils.Int32ToPrefixCoded(val, 0, bytesRef); |
|
return NewTermQuery(new Term(field, bytesRef)); |
|
} |
|
|
|
return base.GetFieldQuery(field, queryText, quoted); |
|
} |
|
|
|
protected override Query GetFieldQuery(string field, string queryText, int slop) |
|
{ |
|
if (field == "released_inthelast" && ParseStart(queryText, out DateTime start)) |
|
{ |
|
var todayString = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
|
var dateString = start.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
|
|
|
return base.GetRangeQuery(LuceneSearchIndex.ReleaseDateField, dateString, todayString, true, true); |
|
} |
|
|
|
if (field == "released_notinthelast" && ParseStart(queryText, out DateTime finish)) |
|
{ |
|
var dateString = finish.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
|
|
|
return base.GetRangeQuery(LuceneSearchIndex.ReleaseDateField, "00000000", dateString, false, false); |
|
} |
|
|
|
if (field == "added_inthelast" && ParseStart(queryText, out DateTime addedStart)) |
|
{ |
|
var todayString = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
|
var dateString = addedStart.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
|
|
|
return base.GetRangeQuery(LuceneSearchIndex.AddedDateField, dateString, todayString, true, true); |
|
} |
|
|
|
if (field == "added_notinthelast" && ParseStart(queryText, out DateTime addedFinish)) |
|
{ |
|
var dateString = addedFinish.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
|
|
|
return base.GetRangeQuery(LuceneSearchIndex.AddedDateField, "00000000", dateString, false, false); |
|
} |
|
|
|
// assume asterisk always means wildcard |
|
if (queryText.Contains('*') && queryText.Contains(' ')) |
|
{ |
|
var parser = new ComplexPhraseQueryParser(_matchVersion, LuceneSearchIndex.TitleField, _analyzer) |
|
{ |
|
AllowLeadingWildcard = true |
|
}; |
|
|
|
string queryToParse = string.IsNullOrWhiteSpace(field) |
|
? $"\"{queryText}\"" |
|
: $"{field}:\"{queryText}\""; |
|
|
|
return parser.Parse(queryToParse); |
|
} |
|
|
|
return base.GetFieldQuery(field, queryText, slop); |
|
} |
|
|
|
protected override Query GetRangeQuery( |
|
string field, |
|
string part1, |
|
string part2, |
|
bool startInclusive, |
|
bool endInclusive) |
|
{ |
|
if (NumericFields.Contains(field)) |
|
{ |
|
if (part1 is null or "*" && int.TryParse(part2, out int max1)) |
|
{ |
|
return NumericRangeQuery.NewInt32Range(field, null, max1, startInclusive, endInclusive); |
|
} |
|
|
|
if (int.TryParse(part1, out int min)) |
|
{ |
|
if (part2 is null or "*") |
|
{ |
|
return NumericRangeQuery.NewInt32Range(field, min, null, startInclusive, endInclusive); |
|
} |
|
|
|
if (int.TryParse(part2, out int max)) |
|
{ |
|
return NumericRangeQuery.NewInt32Range(field, min, max, startInclusive, endInclusive); |
|
} |
|
} |
|
} |
|
|
|
return base.GetRangeQuery(field, part1, part2, startInclusive, endInclusive); |
|
} |
|
|
|
private static bool ParseStart(string text, out DateTime start) |
|
{ |
|
start = SystemTime.MinValueUtc; |
|
|
|
try |
|
{ |
|
if (int.TryParse(text.Split(" ")[0], out int number)) |
|
{ |
|
if (text.Contains("day")) |
|
{ |
|
start = DateTime.Today.AddDays(number * -1); |
|
return true; |
|
} |
|
|
|
if (text.Contains("week")) |
|
{ |
|
start = DateTime.Today.AddDays(number * -7); |
|
return true; |
|
} |
|
|
|
if (text.Contains("month")) |
|
{ |
|
start = DateTime.Today.AddMonths(number * -1); |
|
return true; |
|
} |
|
|
|
if (text.Contains("year")) |
|
{ |
|
start = DateTime.Today.AddYears(number * -1); |
|
return true; |
|
} |
|
} |
|
} |
|
catch |
|
{ |
|
// do nothing |
|
} |
|
|
|
return false; |
|
} |
|
}
|
|
|