mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-17 17:34:09 +02:00
Add support for book-search (#9306)
This commit is contained in:
@@ -18,6 +18,7 @@ caps:
|
|||||||
|
|
||||||
modes:
|
modes:
|
||||||
search: [q]
|
search: [q]
|
||||||
|
book-search: [q, author, title]
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
- name: username
|
- name: username
|
||||||
@@ -51,14 +52,12 @@ settings:
|
|||||||
|
|
||||||
login:
|
login:
|
||||||
path: /
|
path: /
|
||||||
method: form
|
method: post
|
||||||
form: form#loginform
|
|
||||||
submitpath: /
|
|
||||||
inputs:
|
inputs:
|
||||||
action: login
|
|
||||||
username: "{{ .Config.username }}"
|
username: "{{ .Config.username }}"
|
||||||
password: "{{ .Config.password }}"
|
password: "{{ .Config.password }}"
|
||||||
keeploggedin: 1
|
keeplogged: 1
|
||||||
|
login: "Log In!"
|
||||||
error:
|
error:
|
||||||
- selector: center:first-of-type
|
- selector: center:first-of-type
|
||||||
test:
|
test:
|
||||||
@@ -69,7 +68,7 @@ search:
|
|||||||
paths:
|
paths:
|
||||||
- path: torrents/
|
- path: torrents/
|
||||||
inputs:
|
inputs:
|
||||||
search: "{{ .Keywords }}"
|
search: "{{ if .Query.Author }} @authors {{ .Query.Author }}{{else}}{{end}}{{ if .Query.Title }} @title {{ .Query.Title }}{{else}}{{end}}{{ .Keywords }}"
|
||||||
$raw: "{{ range .Categories }}cat[]={{.}}&{{end}}"
|
$raw: "{{ range .Categories }}cat[]={{.}}&{{end}}"
|
||||||
orderby: "{{ .Config.orderby }}"
|
orderby: "{{ .Config.orderby }}"
|
||||||
order: "{{ .Config.order }}"
|
order: "{{ .Config.order }}"
|
||||||
@@ -86,39 +85,48 @@ search:
|
|||||||
div[title="Comics"]: 4
|
div[title="Comics"]: 4
|
||||||
div[title="Ebooks"]: 5
|
div[title="Ebooks"]: 5
|
||||||
div[title="Magazines"]: 7
|
div[title="Magazines"]: 7
|
||||||
|
_author:
|
||||||
|
selector: .authorLink
|
||||||
|
optional: true
|
||||||
|
_editor:
|
||||||
|
selector: .editorLink
|
||||||
|
optional: true
|
||||||
|
author:
|
||||||
|
text: "{{ or (.Result._author) (.Result._editor) }}"
|
||||||
_year:
|
_year:
|
||||||
selector: .torYear
|
selector: .torYear
|
||||||
optional: true
|
optional: true
|
||||||
_filetype:
|
_filetype:
|
||||||
selector: .torFormat
|
selector: .torFormat
|
||||||
optional: true
|
optional: true
|
||||||
title:
|
_retail:
|
||||||
|
selector: .torRetail
|
||||||
|
optional: true
|
||||||
|
booktitle:
|
||||||
selector: .title a
|
selector: .title a
|
||||||
|
title:
|
||||||
|
text: "{{.Result.booktitle}}"
|
||||||
filters:
|
filters:
|
||||||
- name: append
|
- name: append
|
||||||
args: "{{ if .Result._year }} {{ .Result._year }}{{else}}{{end}}{{ if .Result._filetype }} {{ .Result._filetype }}{{else}}{{end}}"
|
args: "{{ if .Result.author }} by {{ .Result.author }}{{else}}{{end}}{{ if .Result._year }} {{ .Result._year }}{{else}}{{end}}{{ if .Result._filetype }} {{ .Result._filetype }}{{else}}{{end}}{{ if .Result._retail }} {{ .Result._retail }}{{else}}{{end}}"
|
||||||
details:
|
details:
|
||||||
selector: .title a
|
selector: .title a
|
||||||
attribute: href
|
attribute: href
|
||||||
date:
|
date:
|
||||||
optional: true
|
optional: true
|
||||||
selector: .t_files_size_added time
|
selector: .t_files_size_added time
|
||||||
filters:
|
attribute: datetime
|
||||||
- name: timeago
|
|
||||||
download:
|
download:
|
||||||
selector: a[title="Download"]
|
selector: a[title="Download"]
|
||||||
attribute: href
|
attribute: href
|
||||||
# files:
|
files:
|
||||||
# selector: .t_files_size_added
|
|
||||||
# filters:
|
|
||||||
# - name: regexp
|
|
||||||
# args: "^\\s*(\\d+)\\s*file"
|
|
||||||
size:
|
|
||||||
selector: .t_files_size_added
|
selector: .t_files_size_added
|
||||||
filters:
|
filters:
|
||||||
- name: split
|
- name: regexp
|
||||||
args: [",", 1]
|
args: "^\\s*(\\d+)\\s*file"
|
||||||
- name: trim
|
size:
|
||||||
|
selector: .t_files_size_added span
|
||||||
|
attribute: data-bytecount
|
||||||
seeders:
|
seeders:
|
||||||
text: 0
|
text: 0
|
||||||
seeders:
|
seeders:
|
||||||
|
@@ -299,6 +299,8 @@ namespace Jackett.Common.Indexers
|
|||||||
return true;
|
return true;
|
||||||
if (caps.MusicSearchAvailable && query.IsMusicSearch)
|
if (caps.MusicSearchAvailable && query.IsMusicSearch)
|
||||||
return true;
|
return true;
|
||||||
|
if (caps.BookSearchAvailable && query.IsBookSearch)
|
||||||
|
return true;
|
||||||
if (caps.SupportsTVRageSearch && query.IsTVRageSearch)
|
if (caps.SupportsTVRageSearch && query.IsTVRageSearch)
|
||||||
return true;
|
return true;
|
||||||
if (caps.SupportsImdbMovieSearch && query.IsImdbQuery)
|
if (caps.SupportsImdbMovieSearch && query.IsImdbQuery)
|
||||||
|
@@ -113,7 +113,8 @@ namespace Jackett.Common.Indexers
|
|||||||
Type = Definition.Type;
|
Type = Definition.Type;
|
||||||
TorznabCaps = new TorznabCapabilities
|
TorznabCaps = new TorznabCapabilities
|
||||||
{
|
{
|
||||||
SupportsImdbMovieSearch = Definition.Caps.Modes.Any(c => c.Key == "movie-search" && c.Value.Contains("imdbid"))
|
SupportsImdbMovieSearch = Definition.Caps.Modes.Any(c => c.Key == "movie-search" && c.Value.Contains("imdbid")),
|
||||||
|
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"))
|
if (Definition.Caps.Modes.ContainsKey("music-search"))
|
||||||
TorznabCaps.SupportedMusicSearchParamsList = Definition.Caps.Modes["music-search"];
|
TorznabCaps.SupportedMusicSearchParamsList = Definition.Caps.Modes["music-search"];
|
||||||
@@ -1237,6 +1238,8 @@ namespace Jackett.Common.Indexers
|
|||||||
variables[".Query.Track"] = query.Track;
|
variables[".Query.Track"] = query.Track;
|
||||||
//variables[".Query.Genre"] = query.Genre ?? new List<string>();
|
//variables[".Query.Genre"] = query.Genre ?? new List<string>();
|
||||||
variables[".Query.Episode"] = query.GetEpisodeSearchString();
|
variables[".Query.Episode"] = query.GetEpisodeSearchString();
|
||||||
|
variables[".Query.Author"] = query.Author;
|
||||||
|
variables[".Query.Title"] = query.Title;
|
||||||
|
|
||||||
var mappedCategories = MapTorznabCapsToTrackers(query);
|
var mappedCategories = MapTorznabCapsToTrackers(query);
|
||||||
if (mappedCategories.Count == 0)
|
if (mappedCategories.Count == 0)
|
||||||
@@ -1325,6 +1328,8 @@ namespace Jackett.Common.Indexers
|
|||||||
}
|
}
|
||||||
var searchUrlUri = new Uri(searchUrl);
|
var searchUrlUri = new Uri(searchUrl);
|
||||||
|
|
||||||
|
logger.Info($"Fetching: {searchUrl}");
|
||||||
|
|
||||||
// send HTTP request
|
// send HTTP request
|
||||||
WebClientStringResult response = null;
|
WebClientStringResult response = null;
|
||||||
Dictionary<string, string> headers = null;
|
Dictionary<string, string> headers = null;
|
||||||
@@ -1570,6 +1575,12 @@ namespace Jackett.Common.Indexers
|
|||||||
release.TVDBId = ParseUtil.CoerceLong(TVDBId);
|
release.TVDBId = ParseUtil.CoerceLong(TVDBId);
|
||||||
value = release.TVDBId.ToString();
|
value = release.TVDBId.ToString();
|
||||||
break;
|
break;
|
||||||
|
case "author":
|
||||||
|
release.Author = value;
|
||||||
|
break;
|
||||||
|
case "booktitle":
|
||||||
|
release.BookTitle = value;
|
||||||
|
break;
|
||||||
case "banner":
|
case "banner":
|
||||||
if (!string.IsNullOrWhiteSpace(value))
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
{
|
{
|
||||||
|
@@ -21,6 +21,8 @@ namespace Jackett.Common.Models.DTO
|
|||||||
public string track { get; set; }
|
public string track { get; set; }
|
||||||
public string year { get; set; }
|
public string year { get; set; }
|
||||||
public string genre { get; set; }
|
public string genre { get; set; }
|
||||||
|
public string author { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
public string configured { get; set; }
|
public string configured { get; set; }
|
||||||
|
|
||||||
public static TorznabQuery ToTorznabQuery(TorznabRequest request)
|
public static TorznabQuery ToTorznabQuery(TorznabRequest request)
|
||||||
@@ -72,6 +74,11 @@ namespace Jackett.Common.Models.DTO
|
|||||||
if (!string.IsNullOrWhiteSpace(request.genre))
|
if (!string.IsNullOrWhiteSpace(request.genre))
|
||||||
query.Genre = request.genre.Split(',');
|
query.Genre = request.genre.Split(',');
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.title))
|
||||||
|
query.Title = request.title;
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.author))
|
||||||
|
query.Author = request.author;
|
||||||
|
|
||||||
query.ExpandCatsToSubCats();
|
query.ExpandCatsToSubCats();
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
|
@@ -24,6 +24,8 @@ namespace Jackett.Common.Models
|
|||||||
public long? TVDBId { get; set; }
|
public long? TVDBId { get; set; }
|
||||||
public long? Imdb { get; set; }
|
public long? Imdb { get; set; }
|
||||||
public long? TMDb { get; set; }
|
public long? TMDb { get; set; }
|
||||||
|
public string Author { get; set; }
|
||||||
|
public string BookTitle { get; set; }
|
||||||
public int? Seeders { get; set; }
|
public int? Seeders { get; set; }
|
||||||
public int? Peers { get; set; }
|
public int? Peers { get; set; }
|
||||||
public Uri BannerUrl { get; set; }
|
public Uri BannerUrl { get; set; }
|
||||||
@@ -59,6 +61,8 @@ namespace Jackett.Common.Models
|
|||||||
RageID = copyFrom.RageID;
|
RageID = copyFrom.RageID;
|
||||||
Imdb = copyFrom.Imdb;
|
Imdb = copyFrom.Imdb;
|
||||||
TMDb = copyFrom.TMDb;
|
TMDb = copyFrom.TMDb;
|
||||||
|
Author = copyFrom.Author;
|
||||||
|
BookTitle = copyFrom.BookTitle;
|
||||||
Seeders = copyFrom.Seeders;
|
Seeders = copyFrom.Seeders;
|
||||||
Peers = copyFrom.Peers;
|
Peers = copyFrom.Peers;
|
||||||
BannerUrl = copyFrom.BannerUrl;
|
BannerUrl = copyFrom.BannerUrl;
|
||||||
|
@@ -82,6 +82,8 @@ namespace Jackett.Common.Models
|
|||||||
getTorznabElement("rageid", r.RageID),
|
getTorznabElement("rageid", r.RageID),
|
||||||
getTorznabElement("thetvdb", r.TVDBId),
|
getTorznabElement("thetvdb", r.TVDBId),
|
||||||
getTorznabElement("imdb", r.Imdb == null ? null : ((long)r.Imdb).ToString("D7")),
|
getTorznabElement("imdb", r.Imdb == null ? null : ((long)r.Imdb).ToString("D7")),
|
||||||
|
getTorznabElement("author", r.Author),
|
||||||
|
getTorznabElement("booktitle", r.BookTitle),
|
||||||
getTorznabElement("seeders", r.Seeders),
|
getTorznabElement("seeders", r.Seeders),
|
||||||
getTorznabElement("peers", r.Peers),
|
getTorznabElement("peers", r.Peers),
|
||||||
getTorznabElement("infohash", r.InfoHash),
|
getTorznabElement("infohash", r.InfoHash),
|
||||||
|
@@ -26,6 +26,8 @@ namespace Jackett.Common.Models
|
|||||||
|
|
||||||
public List<string> SupportedMusicSearchParamsList;
|
public List<string> SupportedMusicSearchParamsList;
|
||||||
|
|
||||||
|
public bool BookSearchAvailable { get; set; }
|
||||||
|
|
||||||
public List<TorznabCategory> Categories { get; private set; }
|
public List<TorznabCategory> Categories { get; private set; }
|
||||||
|
|
||||||
public TorznabCapabilities()
|
public TorznabCapabilities()
|
||||||
@@ -38,6 +40,7 @@ namespace Jackett.Common.Models
|
|||||||
SupportsImdbMovieSearch = false;
|
SupportsImdbMovieSearch = false;
|
||||||
SupportsImdbTVSearch = false;
|
SupportsImdbTVSearch = false;
|
||||||
SupportedMusicSearchParamsList = new List<string>();
|
SupportedMusicSearchParamsList = new List<string>();
|
||||||
|
BookSearchAvailable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TorznabCapabilities(params TorznabCategory[] cats)
|
public TorznabCapabilities(params TorznabCategory[] cats)
|
||||||
@@ -48,6 +51,7 @@ namespace Jackett.Common.Models
|
|||||||
SupportsImdbMovieSearch = false;
|
SupportsImdbMovieSearch = false;
|
||||||
SupportsImdbTVSearch = false;
|
SupportsImdbTVSearch = false;
|
||||||
SupportedMusicSearchParamsList = new List<string>();
|
SupportedMusicSearchParamsList = new List<string>();
|
||||||
|
BookSearchAvailable = false;
|
||||||
Categories = new List<TorznabCategory>();
|
Categories = new List<TorznabCategory>();
|
||||||
Categories.AddRange(cats);
|
Categories.AddRange(cats);
|
||||||
MovieSearchAvailable = Categories.Any(i => TorznabCatType.Movies.Contains(i));
|
MovieSearchAvailable = Categories.Any(i => TorznabCatType.Movies.Contains(i));
|
||||||
@@ -79,6 +83,17 @@ namespace Jackett.Common.Models
|
|||||||
|
|
||||||
private string SupportedMusicSearchParams => string.Join(",", SupportedMusicSearchParamsList);
|
private string SupportedMusicSearchParams => string.Join(",", SupportedMusicSearchParamsList);
|
||||||
|
|
||||||
|
private string SupportedBookSearchParams
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var parameters = new List<string>() { "q" };
|
||||||
|
if (BookSearchAvailable)
|
||||||
|
parameters.Add("author,title");
|
||||||
|
return string.Join(",", parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool SupportsCategories(int[] categories)
|
public bool SupportsCategories(int[] categories)
|
||||||
{
|
{
|
||||||
var subCategories = Categories.SelectMany(c => c.SubCategories);
|
var subCategories = Categories.SelectMany(c => c.SubCategories);
|
||||||
@@ -122,6 +137,10 @@ namespace Jackett.Common.Models
|
|||||||
new XElement("audio-search",
|
new XElement("audio-search",
|
||||||
new XAttribute("available", MusicSearchAvailable ? "yes" : "no"),
|
new XAttribute("available", MusicSearchAvailable ? "yes" : "no"),
|
||||||
new XAttribute("supportedParams", SupportedMusicSearchParams)
|
new XAttribute("supportedParams", SupportedMusicSearchParams)
|
||||||
|
),
|
||||||
|
new XElement("book-search",
|
||||||
|
new XAttribute("available", BookSearchAvailable ? "yes" : "no"),
|
||||||
|
new XAttribute("supportedParams", SupportedBookSearchParams)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new XElement("categories",
|
new XElement("categories",
|
||||||
@@ -149,6 +168,7 @@ namespace Jackett.Common.Models
|
|||||||
lhs.SearchAvailable = lhs.SearchAvailable || rhs.SearchAvailable;
|
lhs.SearchAvailable = lhs.SearchAvailable || rhs.SearchAvailable;
|
||||||
lhs.TVSearchAvailable = lhs.TVSearchAvailable || rhs.TVSearchAvailable;
|
lhs.TVSearchAvailable = lhs.TVSearchAvailable || rhs.TVSearchAvailable;
|
||||||
lhs.MovieSearchAvailable = lhs.MovieSearchAvailable || rhs.MovieSearchAvailable;
|
lhs.MovieSearchAvailable = lhs.MovieSearchAvailable || rhs.MovieSearchAvailable;
|
||||||
|
lhs.BookSearchAvailable = lhs.BookSearchAvailable || rhs.BookSearchAvailable;
|
||||||
lhs.SupportsTVRageSearch = lhs.SupportsTVRageSearch || rhs.SupportsTVRageSearch;
|
lhs.SupportsTVRageSearch = lhs.SupportsTVRageSearch || rhs.SupportsTVRageSearch;
|
||||||
lhs.SupportsImdbMovieSearch = lhs.SupportsImdbMovieSearch || rhs.SupportsImdbMovieSearch;
|
lhs.SupportsImdbMovieSearch = lhs.SupportsImdbMovieSearch || rhs.SupportsImdbMovieSearch;
|
||||||
lhs.SupportsImdbTVSearch = lhs.SupportsImdbTVSearch || rhs.SupportsImdbTVSearch;
|
lhs.SupportsImdbTVSearch = lhs.SupportsImdbTVSearch || rhs.SupportsImdbTVSearch;
|
||||||
|
@@ -29,6 +29,9 @@ namespace Jackett.Common.Models
|
|||||||
public int? Year { get; set; }
|
public int? Year { get; set; }
|
||||||
public ICollection<string> Genre { get; set; }
|
public ICollection<string> Genre { get; set; }
|
||||||
|
|
||||||
|
public string Author { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
public bool IsTest { get; set; }
|
public bool IsTest { get; set; }
|
||||||
|
|
||||||
public string ImdbIDShort => ImdbID?.TrimStart('t');
|
public string ImdbIDShort => ImdbID?.TrimStart('t');
|
||||||
@@ -43,6 +46,8 @@ namespace Jackett.Common.Models
|
|||||||
|
|
||||||
public bool IsMusicSearch => QueryType == "music";
|
public bool IsMusicSearch => QueryType == "music";
|
||||||
|
|
||||||
|
public bool IsBookSearch => QueryType == "book";
|
||||||
|
|
||||||
public bool IsTVRageSearch => RageID != null;
|
public bool IsTVRageSearch => RageID != null;
|
||||||
|
|
||||||
public bool IsImdbQuery => ImdbID != null;
|
public bool IsImdbQuery => ImdbID != null;
|
||||||
@@ -121,6 +126,8 @@ namespace Jackett.Common.Models
|
|||||||
Label = Label,
|
Label = Label,
|
||||||
Track = Track,
|
Track = Track,
|
||||||
Year = Year,
|
Year = Year,
|
||||||
|
Author = Author,
|
||||||
|
Title = Title,
|
||||||
RageID = RageID,
|
RageID = RageID,
|
||||||
ImdbID = ImdbID
|
ImdbID = ImdbID
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user