diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bb8d7f35b..1c07673cc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,7 +2,7 @@ name: $(majorVersion).$(minorVersion).$(patchVersion) variables: majorVersion: 0 - minorVersion: 17 + minorVersion: 18 patchVersion: $[counter(variables['minorVersion'], 1)] # this will reset when we bump minor jackettVersion: $(majorVersion).$(minorVersion).$(patchVersion) buildConfiguration: Release diff --git a/src/Jackett.Common/Content/css/tagify.css b/src/Jackett.Common/Content/css/tagify.css new file mode 100644 index 000000000..31afa052e --- /dev/null +++ b/src/Jackett.Common/Content/css/tagify.css @@ -0,0 +1 @@ +:root{--tagify-dd-color-primary:rgb(53,149,246);--tagify-dd-bg-color:white}.tagify{--tags-border-color:#DDD;--tags-hover-border-color:#CCC;--tags-focus-border-color:#3595f6;--tag-bg:#E5E5E5;--tag-hover:#D3E2E2;--tag-text-color:black;--tag-text-color--edit:black;--tag-pad:0.3em 0.5em;--tag-inset-shadow-size:1.1em;--tag-invalid-color:#D39494;--tag-invalid-bg:rgba(211, 148, 148, 0.5);--tag-remove-bg:rgba(211, 148, 148, 0.3);--tag-remove-btn-color:black;--tag-remove-btn-bg:none;--tag-remove-btn-bg--hover:#c77777;--input-color:inherit;--tag--min-width:1ch;--tag--max-width:auto;--tag-hide-transition:0.3s;--placeholder-color:rgba(0, 0, 0, 0.4);--placeholder-color-focus:rgba(0, 0, 0, 0.25);--loader-size:.8em;display:flex;align-items:flex-start;flex-wrap:wrap;border:1px solid #ddd;border:1px solid var(--tags-border-color);padding:0;line-height:normal;cursor:text;outline:0;position:relative;box-sizing:border-box;transition:.1s}@keyframes tags--bump{30%{transform:scale(1.2)}}@keyframes rotateLoader{to{transform:rotate(1turn)}}.tagify:hover{border-color:#ccc;border-color:var(--tags-hover-border-color)}.tagify.tagify--focus{transition:0s;border-color:#3595f6;border-color:var(--tags-focus-border-color)}.tagify[readonly]:not(.tagify--mix){cursor:default}.tagify[readonly]:not(.tagify--mix)>.tagify__input{visibility:hidden;width:0;margin:5px 0}.tagify[readonly]:not(.tagify--mix) .tagify__tag>div{padding:.3em .5em;padding:var(--tag-pad)}.tagify[readonly]:not(.tagify--mix) .tagify__tag>div::before{background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px;box-shadow:none;filter:brightness(.95)}.tagify[readonly] .tagify__tag__removeBtn{display:none}.tagify--loading .tagify__input>br:last-child{display:none}.tagify--loading .tagify__input::before{content:none}.tagify--loading .tagify__input::after{content:'';vertical-align:middle;opacity:1;width:.7em;height:.7em;width:var(--loader-size);height:var(--loader-size);border:3px solid;border-color:#eee #bbb #888 transparent;border-radius:50%;animation:rotateLoader .4s infinite linear;content:''!important;margin:-2px 0 -2px .5em}.tagify--loading .tagify__input:empty::after{margin-left:0}.tagify+input,.tagify+textarea{position:absolute!important;left:-9999em!important;transform:scale(0)!important}.tagify__tag{display:inline-flex;align-items:center;margin:5px 0 5px 5px;position:relative;z-index:1;outline:0;cursor:default;transition:.13s ease-out}.tagify__tag>div{vertical-align:top;box-sizing:border-box;max-width:100%;padding:.3em .5em;padding:var(--tag-pad,.3em .5em);color:#000;color:var(--tag-text-color,#000);line-height:inherit;border-radius:3px;white-space:nowrap;transition:.13s ease-out}.tagify__tag>div>*{white-space:pre-wrap;overflow:hidden;text-overflow:ellipsis;display:inline-block;vertical-align:top;min-width:1ch;max-width:auto;min-width:var(--tag--min-width,1ch);max-width:var(--tag--max-width,auto);transition:.8s ease,.1s color}.tagify__tag>div>[contenteditable]{outline:0;-webkit-user-select:text;user-select:text;cursor:text;margin:-2px;padding:2px;max-width:350px}.tagify__tag>div::before{content:'';position:absolute;border-radius:inherit;left:0;top:0;right:0;bottom:0;z-index:-1;pointer-events:none;transition:120ms ease;animation:tags--bump .3s ease-out 1;box-shadow:0 0 0 1.1em #e5e5e5 inset;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-bg,#e5e5e5) inset}.tagify__tag:focus div::before,.tagify__tag:hover:not([readonly]) div::before{top:-2px;right:-2px;bottom:-2px;left:-2px;box-shadow:0 0 0 1.1em #d3e2e2 inset;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-hover,#d3e2e2) inset}.tagify__tag--loading{pointer-events:none}.tagify__tag--loading .tagify__tag__removeBtn{display:none}.tagify__tag--loading::after{--loader-size:.4em;content:'';vertical-align:middle;opacity:1;width:.7em;height:.7em;width:var(--loader-size);height:var(--loader-size);border:3px solid;border-color:#eee #bbb #888 transparent;border-radius:50%;animation:rotateLoader .4s infinite linear;margin:0 .5em 0 -.1em}.tagify__tag--flash div::before{animation:none}.tagify__tag--hide{width:0!important;padding-left:0;padding-right:0;margin-left:0;margin-right:0;opacity:0;transform:scale(0);transition:.3s;transition:var(--tag-hide-transition,.3s);pointer-events:none}.tagify__tag--hide>div>*{white-space:nowrap}.tagify__tag.tagify--noAnim>div::before{animation:none}.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div>span{opacity:.5}.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div::before{box-shadow:0 0 0 1.1em rgba(211,148,148,.5) inset!important;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-invalid-bg,rgba(211,148,148,.5)) inset!important;transition:.2s}.tagify__tag[readonly] .tagify__tag__removeBtn{display:none}.tagify__tag[readonly]>div::before{background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px;box-shadow:none;filter:brightness(.95)}.tagify__tag--editable>div{color:#000;color:var(--tag-text-color--edit,#000)}.tagify__tag--editable>div::before{box-shadow:0 0 0 2px #d3e2e2 inset!important;box-shadow:0 0 0 2px var(--tag-hover,#d3e2e2) inset!important}.tagify__tag--editable>.tagify__tag__removeBtn{pointer-events:none}.tagify__tag--editable>.tagify__tag__removeBtn::after{opacity:0;transform:translateX(100%) translateX(5px)}.tagify__tag--editable.tagify--invalid>div::before{box-shadow:0 0 0 2px #d39494 inset!important;box-shadow:0 0 0 2px var(--tag-invalid-color,#d39494) inset!important}.tagify__tag__removeBtn{order:5;display:inline-flex;align-items:center;justify-content:center;border-radius:50px;cursor:pointer;font:14px/1 Arial;background:0 0;background:var(--tag-remove-btn-bg,none);color:#000;color:var(--tag-remove-btn-color,#000);width:14px;height:14px;margin-right:4.66667px;margin-left:auto;overflow:hidden;transition:.2s ease-out}.tagify__tag__removeBtn::after{content:"\00D7";transition:.3s,color 0s}.tagify__tag__removeBtn:hover{color:#fff;background:#c77777;background:var(--tag-remove-btn-bg--hover,#c77777)}.tagify__tag__removeBtn:hover+div>span{opacity:.5}.tagify__tag__removeBtn:hover+div::before{box-shadow:0 0 0 1.1em rgba(211,148,148,.3) inset!important;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-remove-bg,rgba(211,148,148,.3)) inset!important;transition:box-shadow .2s}.tagify:not(.tagify--mix) .tagify__input br{display:none}.tagify:not(.tagify--mix) .tagify__input *{display:inline;white-space:nowrap}.tagify__input{flex-grow:1;display:inline-block;min-width:110px;margin:5px;padding:.3em .5em;padding:var(--tag-pad,.3em .5em);line-height:inherit;position:relative;white-space:pre-wrap;color:inherit;color:var(--input-color,inherit);box-sizing:inherit}.tagify__input:empty::before{transition:.2s ease-out;opacity:1;transform:none;display:inline-block;width:auto}.tagify--mix .tagify__input:empty::before{display:inline-block}.tagify__input:focus{outline:0}.tagify__input:focus::before{transition:.2s ease-out;opacity:0;transform:translatex(6px)}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.tagify__input:focus::before{display:none}}@supports (-ms-ime-align:auto){.tagify__input:focus::before{display:none}}.tagify__input:focus:empty::before{transition:.2s ease-out;opacity:1;transform:none;color:rgba(0,0,0,.25);color:var(--placeholder-color-focus)}@-moz-document url-prefix(){.tagify__input:focus:empty::after{display:none}}.tagify__input::before{content:attr(data-placeholder);height:1em;line-height:1em;margin:auto 0;z-index:1;color:rgba(0,0,0,.4);color:var(--placeholder-color);white-space:nowrap;pointer-events:none;opacity:0;position:absolute}.tagify--mix .tagify__input::before{display:none;position:static;line-height:inherit}.tagify__input::after{content:attr(data-suggest);display:inline-block;white-space:pre;color:#000;opacity:.3;pointer-events:none;max-width:100px}.tagify__input .tagify__tag{margin:0 1px}.tagify__input .tagify__tag>div{padding-top:0;padding-bottom:0}.tagify--mix{display:block}.tagify--mix .tagify__input{padding:5px;margin:0;width:100%;height:100%;line-height:1.5;display:block}.tagify--mix .tagify__input::before{height:auto}.tagify--mix .tagify__input::after{content:none}.tagify--select::after{content:'>';opacity:.5;position:absolute;top:50%;right:0;bottom:0;font:16px monospace;line-height:8px;height:8px;pointer-events:none;transform:translate(-150%,-50%) scaleX(1.2) rotate(90deg);transition:.2s ease-in-out}.tagify--select[aria-expanded=true]::after{transform:translate(-150%,-50%) rotate(270deg) scaleY(1.2)}.tagify--select .tagify__tag{position:absolute;top:0;right:1.8em;bottom:0}.tagify--select .tagify__tag div{display:none}.tagify--select .tagify__input{width:100%}.tagify--invalid{--tags-border-color:#D39494}.tagify__dropdown{position:absolute;z-index:9999;transform:translateY(1px);overflow:hidden}.tagify__dropdown[placement=top]{margin-top:0;transform:translateY(-100%)}.tagify__dropdown[placement=top] .tagify__dropdown__wrapper{border-top-width:1px;border-bottom-width:0}.tagify__dropdown[position=text]{box-shadow:0 0 0 3px rgba(var(--tagify-dd-color-primary),.1);font-size:.9em}.tagify__dropdown[position=text] .tagify__dropdown__wrapper{border-width:1px}.tagify__dropdown__wrapper{max-height:300px;overflow:hidden;background:#fff;background:var(--tagify-dd-bg-color);border:1px solid #3595f6;border-color:var(--tagify-dd-color-primary);border-width:1.1px;border-top-width:0;box-shadow:0 2px 4px -2px rgba(0,0,0,.2);transition:.25s cubic-bezier(0,1,.5,1)}.tagify__dropdown__wrapper:hover{overflow:auto}.tagify__dropdown--initial .tagify__dropdown__wrapper{max-height:20px;transform:translateY(-1em)}.tagify__dropdown--initial[placement=top] .tagify__dropdown__wrapper{transform:translateY(2em)}.tagify__dropdown__item{box-sizing:inherit;padding:.3em .5em;margin:1px;cursor:pointer;border-radius:2px;position:relative;outline:0}.tagify__dropdown__item--active{background:#3595f6;background:var(--tagify-dd-color-primary);color:#fff}.tagify__dropdown__item:active{filter:brightness(105%)} \ No newline at end of file diff --git a/src/Jackett.Common/Content/custom.css b/src/Jackett.Common/Content/custom.css index 246be5a50..750d9eee5 100644 --- a/src/Jackett.Common/Content/custom.css +++ b/src/Jackett.Common/Content/custom.css @@ -76,6 +76,10 @@ body { max-width: 255px; } +.setup-item-inputtags { + max-width: 255px; +} + [data-type=hiddendata]{ display: none; } @@ -328,3 +332,21 @@ input#searchquery { #proxy-warning { color: red; } + +.label-tag { + text-transform: lowercase; + background-color: #777; +} + +.tagify { + height: auto; +} + +.tagify .tagify__input { + min-width: 0; + text-transform: lowercase; +} + +.tagify .tagify__tag-text { + text-transform: lowercase; +} diff --git a/src/Jackett.Common/Content/custom.js b/src/Jackett.Common/Content/custom.js index c48f2be67..9ecceacc0 100644 --- a/src/Jackett.Common/Content/custom.js +++ b/src/Jackett.Common/Content/custom.js @@ -3,6 +3,8 @@ var basePath = ''; var indexers = []; var configuredIndexers = []; var unconfiguredIndexers = []; +var configuredTags = []; +var availableFilters = []; $.fn.inView = function () { if (!this.length) return false; @@ -58,7 +60,7 @@ function openSearchIfNecessary() { decodeURIComponent(item.split('=')[1].replace(/\+/g, '%20'))) }, prev), {}); if ("search" in hashArgs) { - showSearch(hashArgs.tracker, hashArgs.search, hashArgs.category); + showSearch(hashArgs.filter, hashArgs.tracker, hashArgs.search, hashArgs.category); } } @@ -67,6 +69,14 @@ function insertWordWrap(str) { return str.replace(/([\.\-_\/\\])/g, "$1\u200B"); } +function type_filter(indexer) { + return indexer.type == this.value; +} + +function tag_filter(indexer) { + return indexer.tags.map(t => t.toLowerCase()).indexOf(this.value.toLowerCase()) > -1; +} + function getJackettConfig(callback) { api.getServerConfig(callback).fail(function () { doNotify("Error loading Jackett settings, request to Jackett server failed, is server running ?", "danger", "glyphicon glyphicon-alert"); @@ -131,11 +141,14 @@ function loadJackettSettings() { } function reloadIndexers() { + $('#filters').hide(); $('#indexers').hide(); api.getAllIndexers(function (data) { indexers = data; configuredIndexers = []; unconfiguredIndexers = []; + configuredTags = []; + availableFilters = []; for (var i = 0; i < data.length; i++) { var item = data[i]; item.rss_host = resolveUrl(basePath + "/api/v2.0/indexers/" + item.id + "/results/torznab/api?apikey=" + api.key + "&t=search&cat=&q="); @@ -169,7 +182,13 @@ function reloadIndexers() { else unconfiguredIndexers.push(item); } + + configuredTags = configuredIndexers.map(i => i.tags).reduce((a, g) => a.concat(g), []).filter((v, i, a) => a.indexOf(v) === i); + + configureFilters(configuredIndexers); + displayConfiguredIndexersList(configuredIndexers); + $('#indexers div.dataTables_filter input').focusWithoutScrolling(); openSearchIfNecessary(); }).fail(function () { @@ -177,6 +196,23 @@ function reloadIndexers() { }); } +function configureFilters(indexers) { + function add(f) { + if (availableFilters.find(x => x.id == f.id)) + return; + if (!indexers.every(f.apply, f) && indexers.some(f.apply, f)) + availableFilters.push(f); + } + + ["public", "private", "semi-private"] + .map(t => { return { id: "type:" + t, apply: type_filter, value: t } }) + .forEach(add); + + configuredTags.sort() + .map(t => { return { id: "tag:" + t.toLowerCase(), apply: tag_filter, value: t }}) + .forEach(add); +} + function displayConfiguredIndexersList(indexers) { var indexersTemplate = Handlebars.compile($("#configured-indexer-table").html()); var indexersTable = $(indexersTemplate({ @@ -484,17 +520,20 @@ function prepareSearchButtons(element) { var id = $btn.data("id"); $btn.click(function () { window.location.hash = "search&tracker=" + id; - showSearch(id); + showSearch(null, id); }); }); } function prepareSetupButtons(element) { element.find('.indexer-setup').each(function (i, btn) { - var indexer = configuredIndexers[i]; - $(btn).click(function () { - displayIndexerSetup(indexer.id, indexer.name, indexer.caps, indexer.link, indexer.alternativesitelinks, indexer.description); - }); + var $btn = $(btn); + var id = $btn.data("id"); + var indexer = configuredIndexers.find(i => i.id === id); + if (indexer) + $btn.click(function () { + displayIndexerSetup(indexer.id, indexer.name, indexer.caps, indexer.link, indexer.alternativesitelinks, indexer.description); + }); }); } @@ -610,11 +649,32 @@ function populateConfigItems(configForm, config) { var item = config[i]; var setupValueTemplate = Handlebars.compile($("#setup-item-" + item.type).html()); item.value_element = setupValueTemplate(item); - var template = setupItemTemplate(item); + var template = $(setupItemTemplate(item)); $formItemContainer.append(template); + setupConfigItem(template, item); } } +function setupConfigItem(configItem, item) { + switch (item.type) { + case "inputtags": { + configItem.find("input").tagify({ + dropdown: { + enabled: 0, + position: "text" + }, + separator: item.separator || ",", + whitelist: item.whitelist || [], + blacklist: item.blacklist || [], + pattern: item.pattern || null, + delimiters: item.delimiters || item.separator || ",", + originalInputValueFormat: function (values) { return values.map(item => item.value.toLowerCase()).join(this.separator); } + }); + } + break; + } +} + function newConfigModal(title, config, caps, link, alternativesitelinks, description) { var configTemplate = Handlebars.compile($("#jackett-config-setup-modal").html()); var configForm = $(configTemplate({ @@ -638,6 +698,8 @@ function newConfigModal(title, config, caps, link, alternativesitelinks, descrip }); } + $("div[data-id='tags'] input", configForm).data("tagify").settings.whitelist = configuredTags; + return configForm; } @@ -668,9 +730,13 @@ function getConfigModalJson(configForm) { $el.find(".setup-item-inputcheckbox input:checked").each(function () { itemEntry.values.push($(this).val()); }); + break; case "inputselect": itemEntry.value = $el.find(".setup-item-inputselect select").val(); break; + case "inputtags": + itemEntry.value = $el.find(".setup-item-inputtags input").val(); + break; } configJson.push(itemEntry) }); @@ -802,14 +868,15 @@ function updateReleasesRow(row) { } } -function showSearch(selectedIndexer, query, category) { +function showSearch(selectedFilter, selectedIndexer, query, category) { var selectedIndexers = []; if (selectedIndexer) - selectedIndexers = selectedIndexer.split(","); + selectedIndexers = selectedIndexer.split(","); $('#select-indexer-modal').remove(); var releaseTemplate = Handlebars.compile($("#jackett-search").html()); var releaseDialog = $(releaseTemplate({ - indexers: configuredIndexers + filters: availableFilters, + active: selectedFilter })); $("#modals").append(releaseDialog); @@ -823,6 +890,29 @@ function showSearch(selectedIndexer, query, category) { window.location.hash = ''; }); + var setTrackers = function (filterId, trackers) { + var select = $('#searchTracker'); + var selected = select.val(); + var filter = availableFilters.find(f => f.id == filterId); + if (filter) + trackers = trackers.filter(filter.apply,filter); + var options = trackers.map(t => { + return { + label: t.name, + value: t.id + } + }); + select.multiselect('dataprovider', options); + select.val(selected).multiselect("refresh"); + }; + + $('#searchFilter').change(jQuery.proxy(function () { + var filterId = $('#searchFilter').val(); + setTrackers(filterId, this.items); + }, { + items: configuredIndexers + })); + var setCategories = function (trackers, items) { var cats = {}; for (var i = 0; i < items.length; i++) { @@ -869,6 +959,7 @@ function showSearch(selectedIndexer, query, category) { return; } var searchString = releaseDialog.find('#searchquery').val(); + var filterId = releaseDialog.find('#searchFilter').val(); var queryObj = { Query: searchString, Category: releaseDialog.find('#searchCategory').val(), @@ -878,14 +969,15 @@ function showSearch(selectedIndexer, query, category) { window.location.hash = Object.entries({ search: encodeURIComponent(queryObj.Query).replace(/%20/g, '+'), tracker: queryObj.Tracker.join(","), - category: queryObj.Category.join(",") - }).map(([k, v], i) => k + '=' + v).join('&'); + category: queryObj.Category.join(","), + filter: filterId ? encodeURIComponent(filterId) : "" + }).filter(([k, v]) => v).map(([k, v], i) => k + '=' + v).join('&'); $('#jackett-search-perform').html($('#spinner').html()); $('#searchResults div.dataTables_filter input').val(""); clearSearchResultTable($('#searchResults')); - var trackerId = "all"; + var trackerId = filterId || "all"; api.resultsForIndexer(trackerId, queryObj, function (data) { for (var i = 0; i < data.Results.length; i++) { var item = data.Results[i]; @@ -906,16 +998,14 @@ function showSearch(selectedIndexer, query, category) { var searchTracker = releaseDialog.find("#searchTracker"); var searchCategory = releaseDialog.find('#searchCategory'); - searchCategory.multiselect({ + var searchFilter = releaseDialog.find('#searchFilter'); + + searchFilter.multiselect({ maxHeight: 400, enableFiltering: true, - includeSelectAllOption: true, enableCaseInsensitiveFiltering: true, - nonSelectedText: 'Any' + nonSelectedText: 'All' }); - if (selectedIndexers) - searchTracker.val(selectedIndexers); - searchTracker.trigger("change"); updateSearchResultTable($('#searchResults'), []); clearSearchResultTable($('#searchResults')); @@ -928,6 +1018,29 @@ function showSearch(selectedIndexer, query, category) { nonSelectedText: 'All' }); + searchCategory.multiselect({ + maxHeight: 400, + enableFiltering: true, + includeSelectAllOption: true, + enableCaseInsensitiveFiltering: true, + nonSelectedText: 'Any' + }); + + if (availableFilters.length > 0) { + if (selectedFilter) { + searchFilter.val(selectedFilter); + searchFilter.multiselect("refresh"); + } + searchFilter.trigger("change"); + } + else + setTrackers(selectedFilter, configuredIndexers); + + if (selectedIndexers) { + searchTracker.val(selectedIndexers); + searchTracker.multiselect("refresh"); + } + searchTracker.trigger("change"); if (category !== undefined) { searchCategory.val(category.split(",")); @@ -1231,7 +1344,7 @@ function bindUIButtons() { }); $("#jackett-show-search").click(function () { - showSearch(null); + showSearch(); window.location.hash = "search"; }); @@ -1348,4 +1461,4 @@ function proxyWarning(input) { } else { $('#proxy-warning').hide(); } -} \ No newline at end of file +} diff --git a/src/Jackett.Common/Content/custom_mobile.css b/src/Jackett.Common/Content/custom_mobile.css index 578880907..64a6f04e1 100644 --- a/src/Jackett.Common/Content/custom_mobile.css +++ b/src/Jackett.Common/Content/custom_mobile.css @@ -330,3 +330,21 @@ input#searchquery { #proxy-warning { color: red; } + +.label-tag { + text-transform: lowercase; + background-color: #777; +} + +.tagify { + height: auto; +} + +.tagify .tagify__input { + min-width: 0; + text-transform: lowercase; +} + +.tagify .tagify__tag-text { + text-transform: lowercase; +} diff --git a/src/Jackett.Common/Content/index.html b/src/Jackett.Common/Content/index.html index e830ce0ba..3d8b69780 100644 --- a/src/Jackett.Common/Content/index.html +++ b/src/Jackett.Common/Content/index.html @@ -22,11 +22,14 @@ + + - - + + + @@ -65,7 +68,7 @@