manual search: add multiselect support for tracker/category dropdowns

This commit is contained in:
kaso17 2017-08-30 17:40:32 +02:00
parent e754d3da9f
commit 00027a41c1
7 changed files with 1783 additions and 36 deletions

View File

@ -0,0 +1 @@
span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container>li{padding:0}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;padding:3px 20px 3px 20px;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>a{padding:0}.multiselect-container>li>a>label{margin:0;height:100%;cursor:pointer;font-weight:400;padding:3px 20px 3px 40px}.multiselect-container>li>a>label.radio,.multiselect-container>li>a>label.checkbox{margin:0}.multiselect-container>li>a>label>input[type=checkbox]{margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container label.checkbox,.form-inline .multiselect-container label.radio{padding:3px 20px 3px 40px}.form-inline .multiselect-container li a label.checkbox input[type=checkbox],.form-inline .multiselect-container li a label.radio input[type=radio]{margin-left:-20px;margin-right:0}

View File

@ -724,6 +724,9 @@ function updateReleasesRow(row)
}
function showSearch(selectedIndexer, query, category) {
var selectedIndexers = []
if (selectedIndexer)
selectedIndexers = selectedIndexer.split(",");
$('#select-indexer-modal').remove();
var releaseTemplate = Handlebars.compile($("#jackett-search").html());
var releaseDialog = $(releaseTemplate({
@ -741,28 +744,30 @@ function showSearch(selectedIndexer, query, category) {
window.location.hash = '';
}) ;
var setCategories = function (tracker, items) {
var setCategories = function (trackers, items) {
var cats = {};
for (var i = 0; i < items.length; i++) {
if (items[i].configured === true && (items[i].id === tracker || tracker === '')) {
indexers["'" + items[i].id + "'"] = items[i].name;
for (var prop in items[i].caps) {
if (prop < 100000 || tracker)
cats[prop] = items[i].caps[prop];
if (trackers.length == 0 || $.inArray(items[i].id, trackers) !== -1) {
for (var j in items[i].caps) {
var cat = items[i].caps[j]
if (cat.ID < 100000 || trackers.length == 1)
cats[cat.ID] = cat.Name;
}
}
}
var select = $('#searchCategory');
select.html("<option value=''>-- All --</option>");
$.each(cats, function (index, value) {
select.append($("<option></option>")
.attr("value", value["ID"]).text(value["ID"] + ' (' + value["Name"] + ')'));
var selected = select.val();
var options = []
$.each(cats, function (ID, Name) {
options.push({ label: ID + ' (' + Name + ')', value: ID });
});
select.multiselect('dataprovider', options);
select.val(selected).multiselect("refresh");
};
$('#searchTracker').change(jQuery.proxy(function () {
var trackerId = $('#searchTracker').val();
setCategories(trackerId, this.items);
var trackerIds = $('#searchTracker').val();
setCategories(trackerIds, this.items);
}, { items: configuredIndexers }));
var queryField = document.getElementById("searchquery");
@ -783,18 +788,16 @@ function showSearch(selectedIndexer, query, category) {
var queryObj = {
Query: searchString,
Category: releaseDialog.find('#searchCategory').val(),
Tracker: releaseDialog.find('#searchTracker').val().replace("'", "").replace("'", ""),
Tracker: releaseDialog.find('#searchTracker').val()
};
window.location.hash = $.param({ search: queryObj.Query, tracker: queryObj.Tracker, category: queryObj.Category});
window.location.hash = $.param({ search: queryObj.Query, tracker: queryObj.Tracker.join(","), category: queryObj.Category.join(",") });
$('#jackett-search-perform').html($('#spinner').html());
$('#searchResults div.dataTables_filter input').val("");
clearSearchResultTable($('#searchResults'));
var trackerId = queryObj.Tracker;
if (trackerId == null || trackerId == "")
trackerId = "all";
var trackerId = "all";
api.resultsForIndexer(trackerId, queryObj, function (data) {
for (var i = 0; i < data.Results.length; i++) {
var item = data.Results[i];
@ -814,18 +817,36 @@ function showSearch(selectedIndexer, query, category) {
});
var searchTracker = releaseDialog.find("#searchTracker");
if (selectedIndexer)
searchTracker.val(selectedIndexer);
var searchCategory = releaseDialog.find('#searchCategory')
searchCategory.multiselect({
maxHeight: 400,
enableFiltering: true,
includeSelectAllOption: true,
enableCaseInsensitiveFiltering: true,
nonSelectedText: 'Any'
});
if (selectedIndexers)
searchTracker.val(selectedIndexers);
searchTracker.trigger("change");
updateSearchResultTable($('#searchResults'), []);
clearSearchResultTable($('#searchResults'));
releaseDialog.modal("show");
searchTracker.multiselect({
maxHeight: 400,
enableFiltering: true,
includeSelectAllOption: true,
enableCaseInsensitiveFiltering: true,
nonSelectedText: 'All'
});
if (category !== undefined) {
$('#searchCategory').val(category);
searchCategory.val(category.split(","));
searchCategory.multiselect("refresh");
}
releaseDialog.modal("show");
if (query !== undefined) {
queryField.value = query;
searchButton.click();

View File

@ -29,6 +29,7 @@
<script src="../libs/handlebarsextend.js"></script>
<script src="../bootstrap/bootstrap.min.js"></script>
<script src="../libs/bootstrap-notify.js"></script>
<script type="text/javascript" src="../libs/bootstrap-multiselect.js"></script>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>
<link href="../bootstrap/bootstrap.min.css" rel="stylesheet">
@ -37,6 +38,7 @@
<link rel="stylesheet" href="../custom_mobile.css" media="only screen and (max-device-width: 480px)">
<link href="../css/jquery.dataTables.min.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="../css/bootstrap-multiselect.css" type="text/css" />
<link rel="stylesheet" href="../css/font-awesome.min.css">
<title>Jackett</title>
</head>
@ -419,14 +421,13 @@
<label for="text">Query</label>
<input type="text" name="query" id="searchquery" />
<label for="tracker">Tracker</label>
<select name="tracker" id="searchTracker">
<option value="">-- All --</option>
<select name="tracker" id="searchTracker" multiple="multiple">
{{#each indexers}}
<option value="{{id}}">{{name}}</option>
<option value="{{id}}" selected>{{name}}</option>
{{/each}}
</select>
<label for="category">Category</label>
<select name="category" id="searchCategory"></select>
<select name="category" id="searchCategory" multiple="multiple"></select>
<button id="jackett-search-perform" class="btn btn-success btn-sm"><span class="fa fa-search"></span></button>
<div id="searchResults"></div>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -28,9 +28,8 @@ namespace Jackett.Controllers.V20
public override void OnAuthorization(HttpActionContext actionContext)
{
var validApiKey = Engine.Server.Config.APIKey;
var queryParams = actionContext.Request.GetQueryNameValuePairs().ToDictionary();
var queryApiKey = queryParams.ContainsKey("apikey") ? queryParams["apikey"] : null;
queryApiKey = queryParams.ContainsKey("passkey") ? queryParams["passkey"] : queryApiKey;
var queryParams = actionContext.Request.GetQueryNameValuePairs();
var queryApiKey = queryParams.Where(x => x.Key == "apikey" || x.Key == "passkey").Select(x => x.Value).FirstOrDefault();
#if DEBUG
if (Debugger.IsAttached)
@ -112,6 +111,9 @@ namespace Jackett.Controllers.V20
var torznabQuery = converted as TorznabQuery;
resultController.CurrentQuery = torznabQuery;
if (queryType == typeof(ApiSearch)) // Skip CanHandleQuery() check for manual search (CurrentIndexer isn't used during manul search)
return;
if (!resultController.CurrentIndexer.CanHandleQuery(resultController.CurrentQuery))
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"{resultController.CurrentIndexer.ID} does not support the requested query.");
}
@ -157,8 +159,8 @@ namespace Jackett.Controllers.V20
{
var manualResult = new ManualSearchResult();
var trackers = IndexerService.GetAllIndexers().Where(t => t.IsConfigured);
if (CurrentIndexer.ID != "all")
trackers = trackers.Where(t => t.ID == CurrentIndexer.ID).ToList();
if (request.Tracker != null)
trackers = trackers.Where(t => request.Tracker.Contains(t.ID));
trackers = trackers.Where(t => t.CanHandleQuery(CurrentQuery));
var tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList();

View File

@ -420,6 +420,9 @@
<None Include="CurlSharp.dll.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="Content\css\bootstrap-multiselect.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\custom_mobile.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -432,6 +435,9 @@
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Content\libs\bootstrap-multiselect.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\libs\handlebarsextend.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -567,10 +573,7 @@
</ItemGroup>
<ItemGroup />
<ItemGroup />
<ItemGroup>
<Folder Include="Indexers\Feeds\" />
<Folder Include="Models\DTO\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -6,7 +6,8 @@ namespace Jackett.Models.DTO
public class ApiSearch
{
public string Query { get; set; }
public int Category { get; set; }
public int[] Category { get; set; }
public string[] Tracker { get; set; }
public static TorznabQuery ToTorznabQuery(ApiSearch request)
{
@ -37,7 +38,9 @@ namespace Jackett.Models.DTO
}
stringQuery.SearchTerm = queryStr;
stringQuery.Categories = request.Category == 0 ? new int[0] : new int[1] { request.Category };
stringQuery.Categories = request.Category;
if (stringQuery.Categories == null)
stringQuery.Categories = new int[0];
stringQuery.ExpandCatsToSubCats();
// try to build an IMDB Query