2020-02-09 02:35:16 +00:00
|
|
|
using System;
|
2015-04-13 06:25:21 +00:00
|
|
|
using System.Collections.Generic;
|
2015-04-18 20:18:14 +00:00
|
|
|
using System.Globalization;
|
2015-04-13 06:25:21 +00:00
|
|
|
using System.Linq;
|
2017-04-15 08:45:10 +00:00
|
|
|
using System.Text.RegularExpressions;
|
2018-03-10 08:05:56 +00:00
|
|
|
using Jackett.Common.Utils;
|
2015-04-13 06:25:21 +00:00
|
|
|
|
2018-03-10 08:05:56 +00:00
|
|
|
namespace Jackett.Common.Models
|
2015-04-13 06:25:21 +00:00
|
|
|
{
|
|
|
|
public class TorznabQuery
|
|
|
|
{
|
2015-07-25 23:51:55 +00:00
|
|
|
public string QueryType { get; set; }
|
2015-07-28 23:10:04 +00:00
|
|
|
public int[] Categories { get; set; }
|
2015-07-25 23:51:55 +00:00
|
|
|
public int Extended { get; set; }
|
|
|
|
public string ApiKey { get; set; }
|
|
|
|
public int Limit { get; set; }
|
|
|
|
public int Offset { get; set; }
|
2017-01-31 18:32:32 +00:00
|
|
|
public int? RageID { get; set; }
|
2020-08-16 22:07:04 +00:00
|
|
|
public int? TvdbID { get; set; }
|
2016-03-20 09:40:54 +00:00
|
|
|
public string ImdbID { get; set; }
|
2020-08-16 22:07:04 +00:00
|
|
|
public int? TmdbID { get; set; }
|
2015-07-18 20:35:02 +00:00
|
|
|
|
2015-07-25 23:51:55 +00:00
|
|
|
public int Season { get; set; }
|
|
|
|
public string Episode { get; set; }
|
|
|
|
public string SearchTerm { get; set; }
|
2015-08-02 17:39:32 +00:00
|
|
|
|
2017-10-18 16:30:41 +00:00
|
|
|
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; }
|
|
|
|
|
2020-08-16 21:44:12 +00:00
|
|
|
public string Author { get; set; }
|
|
|
|
public string Title { get; set; }
|
|
|
|
|
2016-12-06 17:24:40 +00:00
|
|
|
public bool IsTest { get; set; }
|
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public string ImdbIDShort => ImdbID?.TrimStart('t');
|
2017-01-25 15:59:36 +00:00
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
protected string[] QueryStringParts;
|
2016-09-16 17:03:54 +00:00
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool IsSearch => QueryType == "search";
|
2017-05-14 16:55:36 +00:00
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool IsTVSearch => QueryType == "tvsearch";
|
2017-05-14 16:55:36 +00:00
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool IsMovieSearch => QueryType == "movie" || (QueryType == "TorrentPotato" && !string.IsNullOrWhiteSpace(SearchTerm));
|
2017-05-14 16:55:36 +00:00
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool IsMusicSearch => QueryType == "music";
|
2017-10-18 16:30:41 +00:00
|
|
|
|
2020-08-16 21:44:12 +00:00
|
|
|
public bool IsBookSearch => QueryType == "book";
|
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool IsTVRageSearch => RageID != null;
|
2017-05-14 16:55:36 +00:00
|
|
|
|
2020-08-16 22:07:04 +00:00
|
|
|
public bool IsTvdbSearch => TvdbID != null;
|
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool IsImdbQuery => ImdbID != null;
|
2017-05-14 16:55:36 +00:00
|
|
|
|
2020-08-16 22:07:04 +00:00
|
|
|
public bool IsTmdbQuery => TmdbID != null;
|
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public bool HasSpecifiedCategories => (Categories != null && Categories.Length > 0);
|
2017-05-14 16:55:36 +00:00
|
|
|
|
2015-08-02 17:39:32 +00:00
|
|
|
public string SanitizedSearchTerm
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2017-08-08 15:02:16 +00:00
|
|
|
var term = SearchTerm;
|
2015-08-02 17:39:32 +00:00
|
|
|
if (SearchTerm == null)
|
2017-08-08 15:02:16 +00:00
|
|
|
term = "";
|
2020-03-27 03:13:38 +00:00
|
|
|
var safeTitle = term.Where(c => (char.IsLetterOrDigit(c)
|
2020-02-25 16:08:03 +00:00
|
|
|
|| char.IsWhiteSpace(c)
|
|
|
|
|| c == '-'
|
|
|
|
|| c == '.'
|
|
|
|
|| c == '_'
|
|
|
|
|| c == '('
|
|
|
|
|| c == ')'
|
|
|
|
|| c == '@'
|
|
|
|
|| c == '/'
|
|
|
|
|| c == '\''
|
|
|
|
|| c == '['
|
|
|
|
|| c == ']'
|
|
|
|
|| c == '+'
|
|
|
|
|| c == '%'
|
2020-03-27 03:13:38 +00:00
|
|
|
));
|
|
|
|
return string.Concat(safeTitle);
|
2015-08-02 17:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-18 20:18:14 +00:00
|
|
|
|
2015-07-29 20:11:30 +00:00
|
|
|
public TorznabQuery()
|
|
|
|
{
|
|
|
|
Categories = new int[0];
|
2016-12-06 17:24:40 +00:00
|
|
|
IsTest = false;
|
2015-07-29 20:11:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 15:02:16 +00:00
|
|
|
public TorznabQuery CreateFallback(string search)
|
|
|
|
{
|
2017-06-03 13:04:51 +00:00
|
|
|
var ret = Clone();
|
2017-08-08 15:02:16 +00:00
|
|
|
if (Categories == null || Categories.Length == 0)
|
|
|
|
{
|
2017-06-03 13:04:51 +00:00
|
|
|
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,
|
2017-08-08 15:02:16 +00:00
|
|
|
TorznabCatType.MoviesDVD.ID,
|
|
|
|
TorznabCatType.MoviesWEBDL.ID,
|
2019-03-12 23:12:29 +00:00
|
|
|
TorznabCatType.MoviesUHD.ID,
|
2017-06-03 13:04:51 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
ret.SearchTerm = search;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-08 15:02:16 +00:00
|
|
|
public TorznabQuery Clone()
|
|
|
|
{
|
2020-03-26 22:15:28 +00:00
|
|
|
var ret = new TorznabQuery
|
|
|
|
{
|
|
|
|
QueryType = QueryType,
|
|
|
|
Extended = Extended,
|
|
|
|
ApiKey = ApiKey,
|
|
|
|
Limit = Limit,
|
|
|
|
Offset = Offset,
|
|
|
|
Season = Season,
|
|
|
|
Episode = Episode,
|
|
|
|
SearchTerm = SearchTerm,
|
|
|
|
IsTest = IsTest,
|
|
|
|
Album = Album,
|
|
|
|
Artist = Artist,
|
|
|
|
Label = Label,
|
|
|
|
Track = Track,
|
|
|
|
Year = Year,
|
2020-08-16 21:44:12 +00:00
|
|
|
Author = Author,
|
|
|
|
Title = Title,
|
2020-03-26 22:15:28 +00:00
|
|
|
RageID = RageID,
|
2020-08-16 22:07:04 +00:00
|
|
|
TvdbID = TvdbID,
|
|
|
|
ImdbID = ImdbID,
|
|
|
|
TmdbID = TmdbID
|
2020-03-26 22:15:28 +00:00
|
|
|
};
|
|
|
|
if (Categories?.Length > 0)
|
2017-08-08 15:02:16 +00:00
|
|
|
{
|
|
|
|
ret.Categories = new int[Categories.Length];
|
|
|
|
Array.Copy(Categories, ret.Categories, Categories.Length);
|
2017-06-03 13:04:51 +00:00
|
|
|
}
|
2020-03-26 22:15:28 +00:00
|
|
|
if (QueryStringParts?.Length > 0)
|
2017-08-08 15:02:16 +00:00
|
|
|
{
|
|
|
|
ret.QueryStringParts = new string[QueryStringParts.Length];
|
|
|
|
Array.Copy(QueryStringParts, ret.QueryStringParts, QueryStringParts.Length);
|
2017-06-03 13:04:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-02-25 16:08:03 +00:00
|
|
|
public string GetQueryString() => (SanitizedSearchTerm + " " + GetEpisodeSearchString()).Trim();
|
2015-08-14 21:20:51 +00:00
|
|
|
|
2016-09-16 17:03:54 +00:00
|
|
|
// Some trackers don't support AND logic for search terms resulting in unwanted results.
|
|
|
|
// Using this method we can AND filter it within jackett.
|
2016-12-29 11:19:25 +00:00
|
|
|
// With limit we can limit the amount of characters which should be compared (use it if a tracker doesn't return the full title).
|
2017-04-15 08:45:10 +00:00
|
|
|
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)
|
|
|
|
{
|
2020-04-11 19:02:00 +00:00
|
|
|
var queryString = !string.IsNullOrWhiteSpace(queryStringOverride) ? queryStringOverride : GetQueryString();
|
|
|
|
|
2017-04-15 08:45:10 +00:00
|
|
|
if (limit != null && limit > 0)
|
|
|
|
{
|
|
|
|
if (limit > queryString.Length)
|
|
|
|
limit = queryString.Length;
|
|
|
|
queryString = queryString.Substring(0, (int)limit);
|
|
|
|
}
|
2020-02-10 22:16:19 +00:00
|
|
|
var SplitRegex = new Regex("[^a-zA-Z0-9]+");
|
2017-04-15 08:45:10 +00:00
|
|
|
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;
|
2016-09-16 17:03:54 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 20:18:14 +00:00
|
|
|
public string GetEpisodeSearchString()
|
|
|
|
{
|
|
|
|
if (Season == 0)
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
|
string episodeString;
|
2020-02-10 22:16:19 +00:00
|
|
|
if (DateTime.TryParseExact(string.Format("{0} {1}", Season, Episode), "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
|
2015-04-18 20:18:14 +00:00
|
|
|
episodeString = showDate.ToString("yyyy.MM.dd");
|
2015-04-20 05:10:50 +00:00
|
|
|
else if (string.IsNullOrEmpty(Episode))
|
|
|
|
episodeString = string.Format("S{0:00}", Season);
|
2015-04-18 20:18:14 +00:00
|
|
|
else
|
2017-06-25 16:25:16 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
episodeString = string.Format("S{0:00}E{1:00}", Season, ParseUtil.CoerceInt(Episode));
|
2017-08-08 15:02:16 +00:00
|
|
|
}
|
|
|
|
catch (FormatException) // e.g. seaching for S01E01A
|
2017-06-25 16:25:16 +00:00
|
|
|
{
|
|
|
|
episodeString = string.Format("S{0:00}E{1}", Season, Episode);
|
|
|
|
}
|
2015-04-16 06:04:28 +00:00
|
|
|
|
2015-07-18 20:35:02 +00:00
|
|
|
}
|
2017-08-08 15:02:16 +00:00
|
|
|
return episodeString;
|
2015-04-13 06:25:21 +00:00
|
|
|
}
|
2015-08-14 21:20:51 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2015-04-13 06:25:21 +00:00
|
|
|
}
|
|
|
|
}
|