Jackett/src/Jackett.Common/Models/TorznabQuery.cs

223 lines
8.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Jackett.Common.Utils;
namespace Jackett.Common.Models
{
public class TorznabQuery
{
public string QueryType { get; set; }
public int[] Categories { get; set; }
public int Extended { get; set; }
public string ApiKey { get; set; }
public int Limit { get; set; }
public int Offset { get; set; }
public int? RageID { get; set; }
public string ImdbID { get; set; }
public int Season { get; set; }
public string Episode { get; set; }
public string SearchTerm { get; set; }
public string Album { get; set; }
public string Artist { get; set; }
public string Label { get; set; }
public string Track { get; set; }
public int? Year { get; set; }
public ICollection<string> Genre { get; set; }
public bool IsTest { get; set; }
public string ImdbIDShort => ImdbID?.TrimStart('t');
protected string[] QueryStringParts;
public bool IsSearch => QueryType == "search";
public bool IsTVSearch => QueryType == "tvsearch";
public bool IsMovieSearch => QueryType == "movie" || (QueryType == "TorrentPotato" && !string.IsNullOrWhiteSpace(SearchTerm));
public bool IsMusicSearch => QueryType == "music";
public bool IsTVRageSearch => RageID != null;
public bool IsImdbQuery => ImdbID != null;
public bool HasSpecifiedCategories => (Categories != null && Categories.Length > 0);
public string SanitizedSearchTerm
{
get
{
var term = SearchTerm;
if (SearchTerm == null)
term = "";
var safetitle = term.Where(c => (char.IsLetterOrDigit(c)
|| char.IsWhiteSpace(c)
|| c == '-'
|| c == '.'
|| c == '_'
|| c == '('
|| c == ')'
|| c == '@'
|| c == '/'
|| c == '\''
|| c == '['
|| c == ']'
|| c == '+'
|| c == '%'
)).AsString();
return safetitle;
}
}
public TorznabQuery()
{
Categories = new int[0];
IsTest = false;
}
public TorznabQuery CreateFallback(string search)
{
var ret = Clone();
if (Categories == null || Categories.Length == 0)
{
ret.Categories = new int[]{ TorznabCatType.Movies.ID,
TorznabCatType.MoviesForeign.ID,
TorznabCatType.MoviesOther.ID,
TorznabCatType.MoviesSD.ID,
TorznabCatType.MoviesHD.ID,
TorznabCatType.Movies3D.ID,
TorznabCatType.MoviesBluRay.ID,
TorznabCatType.MoviesDVD.ID,
TorznabCatType.MoviesWEBDL.ID,
TorznabCatType.MoviesUHD.ID,
};
}
ret.SearchTerm = search;
return ret;
}
public TorznabQuery Clone()
{
var ret = new TorznabQuery();
ret.QueryType = QueryType;
if (Categories != null && Categories.Length > 0)
{
ret.Categories = new int[Categories.Length];
Array.Copy(Categories, ret.Categories, Categories.Length);
}
ret.Extended = Extended;
ret.ApiKey = ApiKey;
ret.Limit = Limit;
ret.Offset = Offset;
ret.Season = Season;
ret.Episode = Episode;
ret.SearchTerm = SearchTerm;
ret.IsTest = IsTest;
ret.Album = Album;
ret.Artist = Artist;
ret.Label = Label;
ret.Track = Track;
ret.Year = Year;
if (Genre != null)
{
// Make a copied list and then don't use it?
Genre.Select(item => item.Clone()).ToList();
}
if (QueryStringParts != null && QueryStringParts.Length > 0)
{
ret.QueryStringParts = new string[QueryStringParts.Length];
Array.Copy(QueryStringParts, ret.QueryStringParts, QueryStringParts.Length);
}
ret.RageID = RageID;
ret.ImdbID = ImdbID;
return ret;
}
public string GetQueryString() => (SanitizedSearchTerm + " " + GetEpisodeSearchString()).Trim();
// Some trackers don't support AND logic for search terms resulting in unwanted results.
// Using this method we can AND filter it within jackett.
// With limit we can limit the amount of characters which should be compared (use it if a tracker doesn't return the full title).
public bool MatchQueryStringAND(string title, int? limit = null, string queryStringOverride = null)
{
// We cache the regex split results so we have to do it only once for each query.
if (QueryStringParts == null)
{
var queryString = GetQueryString();
if (queryStringOverride != null)
queryString = queryStringOverride;
if (limit != null && limit > 0)
{
if (limit > queryString.Length)
limit = queryString.Length;
queryString = queryString.Substring(0, (int)limit);
}
var SplitRegex = new Regex("[^a-zA-Z0-9]+");
QueryStringParts = SplitRegex.Split(queryString);
}
// Check if each part of the query string is in the given title.
foreach (var QueryStringPart in QueryStringParts)
{
if (title.IndexOf(QueryStringPart, StringComparison.OrdinalIgnoreCase) < 0)
{
return false;
}
}
return true;
}
public string GetEpisodeSearchString()
{
if (Season == 0)
return string.Empty;
string episodeString;
if (DateTime.TryParseExact(string.Format("{0} {1}", Season, Episode), "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
episodeString = showDate.ToString("yyyy.MM.dd");
else if (string.IsNullOrEmpty(Episode))
episodeString = string.Format("S{0:00}", Season);
else
{
try
{
episodeString = string.Format("S{0:00}E{1:00}", Season, ParseUtil.CoerceInt(Episode));
}
catch (FormatException) // e.g. seaching for S01E01A
{
episodeString = string.Format("S{0:00}E{1}", Season, Episode);
}
}
return episodeString;
}
public void ExpandCatsToSubCats()
{
if (Categories.Count() == 0)
return;
var newCatList = new List<int>();
newCatList.AddRange(Categories);
foreach (var cat in Categories)
{
var majorCat = TorznabCatType.AllCats.Where(c => c.ID == cat).FirstOrDefault();
// If we search for TV we should also search for all sub cats
if (majorCat != null)
{
newCatList.AddRange(majorCat.SubCategories.Select(s => s.ID));
}
}
Categories = newCatList.Distinct().ToArray();
}
}
}