Skip to content

Commit e0091a9

Browse files
Fallback to title based queries. Closes #540
1 parent 20d7393 commit e0091a9

File tree

7 files changed

+51
-10
lines changed

7 files changed

+51
-10
lines changed

changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
----------
44
### 0.2.202
5+
Added: Option to fallback to a query based search if no results were found for an ID based search. Note that this will increase API hits, potentially by a lot, because it will repeat the search e.g. for every search for a movie that's not yet released.
6+
Hydra will also only search the indexers that were searched before, so if the indexer didn't support the ID in the first place and query generation is disabled it won't be search. See [#540](https://github.com/theotherp/nzbhydra/issues/540)
7+
58
Changed: Reformat pubdates provided by indexers. Hopefully fixes [#489](https://github.com/theotherp/nzbhydra/issues/489).
69

710
Changed: Cleaned up logging of rejection reasons.

nzbhydra/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
"applyRestrictions": "both",
158158
"duplicateAgeThreshold": 2,
159159
"duplicateSizeThresholdInPercent": 1.0,
160+
"idFallbackToTitle": [],
160161
"generate_queries": [
161162
"internal"
162163
],

nzbhydra/search.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def search(search_request):
279279
search_request.category = categoryResult
280280
if search_hash not in pseudo_cache.keys() or search_request.offset == 0: # If it's a new search (which starts with offset 0) do it again instead of using the cached results
281281
logger.debug("Didn't find this query in cache or want to do a new search")
282-
cache_entry = {"results": [], "indexer_infos": {}, "total": 0, "last_access": arrow.utcnow(), "offset": 0, "rejected": SearchModule.getRejectedCountDict()}
282+
cache_entry = {"results": [], "indexer_infos": {}, "total": 0, "last_access": arrow.utcnow(), "offset": 0, "rejected": SearchModule.getRejectedCountDict(), "usedFallback": False}
283283
category = categoryResult.category
284284
indexers_to_call = pick_indexers(search_request)
285285
for p in indexers_to_call:
@@ -415,14 +415,14 @@ def search(search_request):
415415
search_results = allresults
416416

417417
with databaseLock:
418-
for indexer, infos in cache_entry["indexer_infos"].iteritems():
418+
for indexer, result_infos in cache_entry["indexer_infos"].iteritems():
419419
if indexer.name in uniqueResultsPerIndexer.keys(): # If the search failed it isn't contained in the duplicates list
420-
uniqueResultsCount = uniqueResultsPerIndexer[infos["indexer"]]
421-
processedResults = infos["processed_results"]
420+
uniqueResultsCount = uniqueResultsPerIndexer[result_infos["indexer"]]
421+
processedResults = result_infos["processed_results"]
422422
logger.debug("Indexer %s had a unique results share of %d%% (%d of %d total results were only provided by this indexer)" % (indexer.name, 100 / (numberResultsBeforeDuplicateRemoval / uniqueResultsCount), uniqueResultsCount, numberResultsBeforeDuplicateRemoval))
423-
infos["indexer_search"].uniqueResults = uniqueResultsCount
424-
infos["indexer_search"].processedResults = processedResults
425-
infos["indexer_search"].save()
423+
result_infos["indexer_search"].uniqueResults = uniqueResultsCount
424+
result_infos["indexer_search"].processedResults = processedResults
425+
result_infos["indexer_search"].save()
426426

427427
if not search_request.internal:
428428
countAfter = len(search_results)
@@ -434,6 +434,17 @@ def search(search_request):
434434
cache_entry["results"].extend(search_results)
435435
cache_entry["offset"] += limit
436436

437+
if len(indexers_to_call) == 0 and len(cache_entry["results"]) == 0 and search_request.identifier_key is not None and not cache_entry["usedFallback"] and ("internal" if search_request.internal else "external") in config.settings.searching.idFallbackToTitle:
438+
logger.debug("No results found using ID based search. Getting title from ID to fall back")
439+
title = infos.convertId(search_request.identifier_key, "title", search_request.identifier_value)
440+
if title:
441+
logger.info("Repeating search with title based query as fallback")
442+
search_request.title = title
443+
indexers_to_call = [indexer for indexer, _ in cache_entry["indexer_infos"].items()]
444+
cache_entry["usedFallback"] = True
445+
else:
446+
logger.info("Unable to find title for ID")
447+
437448
if len(indexers_to_call) == 0:
438449
logger.info("All indexers exhausted")
439450
elif len(cache_entry["results"]) >= external_offset + limit:

onlinehelp/searching.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Some indexers provide information if a release is passworded. If you select to i
55

66
Raw search engines like Binsearch don't support searches based on IDs (e.g. for a movie using an IMDB id). You can enable query generation for these. Hydra will then try to retrieve the movie's or show's title and generate a query, for example "showname s01e01".
77

8+
In some cases an ID based search will not provide any results. You can enable a fallback so that in such a case the search will be repeated with a query using the title of the show or movie.
9+
810
Some indexers don't seem to like Hydra and disable access based on the user agent. You can change it here if you want. Please leave it as it is if you have no problems. This allows indexers to gather better statistics on how their API services are used.
911

1012
### Forbidden and required words

static/js/nzbhydra.js

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

static/js/nzbhydra.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui-src/js/config-fields-service.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ function ConfigFields($injector) {
711711
templateOptions: {
712712
type: 'number',
713713
label: 'Maximum results age',
714-
help: 'Results older than this are ignored. Can be overwritten per search.',
714+
help: 'Results older than this are ignored. Can be overwritten per search',
715715
addonRight: {
716716
text: 'days'
717717
}
@@ -729,6 +729,18 @@ function ConfigFields($injector) {
729729
help: "Generate queries for indexers which do not support ID based searches"
730730
}
731731
},
732+
{
733+
key: 'idFallbackToTitle',
734+
type: 'horizontalMultiselect',
735+
templateOptions: {
736+
label: 'Fallback to title queries',
737+
options: [
738+
{label: 'Internal searches', id: 'internal'},
739+
{label: 'API searches', id: 'external'}
740+
],
741+
help: "When no results were found for a query ID search again using the title"
742+
}
743+
},
732744
{
733745
key: 'userAgent',
734746
type: 'horizontalInput',

0 commit comments

Comments
 (0)