Merge pull request #68 from cheir-mneme/fix/p4-backend

perf: backend optimizations for regex caching and O(n*m) patterns
This commit is contained in:
Cody Kickertz 2025-12-19 13:45:24 -06:00 committed by GitHub
commit 0366c8f258
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 23 additions and 17 deletions

View file

@ -62,8 +62,8 @@ public void Execute(MissingMoviesSearchCommand message)
var movies = _movieService.MoviesWithoutFiles(pagingSpec).Records.ToList();
var queue = _queueService.GetQueue().Where(q => q.Movie != null).Select(q => q.Movie.Id);
var missing = movies.Where(e => !queue.Contains(e.Id)).ToList();
var queuedMovieIds = new HashSet<int>(_queueService.GetQueue().Where(q => q.Movie != null).Select(q => q.Movie.Id));
var missing = movies.Where(e => !queuedMovieIds.Contains(e.Id)).ToList();
SearchForBulkMovies(missing, message.Trigger == CommandTrigger.Manual).GetAwaiter().GetResult();
}
@ -82,8 +82,8 @@ public void Execute(CutoffUnmetMoviesSearchCommand message)
var movies = _movieCutoffService.MoviesWhereCutoffUnmet(pagingSpec).Records.ToList();
var queue = _queueService.GetQueue().Where(q => q.Movie != null).Select(q => q.Movie.Id);
var missing = movies.Where(e => !queue.Contains(e.Id)).ToList();
var queuedMovieIds = new HashSet<int>(_queueService.GetQueue().Where(q => q.Movie != null).Select(q => q.Movie.Id));
var missing = movies.Where(e => !queuedMovieIds.Contains(e.Id)).ToList();
SearchForBulkMovies(missing, message.Trigger == CommandTrigger.Manual).GetAwaiter().GetResult();
}

View file

@ -25,6 +25,9 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
{
public class SkyHookProxy : IProvideMovieInfo, ISearchForNewMovie
{
private static readonly Regex ImdbUrlRegex = new Regex(@"\bimdb\.com/title/(tt\d{7,})\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex TmdbUrlRegex = new Regex(@"\bthemoviedb\.org/movie/(\d+)\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
@ -406,7 +409,7 @@ public List<Movie> SearchForNewMovie(string title)
{
try
{
var match = new Regex(@"\bimdb\.com/title/(tt\d{7,})\b", RegexOptions.IgnoreCase).Match(title);
var match = ImdbUrlRegex.Match(title);
if (match.Success)
{
@ -414,7 +417,7 @@ public List<Movie> SearchForNewMovie(string title)
}
else
{
match = new Regex(@"\bthemoviedb\.org/movie/(\d+)\b", RegexOptions.IgnoreCase).Match(title);
match = TmdbUrlRegex.Match(title);
if (match.Success)
{

View file

@ -125,31 +125,32 @@ public Movie FindByTitle(string title, int year)
public Movie FindByTitle(List<string> titles, int? year, List<string> otherTitles, List<Movie> candidates)
{
var cleanTitles = titles.Select(t => t.CleanMovieTitle().ToLowerInvariant());
var cleanTitlesSet = new HashSet<string>(titles.Select(t => t.CleanMovieTitle().ToLowerInvariant()));
var otherTitlesSet = new HashSet<string>(otherTitles);
var result = candidates.Where(x => cleanTitles.Contains(x.MovieMetadata.Value.CleanTitle) || cleanTitles.Contains(x.MovieMetadata.Value.CleanOriginalTitle))
var result = candidates.Where(x => cleanTitlesSet.Contains(x.MovieMetadata.Value.CleanTitle) || cleanTitlesSet.Contains(x.MovieMetadata.Value.CleanOriginalTitle))
.AllWithYear(year)
.ToList();
if (result == null || result.Count == 0)
{
result =
candidates.Where(movie => otherTitles.Contains(movie.MovieMetadata.Value.CleanTitle)).AllWithYear(year).ToList();
candidates.Where(movie => otherTitlesSet.Contains(movie.MovieMetadata.Value.CleanTitle)).AllWithYear(year).ToList();
}
if (result == null || result.Count == 0)
{
result = candidates
.Where(m => m.MovieMetadata.Value.AlternativeTitles.Any(t => cleanTitles.Contains(t.CleanTitle) ||
otherTitles.Contains(t.CleanTitle)))
.Where(m => m.MovieMetadata.Value.AlternativeTitles.Any(t => cleanTitlesSet.Contains(t.CleanTitle) ||
otherTitlesSet.Contains(t.CleanTitle)))
.AllWithYear(year).ToList();
}
if (result == null || result.Count == 0)
{
result = candidates
.Where(m => m.MovieMetadata.Value.Translations.Any(t => cleanTitles.Contains(t.CleanTitle) ||
otherTitles.Contains(t.CleanTitle)))
.Where(m => m.MovieMetadata.Value.Translations.Any(t => cleanTitlesSet.Contains(t.CleanTitle) ||
otherTitlesSet.Contains(t.CleanTitle)))
.AllWithYear(year).ToList();
}

View file

@ -10,6 +10,8 @@ namespace NzbDrone.Core.Notifications.Pushsafer
{
public class PushsaferSettingsValidator : AbstractValidator<PushsaferSettings>
{
private static readonly Regex HexColorRegex = new Regex("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", RegexOptions.Compiled);
public PushsaferSettingsValidator()
{
RuleFor(c => c.ApiKey).NotEmpty();
@ -18,7 +20,7 @@ public PushsaferSettingsValidator()
RuleFor(c => c.Sound).ValidParsedStringRange(0, 62).When(c => c.Sound.IsNotNullOrWhiteSpace());
RuleFor(c => c.Vibration).ValidParsedStringRange(1, 3).When(c => c.Vibration.IsNotNullOrWhiteSpace());
RuleFor(c => c.Icon).ValidParsedStringRange(1, 181).When(c => c.Icon.IsNotNullOrWhiteSpace());
RuleFor(c => c.IconColor).Matches(new Regex("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")).When(c => c.IconColor.IsNotNullOrWhiteSpace());
RuleFor(c => c.IconColor).Matches(HexColorRegex).When(c => c.IconColor.IsNotNullOrWhiteSpace());
}
}

View file

@ -15,6 +15,8 @@ public static class Parser
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(Parser));
private static readonly Regex ImdbIdRegex = new Regex(@"^(\d{1,10}|(tt)\d{1,10})$", RegexOptions.Compiled);
private static readonly Regex EditionRegex = new Regex(@"\(?\b(?<edition>(((Recut.|Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Extended|Despecialized|(Special|Rouge|Final|Assembly|Imperial|Diamond|Signature|Hunter|Rekall)(?=(.(Cut|Edition|Version)))|\d{2,3}(th)?.Anniversary)(?:.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|Open.?Matte|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|Open?.Matte|IMAX|Fan.?Edit|Restored|((2|3|4)in1))))))\b\)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ReportEditionRegex = new Regex(@"^.+?" + EditionRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
@ -380,9 +382,7 @@ public static string ReplaceGermanUmlauts(string s)
public static string NormalizeImdbId(string imdbId)
{
var imdbRegex = new Regex(@"^(\d{1,10}|(tt)\d{1,10})$");
if (!imdbRegex.IsMatch(imdbId))
if (!ImdbIdRegex.IsMatch(imdbId))
{
return null;
}