diff --git a/src/Jackett.Common/Definitions/aither.yml b/src/Jackett.Common/Definitions/aither.yml index 5bc827c7e..df391dbb7 100644 --- a/src/Jackett.Common/Definitions/aither.yml +++ b/src/Jackett.Common/Definitions/aither.yml @@ -28,8 +28,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] settings: - name: username @@ -89,8 +89,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" diff --git a/src/Jackett.Common/Definitions/blutopia.yml b/src/Jackett.Common/Definitions/blutopia.yml index bec100c89..f5fa5032e 100644 --- a/src/Jackett.Common/Definitions/blutopia.yml +++ b/src/Jackett.Common/Definitions/blutopia.yml @@ -18,8 +18,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] settings: - name: username @@ -79,8 +79,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" @@ -131,6 +131,10 @@ search: optional: true selector: a[href*="imdb.com/title/tt"] attribute: href + tmdbid: + optional: true + selector: a[href*="themoviedb.org/movie/"] + attribute: href date: selector: time filters: @@ -184,4 +188,4 @@ search: minimumseedtime: # 7 days (as seconds = 7 x 24 x 60 x 60) text: 604800 -# UNIT3D 2.7.0 +# UNIT3D 2.7.0b diff --git a/src/Jackett.Common/Definitions/channelx.yml b/src/Jackett.Common/Definitions/channelx.yml index 396d17928..9e900ea31 100644 --- a/src/Jackett.Common/Definitions/channelx.yml +++ b/src/Jackett.Common/Definitions/channelx.yml @@ -19,8 +19,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] settings: - name: username @@ -80,8 +80,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" diff --git a/src/Jackett.Common/Definitions/desireleasers.yml b/src/Jackett.Common/Definitions/desireleasers.yml index 9cd24b5f8..f59a5e2e5 100644 --- a/src/Jackett.Common/Definitions/desireleasers.yml +++ b/src/Jackett.Common/Definitions/desireleasers.yml @@ -18,8 +18,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] music-search: [q] settings: @@ -80,8 +80,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" diff --git a/src/Jackett.Common/Definitions/freetorrent.yml b/src/Jackett.Common/Definitions/freetorrent.yml index a6a010d8b..fc67dadd3 100644 --- a/src/Jackett.Common/Definitions/freetorrent.yml +++ b/src/Jackett.Common/Definitions/freetorrent.yml @@ -26,8 +26,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] music-search: [q] settings: @@ -88,8 +88,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" diff --git a/src/Jackett.Common/Definitions/shareisland.yml b/src/Jackett.Common/Definitions/shareisland.yml index d0513e407..ef244b64c 100644 --- a/src/Jackett.Common/Definitions/shareisland.yml +++ b/src/Jackett.Common/Definitions/shareisland.yml @@ -48,8 +48,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] music-search: [q] settings: @@ -110,8 +110,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" diff --git a/src/Jackett.Common/Definitions/tellytorrent.yml b/src/Jackett.Common/Definitions/tellytorrent.yml index d59cae98f..d56c46e93 100644 --- a/src/Jackett.Common/Definitions/tellytorrent.yml +++ b/src/Jackett.Common/Definitions/tellytorrent.yml @@ -23,8 +23,8 @@ caps: modes: search: [q, imdbid] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] + tv-search: [q, season, ep, imdbid, tvdbid] + movie-search: [q, imdbid, tmdbid] music-search: [q] settings: @@ -85,8 +85,8 @@ search: description: "" uploader: "" imdb: "{{ .Query.IMDBIDShort }}" - tvdb: "" - tmdb: "" + tvdb: "{{ .Query.TVDBID }}" + tmdb: "{{ .Query.TMDBID }}" mal: "" igdb: "" sorting: "{{ .Config.sort }}" diff --git a/src/Jackett.Common/Indexers/BaseIndexer.cs b/src/Jackett.Common/Indexers/BaseIndexer.cs index 99923896a..e1c5c73ad 100644 --- a/src/Jackett.Common/Indexers/BaseIndexer.cs +++ b/src/Jackett.Common/Indexers/BaseIndexer.cs @@ -303,8 +303,12 @@ namespace Jackett.Common.Indexers return true; if (caps.SupportsTVRageSearch && query.IsTVRageSearch) return true; + if (caps.SupportsTvdbSearch && query.IsTvdbSearch) + return true; if (caps.SupportsImdbMovieSearch && query.IsImdbQuery) return true; + if (caps.SupportsTmdbMovieSearch && query.IsTmdbQuery) + return true; return false; } diff --git a/src/Jackett.Common/Indexers/CardigannIndexer.cs b/src/Jackett.Common/Indexers/CardigannIndexer.cs index 7329eddb1..d6d8668d8 100644 --- a/src/Jackett.Common/Indexers/CardigannIndexer.cs +++ b/src/Jackett.Common/Indexers/CardigannIndexer.cs @@ -113,7 +113,11 @@ namespace Jackett.Common.Indexers Type = Definition.Type; TorznabCaps = new TorznabCapabilities { + // SupportsImdbTVSearch temporarily disabled due to #8107 + // SupportsImdbTVSearch = Definition.Caps.Modes.Any(c => c.Key == "tv-search" && c.Value.Contains("imdbid")), + SupportsTvdbSearch = Definition.Caps.Modes.Any(c => c.Key == "tv-search" && c.Value.Contains("tvdbid")), SupportsImdbMovieSearch = Definition.Caps.Modes.Any(c => c.Key == "movie-search" && c.Value.Contains("imdbid")), + SupportsTmdbMovieSearch = Definition.Caps.Modes.Any(c => c.Key == "movie-search" && c.Value.Contains("tmdbid")), BookSearchAvailable = Definition.Caps.Modes.Any(c => c.Key == "book-search" && c.Value.Contains("author") && c.Value.Contains("title")) }; if (Definition.Caps.Modes.ContainsKey("music-search")) @@ -1226,10 +1230,11 @@ namespace Jackett.Common.Indexers variables[".Query.Extended"] = query.Extended.ToString(); variables[".Query.Categories"] = query.Categories; variables[".Query.APIKey"] = query.ApiKey; - variables[".Query.TVDBID"] = null; + variables[".Query.TVDBID"] = query.TvdbID.ToString(); variables[".Query.TVRageID"] = query.RageID; variables[".Query.IMDBID"] = query.ImdbID; variables[".Query.IMDBIDShort"] = query.ImdbIDShort; + variables[".Query.TMDBID"] = query.TmdbID.ToString(); variables[".Query.TVMazeID"] = null; variables[".Query.TraktID"] = null; variables[".Query.Album"] = query.Album; @@ -1561,6 +1566,13 @@ namespace Jackett.Common.Indexers release.Imdb = ParseUtil.GetLongFromString(value); value = release.Imdb.ToString(); break; + case "tmdbid": + var TmdbIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var TmdbIDMatch = TmdbIDRegEx.Match(value); + var TmdbID = TmdbIDMatch.Groups[1].Value; + release.TMDb = ParseUtil.CoerceLong(TmdbID); + value = release.TMDb.ToString(); + break; case "rageid": var RageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var RageIDMatch = RageIDRegEx.Match(value); @@ -1623,6 +1635,12 @@ namespace Jackett.Common.Indexers if (query.ImdbID != null && TorznabCaps.SupportsImdbMovieSearch) break; // skip andmatch filter for imdb searches + if (query.TmdbID != null && TorznabCaps.SupportsTmdbMovieSearch) + break; // skip andmatch filter for tmdb searches + + if (query.TvdbID != null && TorznabCaps.SupportsTvdbSearch) + break; // skip andmatch filter for tvdb searches + var queryKeywords = variables[".Keywords"] as string; if (!query.MatchQueryStringAND(release.Title, CharacterLimit, queryKeywords)) diff --git a/src/Jackett.Common/Models/DTO/TorznabRequest.cs b/src/Jackett.Common/Models/DTO/TorznabRequest.cs index a2fe9ca7e..08251dc46 100644 --- a/src/Jackett.Common/Models/DTO/TorznabRequest.cs +++ b/src/Jackett.Common/Models/DTO/TorznabRequest.cs @@ -9,10 +9,12 @@ namespace Jackett.Common.Models.DTO public string q { get; set; } public string cat { get; set; } public string imdbid { get; set; } + public string tmdbid { get; set; } public string extended { get; set; } public string limit { get; set; } public string offset { get; set; } public string rid { get; set; } + public string tvdbid { get; set; } public string season { get; set; } public string ep { get; set; } public string album { get; set; } @@ -57,10 +59,14 @@ namespace Jackett.Common.Models.DTO if (!string.IsNullOrWhiteSpace(request.rid)) query.RageID = int.Parse(request.rid); - + if (!string.IsNullOrWhiteSpace(request.tvdbid)) + query.TvdbID = int.Parse(request.tvdbid); if (!string.IsNullOrWhiteSpace(request.season)) query.Season = int.Parse(request.season); + if (!string.IsNullOrWhiteSpace(request.tmdbid)) + query.TmdbID = int.Parse(request.tmdbid); + if (!string.IsNullOrWhiteSpace(request.album)) query.Album = request.album; if (!string.IsNullOrWhiteSpace(request.artist)) diff --git a/src/Jackett.Common/Models/ResultPage.cs b/src/Jackett.Common/Models/ResultPage.cs index dd939baec..2c87806d7 100644 --- a/src/Jackett.Common/Models/ResultPage.cs +++ b/src/Jackett.Common/Models/ResultPage.cs @@ -82,6 +82,7 @@ namespace Jackett.Common.Models getTorznabElement("rageid", r.RageID), getTorznabElement("thetvdb", r.TVDBId), getTorznabElement("imdb", r.Imdb == null ? null : ((long)r.Imdb).ToString("D7")), + getTorznabElement("tmdb", r.TMDb), getTorznabElement("author", r.Author), getTorznabElement("booktitle", r.BookTitle), getTorznabElement("seeders", r.Seeders), diff --git a/src/Jackett.Common/Models/TorznabCapabilities.cs b/src/Jackett.Common/Models/TorznabCapabilities.cs index 4ae8fc646..8afc24a46 100644 --- a/src/Jackett.Common/Models/TorznabCapabilities.cs +++ b/src/Jackett.Common/Models/TorznabCapabilities.cs @@ -17,8 +17,10 @@ namespace Jackett.Common.Models public bool MovieSearchAvailable { get; set; } public bool SupportsTVRageSearch { get; set; } + public bool SupportsTvdbSearch { get; set; } public bool SupportsImdbMovieSearch { get; set; } + public bool SupportsTmdbMovieSearch { get; set; } public bool SupportsImdbTVSearch { get; set; } @@ -37,7 +39,9 @@ namespace Jackett.Common.Models TVSearchAvailable = true; MovieSearchAvailable = false; SupportsTVRageSearch = false; + SupportsTvdbSearch = false; SupportsImdbMovieSearch = false; + SupportsTmdbMovieSearch = false; SupportsImdbTVSearch = false; SupportedMusicSearchParamsList = new List(); BookSearchAvailable = false; @@ -48,7 +52,9 @@ namespace Jackett.Common.Models SearchAvailable = true; TVSearchAvailable = true; SupportsTVRageSearch = false; + SupportsTvdbSearch = false; SupportsImdbMovieSearch = false; + SupportsTmdbMovieSearch = false; SupportsImdbTVSearch = false; SupportedMusicSearchParamsList = new List(); BookSearchAvailable = false; @@ -64,6 +70,8 @@ namespace Jackett.Common.Models var parameters = new List() { "q", "season", "ep" }; if (SupportsTVRageSearch) parameters.Add("rid"); + if (SupportsTvdbSearch) + parameters.Add("tvdbid"); if (SupportsImdbTVSearch) parameters.Add("imdbid"); return string.Join(",", parameters); @@ -77,6 +85,8 @@ namespace Jackett.Common.Models var parameters = new List() { "q" }; if (SupportsImdbMovieSearch) parameters.Add("imdbid"); + if (SupportsTmdbMovieSearch) + parameters.Add("tmdbid"); return string.Join(",", parameters); } } @@ -170,7 +180,9 @@ namespace Jackett.Common.Models lhs.MovieSearchAvailable = lhs.MovieSearchAvailable || rhs.MovieSearchAvailable; lhs.BookSearchAvailable = lhs.BookSearchAvailable || rhs.BookSearchAvailable; lhs.SupportsTVRageSearch = lhs.SupportsTVRageSearch || rhs.SupportsTVRageSearch; + lhs.SupportsTvdbSearch = lhs.SupportsTvdbSearch || rhs.SupportsTvdbSearch; lhs.SupportsImdbMovieSearch = lhs.SupportsImdbMovieSearch || rhs.SupportsImdbMovieSearch; + lhs.SupportsTmdbMovieSearch = lhs.SupportsTmdbMovieSearch || rhs.SupportsTmdbMovieSearch; lhs.SupportsImdbTVSearch = lhs.SupportsImdbTVSearch || rhs.SupportsImdbTVSearch; lhs.Categories.AddRange(rhs.Categories.Where(x => x.ID < 100000).Except(lhs.Categories)); // exclude indexer specific categories (>= 100000) diff --git a/src/Jackett.Common/Models/TorznabQuery.cs b/src/Jackett.Common/Models/TorznabQuery.cs index 127aa417b..c110a9749 100644 --- a/src/Jackett.Common/Models/TorznabQuery.cs +++ b/src/Jackett.Common/Models/TorznabQuery.cs @@ -16,7 +16,9 @@ namespace Jackett.Common.Models public int Limit { get; set; } public int Offset { get; set; } public int? RageID { get; set; } + public int? TvdbID { get; set; } public string ImdbID { get; set; } + public int? TmdbID { get; set; } public int Season { get; set; } public string Episode { get; set; } @@ -50,8 +52,12 @@ namespace Jackett.Common.Models public bool IsTVRageSearch => RageID != null; + public bool IsTvdbSearch => TvdbID != null; + public bool IsImdbQuery => ImdbID != null; + public bool IsTmdbQuery => TmdbID != null; + public bool HasSpecifiedCategories => (Categories != null && Categories.Length > 0); public string SanitizedSearchTerm @@ -129,7 +135,9 @@ namespace Jackett.Common.Models Author = Author, Title = Title, RageID = RageID, - ImdbID = ImdbID + TvdbID = TvdbID, + ImdbID = ImdbID, + TmdbID = TmdbID }; if (Categories?.Length > 0) { diff --git a/src/Jackett.Server/Controllers/ResultsController.cs b/src/Jackett.Server/Controllers/ResultsController.cs index 76f8050e1..fa54306d1 100644 --- a/src/Jackett.Server/Controllers/ResultsController.cs +++ b/src/Jackett.Server/Controllers/ResultsController.cs @@ -365,6 +365,24 @@ namespace Jackett.Server.Controllers } } + if (CurrentQuery.TmdbID != null) + { + if (CurrentQuery.IsMovieSearch && !CurrentIndexer.TorznabCaps.SupportsTmdbMovieSearch) + { + logger.Warn($"A search request with tmdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.DisplayName} doesn't support it."); + return GetErrorXML(203, "Function Not Available: tmdbid is not supported for movie search by this indexer"); + } + } + + if (CurrentQuery.TvdbID != null) + { + if (CurrentQuery.IsTVSearch && !CurrentIndexer.TorznabCaps.SupportsTvdbSearch) + { + logger.Warn($"A search request with tvdbid from {Request.HttpContext.Connection.RemoteIpAddress} was made but the indexer {CurrentIndexer.DisplayName} doesn't support it."); + return GetErrorXML(203, "Function Not Available: tvdbid is not supported for movie search by this indexer"); + } + } + try { var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);