diff --git a/src/Jackett/Content/custom.js b/src/Jackett/Content/custom.js index 597240d6c..f8fe8b66c 100644 --- a/src/Jackett/Content/custom.js +++ b/src/Jackett/Content/custom.js @@ -1,1097 +1,1100 @@ -var basePath = ''; - -var indexers = []; -var configuredIndexers = []; -var unconfiguredIndexers = []; - -$.fn.inView = function() { - if(!this.length) return false; - var rect = this.get(0).getBoundingClientRect(); - - return ( - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) - ); -}; - -$.fn.focusWithoutScrolling = function () { - if (this.inView()) - this.focus(); - return this; -}; - -$(document).ready(function () { - $.ajaxSetup({ cache: false }); - window.jackettIsLocal = window.location.hostname === '127.0.0.1'; - - bindUIButtons(); - loadJackettSettings(); - -}); - -function insertWordWrap(str) { - // insert optional word wrap after punctuation to avoid overflows on long scene titles - return str.replace(/([\.\-_\/\\])/g, "$1\u200B"); -} - -function getJackettConfig(callback) { - var jqxhr = $.get("get_jackett_config", function (data) { - - callback(data); - }).fail(function () { - doNotify("Error loading Jackett settings, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); -} - -function loadJackettSettings() { - getJackettConfig(function (data) { - $("#api-key-input").val(data.config.api_key); - $(".api-key-text").text(data.config.api_key); - $("#app-version").html(data.app_version); - $("#jackett-port").val(data.config.port); - $("#jackett-basepathoverride").val(data.config.basepathoverride); - basePath = data.config.basepathoverride; - if (basePath === null || basePath === undefined) { - basePath = ''; - } - - $("#jackett-savedir").val(data.config.blackholedir); - $("#jackett-allowext").attr('checked', data.config.external); - $("#jackett-allowupdate").attr('checked', data.config.updatedisabled); - $("#jackett-prerelease").attr('checked', data.config.prerelease); - $("#jackett-logging").attr('checked', data.config.logging); - var password = data.config.password; - $("#jackett-adminpwd").val(password); - if (password != null && password != '') { - $("#logoutBtn").show(); - } - - $.each(data.config.notices, function (index, value) { - console.log(value); - doNotify(value, "danger", "glyphicon glyphicon-alert", false); - }) - - reloadIndexers(); - }); -} - -function reloadIndexers() { - $('#indexers').hide(); - var jqxhr = $.get("get_indexers", function (data) { - indexers = data; - configuredIndexers = []; - unconfiguredIndexers = []; - for (var i = 0; i < data.items.length; i++) { - var item = data.items[i]; - item.torznab_host = resolveUrl(basePath + "/torznab/" + item.id); - item.potato_host = resolveUrl(basePath + "/potato/" + item.id); - - if (item.last_error) - item.state = "error"; - else - item.state = "success"; - - if (item.type == "public") { - item.type_icon_content = "🔓\uFE0E"; - } - else if (item.type == "private") { - item.type_icon_content = "🔐\uFE0E"; - } - else if (item.type == "semi-private") { - item.type_icon_content = "🔒\uFE0E"; - } - else { - item.type_icon_content = ""; - } - - var main_cats_list = []; - for (var catID in item.caps) { - if (catID >= 100000) - continue; // skip custom cats - var cat = item.caps[catID]; - var mainCat = cat.split("/")[0]; - main_cats_list.push(mainCat); - } - item.mains_cats = $.unique(main_cats_list).join(", "); - - if (item.configured) - configuredIndexers.push(item); - else - unconfiguredIndexers.push(item); - } - displayConfiguredIndexersList(configuredIndexers); - $('#indexers div.dataTables_filter input').focusWithoutScrolling(); - }).fail(function () { - doNotify("Error loading indexers, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); -} - -function displayConfiguredIndexersList(indexers) { - var indexersTemplate = Handlebars.compile($("#configured-indexer-table").html()); - var indexersTable = $(indexersTemplate({ indexers: indexers, total_configured_indexers: indexers.length })); - prepareTestButtons(indexersTable); - prepareSearchButtons(indexersTable); - prepareSetupButtons(indexersTable); - prepareDeleteButtons(indexersTable); - prepareCopyButtons(indexersTable); - indexersTable.find("table").dataTable( - { - "stateSave": true, - "pageLength": -1, - "lengthMenu": [[10, 20, 50, 100, 250, 500, -1], [10, 20, 50, 100, 250, 500, "All"]], - "order": [[0, "asc"]], - "columnDefs": [ - { - "targets": 0, - "visible": true, - "searchable": true, - "orderable": true - }, - { - "targets": 1, - "visible": true, - "searchable": true, - "orderable": true - } - ] - }); - - $('#indexers').empty(); - $('#indexers').append(indexersTable); - $('#indexers').fadeIn(); -} - -function displayUnconfiguredIndexersList() { - var UnconfiguredIndexersDialog = $($("#select-indexer").html()); - - var indexersTemplate = Handlebars.compile($("#unconfigured-indexer-table").html()); - var indexersTable = $(indexersTemplate({ indexers: unconfiguredIndexers, total_unconfigured_indexers: unconfiguredIndexers.length })); - indexersTable.find('.indexer-setup').each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - var link = $btn.data("link"); - $btn.click(function () { - $('#select-indexer-modal').modal('hide').on('hidden.bs.modal', function (e) { - displayIndexerSetup(id, link); - }); - }); - }); - indexersTable.find("table").DataTable( - { - "stateSave": true, - "fnStateSaveParams": function (oSettings, sValue) { - sValue.search.search = ""; // don't save the search filter content - return sValue; - }, - "bAutoWidth": false, - "pageLength": -1, - "lengthMenu": [[10, 20, 50, 100, 250, 500, -1], [10, 20, 50, 100, 250, 500, "All"]], - "order": [[0, "asc"]], - "columnDefs": [ - { - "name": "name", - "targets": 0, - "visible": true, - "searchable": true, - "orderable": true - }, - { - "name": "description", - "targets": 1, - "visible": true, - "searchable": true, - "orderable": true - }, - { - "name": "type", - "targets": 2, - "visible": true, - "searchable": true, - "orderable": true - }, - { - "name": "type_string", - "targets": 3, - "visible": false, - "searchable": true, - "orderable": true, - }, - { - "name": "language", - "targets": 4, - "visible": true, - "searchable": true, - "orderable": true - }, - { - "name": "buttons", - "targets": 5, - "visible": true, - "searchable" : false, - "orderable": false - } - ] - }); - - var undefindexers = UnconfiguredIndexersDialog.find('#unconfigured-indexers'); - undefindexers.append(indexersTable); - - UnconfiguredIndexersDialog.on('shown.bs.modal', function() { - $(this).find('div.dataTables_filter input').focusWithoutScrolling(); - }); - - UnconfiguredIndexersDialog.on('hidden.bs.modal', function (e) { - $('#indexers div.dataTables_filter input').focusWithoutScrolling(); - }); - - $("#modals").append(UnconfiguredIndexersDialog); - - UnconfiguredIndexersDialog.modal("show"); -} - -function copyToClipboard(text) { - // create hidden text element, if it doesn't already exist - var targetId = "_hiddenCopyText_"; - // must use a temporary form element for the selection and copy - target = document.getElementById(targetId); - if (!target) { - var target = document.createElement("textarea"); - target.style.position = "fixed"; - target.style.left = "-9999px"; - target.style.top = "0"; - target.id = targetId; - document.body.appendChild(target); - } - target.textContent = text; - // select the content - var currentFocus = document.activeElement; - target.focus(); - target.setSelectionRange(0, target.value.length); - - // copy the selection - var succeed; - try { - succeed = document.execCommand("copy"); - } catch (e) { - succeed = false; - } - // restore original focus - if (currentFocus && typeof currentFocus.focus === "function") { - $(currentFocus).focusWithoutScrolling(); - } - - target.textContent = ""; - - return succeed; -} - -function prepareCopyButtons(element) { - element.find(".indexer-button-copy").each(function (i, btn) { - var $btn = $(btn); - var title = $btn[0].title; - - $btn.click(function () { - copyToClipboard(title); - return false; - }); - }); -} - -function prepareDeleteButtons(element) { - element.find(".indexer-button-delete").each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - $btn.click(function () { - var jqxhr = $.post("delete_indexer", JSON.stringify({ indexer: id }), function (data) { - if (data.result == "error") { - doNotify("Delete error for " + id + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - doNotify("Deleted " + id, "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Error deleting indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); - }).always(function () { - reloadIndexers(); - }); - }); - }); -} - -function prepareSearchButtons(element) { - element.find('.indexer-button-search').each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - $btn.click(function() { - showSearch(id); - }); - }); -} - -function prepareSetupButtons(element) { - element.find('.indexer-setup').each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - var link = $btn.data("link"); - $btn.click(function () { - displayIndexerSetup(id, link); - }); - }); -} - -function updateTestState(id, state, message, parent) -{ - var btn = parent.find(".indexer-button-test[data-id=" +id + "]"); - - var sortmsg = message; - if (!sortmsg || state == "success") - sortmsg = ""; - - var td = btn.closest("td"); - td.attr("data-sort", sortmsg); - td.attr("data-filter", sortmsg); - - if (message) { - btn.tooltip("hide"); - btn.attr("title", message); - btn.data('bs.tooltip', false).tooltip({ title: message }); - - } - var icon = btn.find("span"); - icon.removeClass("glyphicon-ok test-success glyphicon-alert test-error glyphicon-refresh spinner test-inprogres"); - - if (state == "success") { - icon.addClass("glyphicon-ok test-success"); - } else if (state == "error") { - icon.addClass("glyphicon-alert test-error"); - } else if (state == "inprogres") { - icon.addClass("glyphicon-refresh test-inprogres spinner"); - } - var dt = $.fn.dataTable.tables({ visible: true, api: true}).rows().invalidate('dom'); - if (state != "inprogres") - dt.draw(); -} - -function testIndexer(id, notifyResult) { - var indexers = $('#indexers'); - updateTestState(id, "inprogres", null, indexers); - - if (notifyResult) - doNotify("Test started for " + id, "info", "glyphicon glyphicon-transfer"); - var jqxhr = $.post("test_indexer", JSON.stringify({ indexer: id }), function (data) { - if (data.result == "error") { - updateTestState(id, "error", data.error, indexers); - if (notifyResult) - doNotify("Test failed for " + id + ": \n" + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - updateTestState(id, "success", "Test successful", indexers); - if (notifyResult) - doNotify("Test successful for " + id, "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Error testing indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); - }); -} - -function prepareTestButtons(element) { - element.find(".indexer-button-test").each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - var state = $btn.data("state"); - var title = $btn.attr("title"); - $btn.tooltip(); - updateTestState(id, state, title, element); - $btn.click(function () { - testIndexer(id, true); - }); - }); -} - -function displayIndexerSetup(id, link) { - - var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: id }), function (data) { - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } - - populateSetupForm(id, data.name, data.config, data.caps, link, data.alternativesitelinks); - - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - - $("#select-indexer-modal").modal("hide"); -} - -function populateConfigItems(configForm, config) { - // Set flag so we show fields named password as a password input - for (var i = 0; i < config.length; i++) { - config[i].ispassword = config[i].id.toLowerCase() === 'password'; - } - var $formItemContainer = configForm.find(".config-setup-form"); - $formItemContainer.empty(); - - $('.jackettrecaptcha').remove(); - - var hasReacaptcha = false; - var captchaItem = null; - for (var i = 0; i < config.length; i++) { - if (config[i].type === 'recaptcha') { - hasReacaptcha = true; - captchaItem = config[i]; - } - } - - var setupItemTemplate = Handlebars.compile($("#setup-item").html()); - if (hasReacaptcha && !window.jackettIsLocal) { - var setupValueTemplate = Handlebars.compile($("#setup-item-nonlocalrecaptcha").html()); - captchaItem.value_element = setupValueTemplate(captchaItem); - var template = setupItemTemplate(captchaItem); - $formItemContainer.append(template); - } else { - - for (var i = 0; i < config.length; i++) { - var item = config[i]; - var setupValueTemplate = Handlebars.compile($("#setup-item-" + item.type).html()); - item.value_element = setupValueTemplate(item); - var template = setupItemTemplate(item); - $formItemContainer.append(template); - if (item.type === 'recaptcha') { - var jackettrecaptcha = $('.jackettrecaptcha'); - jackettrecaptcha.data("version", item.version); - switch (item.version) { - case "1": - // The v1 reCAPTCHA code uses document.write() calls to write the CAPTCHA to the location where the script was loaded. - // As it's loaded async this doesn't work. - // We use an iframe to work around this problem. - var html = ''; - var frame = document.createElement('iframe'); - frame.id = "jackettrecaptchaiframe"; - frame.style.height = "145px"; - frame.style.weight = "326px"; - frame.style.border = "none"; - frame.onload = function () { - // auto resize iframe to content - frame.style.height = frame.contentWindow.document.body.scrollHeight + 'px'; - frame.style.width = frame.contentWindow.document.body.scrollWidth + 'px'; - } - jackettrecaptcha.append(frame); - frame.contentDocument.open(); - frame.contentDocument.write(html); - frame.contentDocument.close(); - break; - case "2": - grecaptcha.render(jackettrecaptcha[0], { - 'sitekey': item.sitekey - }); - break; - } - } - } - } -} - -function newConfigModal(title, config, caps, link, alternativesitelinks) { - var configTemplate = Handlebars.compile($("#jackett-config-setup-modal").html()); - var configForm = $(configTemplate({ title: title, caps: caps, link:link })); - $("#modals").append(configForm); - populateConfigItems(configForm, config); - - if (alternativesitelinks.length >= 1) { - var AlternativeSiteLinksTemplate = Handlebars.compile($("#setup-item-alternativesitelinks").html()); - var template = $(AlternativeSiteLinksTemplate({ "alternativesitelinks": alternativesitelinks })); - configForm.find("div[data-id='sitelink']").after(template); - } - - return configForm; -} - -function getConfigModalJson(configForm) { - var configJson = []; - configForm.find(".config-setup-form").children().each(function (i, el) { - $el = $(el); - var type = $el.data("type"); - var id = $el.data("id"); - var itemEntry = { id: id }; - switch (type) { - case "hiddendata": - itemEntry.value = $el.find(".setup-item-hiddendata input").val(); - break; - case "inputstring": - itemEntry.value = $el.find(".setup-item-inputstring input").val(); - break; - case "inputbool": - itemEntry.value = $el.find(".setup-item-inputbool input").is(":checked"); - break; - case "inputselect": - itemEntry.value = $el.find(".setup-item-inputselect select").val(); - break; - case "recaptcha": - if (window.jackettIsLocal) { - var version = $el.find('.jackettrecaptcha').data("version"); - switch (version) { - case "1": - var frameDoc = $("#jackettrecaptchaiframe")[0].contentDocument; - itemEntry.version = version; - itemEntry.challenge = $("#recaptcha_challenge_field", frameDoc).val() - itemEntry.value = $("#recaptcha_response_field", frameDoc).val() - break; - case "2": - itemEntry.value = $('.g-recaptcha-response').val(); - break; - } - } else { - itemEntry.cookie = $el.find(".setup-item-recaptcha input").val(); - } - break; - } - configJson.push(itemEntry) - }); - return configJson; -} - -function populateSetupForm(indexerId, name, config, caps, link, alternativesitelinks) { - var configForm = newConfigModal(name, config, caps, link, alternativesitelinks); - var $goButton = configForm.find(".setup-indexer-go"); - $goButton.click(function () { - var data = { indexer: indexerId, name: name }; - data.config = getConfigModalJson(configForm); - - var originalBtnText = $goButton.html(); - $goButton.prop('disabled', true); - $goButton.html($('#spinner').html()); - - var jqxhr = $.post("configure_indexer", JSON.stringify(data), function (data) { - if (data.result == "error") { - if (data.config) { - populateConfigItems(configForm, data.config); - } - doNotify("Configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); - } - else { - configForm.modal("hide"); - reloadIndexers(); - doNotify("Successfully configured " + data.name, "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }).always(function () { - $goButton.html(originalBtnText); - $goButton.prop('disabled', false); - }); - }); - - configForm.on('hidden.bs.modal', function (e) { - $('#indexers div.dataTables_filter input').focusWithoutScrolling(); - }); - configForm.modal("show"); -} - -function resolveUrl(url) { - var a = document.createElement('a'); - a.href = url; - url = a.href; - return url; -} - -function doNotify(message, type, icon, autoHide) { - if (typeof autoHide === "undefined" || autoHide === null) - autoHide = true; - - var delay = 5000; - if (!autoHide) - delay = -1; - - $.notify({ - message: message, - icon: icon - }, { - element: 'body', - autoHide: autoHide, - delay: delay, - type: type, - allow_dismiss: true, - z_index: 9000, - mouse_over: 'pause', - placement: { - from: "bottom", - align: "center" - } - }); -} - -function clearNotifications() { - $('[data-notify="container"]').remove(); -} - -function updateReleasesRow(row) -{ - var labels = $(row).find("span.release-labels"); - var TitleLink = $(row).find("td.Title > a"); - var IMDBId = $(row).data("imdb"); - var Banner = $(row).data("banner"); - var Description = $(row).data("description"); - var DownloadVolumeFactor = parseFloat($(row).find("td.DownloadVolumeFactor").html()); - var UploadVolumeFactor = parseFloat($(row).find("td.UploadVolumeFactor").html()); - - var TitleTooltip = ""; - if (Banner) - TitleTooltip += "
"; - if (Description) - TitleTooltip += Description; - - if (TitleTooltip) { - TitleLink.data("toggle", "tooltip"); - TitleLink.tooltip({ - title: TitleTooltip, - html: true - }); - } - - labels.empty(); - - if (IMDBId) { - labels.append('\nIMDB'); - } - - if (!isNaN(DownloadVolumeFactor)) { - if (DownloadVolumeFactor == 0) { - labels.append('\nFREELEECH'); - } else if (DownloadVolumeFactor < 1) { - labels.append('\n' + DownloadVolumeFactor * 100 + '%DL'); - } else if (DownloadVolumeFactor > 1) { - labels.append('\n' + DownloadVolumeFactor * 100 + '%DL'); - } - } - - if (!isNaN(UploadVolumeFactor)) { - if (UploadVolumeFactor == 0) { - labels.append('\nNO UPLOAD'); - } else if (UploadVolumeFactor != 1) { - labels.append('\n' + UploadVolumeFactor * 100 + '%UL'); - } - } -} - -function showSearch(selectedIndexer) { - $('#select-indexer-modal').remove(); - var releaseTemplate = Handlebars.compile($("#jackett-search").html()); - var releaseDialog = $(releaseTemplate({ - indexers: configuredIndexers - })); - - $("#modals").append(releaseDialog); - - releaseDialog.on('shown.bs.modal', function () { - releaseDialog.find('#searchquery').focusWithoutScrolling(); - }); - - releaseDialog.on('hidden.bs.modal', function (e) { - $('#indexers div.dataTables_filter input').focusWithoutScrolling(); - }) ; - - var setCategories = function (tracker, 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]; - } - } - } - var select = $('#searchCategory'); - select.html(""); - $.each(cats, function (value, key) { - select.append($("") - .attr("value", value).text(key + ' (' + value + ')')); - }); - }; - - $('#searchTracker').change(jQuery.proxy(function () { - var trackerId = $('#searchTracker').val(); - setCategories(trackerId, this.items); - }, { items: configuredIndexers })); - - document.getElementById("searchquery") - .addEventListener("keyup", function (event) { - event.preventDefault(); - if (event.keyCode == 13) { - document.getElementById("jackett-search-perform").click(); - } - }); - - $('#jackett-search-perform').click(function () { - if ($('#jackett-search-perform span').hasClass("spinner")) { - // We are searchin already - return; - } - var queryObj = { - Query: releaseDialog.find('#searchquery').val(), - Category: releaseDialog.find('#searchCategory').val(), - Tracker: releaseDialog.find('#searchTracker').val().replace("'", "").replace("'", ""), - }; - - $('#jackett-search-perform').html($('#spinner').html()); - $('#searchResults div.dataTables_filter input').val(""); - clearSearchResultTable($('#searchResults')); - var jqxhr = $.post("search", queryObj, function (data) { - for (var i = 0; i < data.Results.length; i++) { - var item = data.Results[i]; - item.Title = insertWordWrap(item.Title); - item.CategoryDesc = insertWordWrap(item.CategoryDesc); - } - - $('#jackett-search-perform').html($('#search-button-ready').html()); - var searchResults = $('#searchResults'); - searchResults.empty(); - var datatable = updateSearchResultTable(searchResults, data).search('').columns().search('').draw(); - searchResults.find('div.dataTables_filter input').focusWithoutScrolling(); - }).fail(function () { - $('#jackett-search-perform').html($('#search-button-ready').html()); - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - var searchTracker = releaseDialog.find("#searchTracker"); - if (selectedIndexer) - searchTracker.val(selectedIndexer); - searchTracker.trigger("change"); - - updateSearchResultTable($('#searchResults'), []); - clearSearchResultTable($('#searchResults')); - releaseDialog.modal("show"); -} - -function clearSearchResultTable(element) { - element.find("#jackett-search-results-datatable > tbody").empty(); - element.find("#jackett-search-results-datatable > tfoot").empty(); - element.find("#jackett-search-results-datatable_info").empty(); - element.find("#jackett-search-results-datatable_paginate").empty(); -} - -// dataTable dead torrent filter -$.fn.dataTable.ext.search = [ - function (settings, data, dataIndex) { - if (settings.sInstance != "jackett-search-results-datatable") - return true; - var deadfiltercheckbox = $(settings.nTableWrapper).find(".dataTables_deadfilter input") - if (!deadfiltercheckbox.length) { - return true; - } - var seeders = data[9]; - if (!deadfiltercheckbox.get(0).checked && seeders == 0) - return false; - return true; - } -] - -function updateSearchResultTable(element, results) { - var resultsTemplate = Handlebars.compile($("#jackett-search-results").html()); - element.html($(resultsTemplate(results))); - element.find('tr.jackett-search-results-row').each(function () { updateReleasesRow(this); }); - var settings = { "deadfilter": true }; - var datatable = element.find('table').DataTable( - { - "fnStateSaveParams": function (oSettings, sValue) { - sValue.search.search = ""; // don't save the search filter content - sValue.deadfilter = settings.deadfilter; - return sValue; - }, - "fnStateLoadParams": function (oSettings, sValue) { - if ("deadfilter" in sValue) - settings.deadfilter = sValue.deadfilter; - }, - - "dom": "lfr<\"dataTables_deadfilter\">tip", - "stateSave": true, - "bAutoWidth": false, - "pageLength": 20, - "lengthMenu": [[10, 20, 50, 100, 250, 500, -1], [10, 20, 50, 100, 250, 500, "All"]], - "order": [[0, "desc"]], - "columnDefs": [ - { - "targets": 0, - "visible": false, - "searchable": false, - "type": 'date' - }, - { - "targets": 1, - "visible": true, - "searchable": false, - "iDataSort": 0 - }, - { - "targets": 4, - "visible": false, - "searchable": false, - "type": 'num' - }, - { - "targets": 5, - "visible": true, - "searchable": false, - "iDataSort": 4 - } - ], - fnPreDrawCallback: function () { - var table = this; - var deadfilterdiv = element.find(".dataTables_deadfilter"); - var deadfiltercheckbox = deadfilterdiv.find("input"); - if (!deadfiltercheckbox.length) { - deadfilterlabel = $('' - ); - deadfilterdiv.append(deadfilterlabel); - deadfiltercheckbox = deadfilterlabel.find("input") - deadfiltercheckbox.on("change", function () { - settings.deadfilter = this.checked; - table.api().draw(); - }); - deadfiltercheckbox.prop('checked', settings.deadfilter); - } - }, - initComplete: function () { - var count = 0; - this.api().columns().every(function () { - count++; - if (count === 3 || count === 8) { - var column = this; - var select = $('') - .appendTo($(column.footer()).empty()) - .on('change', function () { - var val = $.fn.dataTable.util.escapeRegex( - $(this).val() - ); - - column - .search(val ? '^' + val + '$' : '', true, false) - .draw(); - }); - - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - } - }); - } - }); - return datatable; -} - -function bindUIButtons() { - $('body').on('click', '.downloadlink', function (e, b) { - $(e.target).addClass('jackettdownloaded'); - }); - - $('body').on('click', '.jacketdownloadserver', function (event) { - var href = $(event.target).parent().attr('href'); - var jqxhr = $.get(href, function (data) { - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } else { - doNotify("Downloaded sent to the blackhole successfully.", "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - event.preventDefault(); - return false; - }); - - $('#jackett-add-indexer').click(function () { - $("#modals").empty(); - displayUnconfiguredIndexersList(); - }); - - $("#jackett-test-all").click(function () { - $(".indexer-button-test").each(function (i, btn) { - var $btn = $(btn); - var id = $btn.data("id"); - testIndexer(id, false); - }); - }); - - $("#jackett-show-releases").click(function () { - var jqxhr = $.get("GetCache", function (data) { - for (var i = 0; i < data.length; i++) { - var item = data[i]; - item.Title = insertWordWrap(item.Title); - item.CategoryDesc = insertWordWrap(item.CategoryDesc); - } - var releaseTemplate = Handlebars.compile($("#jackett-releases").html()); - var item = { releases: data, Title: 'Releases' }; - var releaseDialog = $(releaseTemplate(item)); - var table = releaseDialog.find('table'); - releaseDialog.find('tr.jackett-releases-row').each(function () { updateReleasesRow(this); }); - releaseDialog.on('hidden.bs.modal', function (e) { - $('#indexers div.dataTables_filter input').focusWithoutScrolling(); - }); - - table.DataTable( - { - "stateSave": true, - "bAutoWidth": false, - "pageLength": 20, - "lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "All"]], - "order": [[0, "desc"]], - "columnDefs": [ - { - "targets": 0, - "visible": false, - "searchable": false, - "type": 'date' - }, - { - "targets": 1, - "visible": false, - "searchable": false, - "type": 'date' - }, - { - "targets": 2, - "visible": true, - "searchable": false, - "iDataSort": 0 - }, - { - "targets": 3, - "visible": true, - "searchable": false, - "iDataSort": 1 - }, - { - "targets": 6, - "visible": false, - "searchable": false, - "type": 'num' - }, - { - "targets": 7, - "visible": true, - "searchable": false, - "iDataSort": 6 - } - ], - initComplete: function () { - var count = 0; - this.api().columns().every(function () { - count++; - if (count === 5 || count === 10) { - var column = this; - var select = $('') - .appendTo($(column.footer()).empty()) - .on('change', function () { - var val = $.fn.dataTable.util.escapeRegex( - $(this).val() - ); - - column - .search(val ? '^' + val + '$' : '', true, false) - .draw(); - }); - - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - } - }); - } - }); - $("#modals").append(releaseDialog); - releaseDialog.modal("show"); - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - $("#jackett-show-search").click(function () { - showSearch(null); - }); - - $("#view-jackett-logs").click(function () { - var jqxhr = $.get("GetLogs", function (data) { - var releaseTemplate = Handlebars.compile($("#jackett-logs").html()); - var item = { logs: data }; - var releaseDialog = $(releaseTemplate(item)); - $("#modals").append(releaseDialog); - releaseDialog.modal("show"); - - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - $("#change-jackett-port").click(function () { - var jackett_port = $("#jackett-port").val(); - var jackett_basepathoverride = $("#jackett-basepathoverride").val(); - var jackett_external = $("#jackett-allowext").is(':checked'); - var jackett_update = $("#jackett-allowupdate").is(':checked'); - var jackett_prerelease = $("#jackett-prerelease").is(':checked'); - var jackett_logging = $("#jackett-logging").is(':checked'); - var jsonObject = { - port: jackett_port, - external: jackett_external, - updatedisabled: jackett_update, - prerelease: jackett_prerelease, - blackholedir: $("#jackett-savedir").val(), - logging: jackett_logging, - basepathoverride: jackett_basepathoverride - }; - var jqxhr = $.post("set_config", JSON.stringify(jsonObject), function (data) { - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } else { - doNotify("Redirecting you to complete configuration update..", "success", "glyphicon glyphicon-ok"); - window.setTimeout(function () { - window.location.reload(true); - }, 3000); - - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - $("#trigger-updater").click(function () { - var jqxhr = $.get("trigger_update", function (data) { - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } else { - doNotify("Updater triggered see log for details..", "success", "glyphicon glyphicon-ok"); - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); - - $("#change-jackett-password").click(function () { - var password = $("#jackett-adminpwd").val(); - var jsonObject = { password: password }; - - var jqxhr = $.post("set_admin_password", JSON.stringify(jsonObject), function (data) { - - if (data.result == "error") { - doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); - return; - } else { - doNotify("Admin password has been set.", "success", "glyphicon glyphicon-ok"); - - window.setTimeout(function () { - window.location = window.location.pathname; - }, 1000); - - } - }).fail(function () { - doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); - }); - }); -} +var basePath = ''; + +var indexers = []; +var configuredIndexers = []; +var unconfiguredIndexers = []; + +$.fn.inView = function() { + if(!this.length) return false; + var rect = this.get(0).getBoundingClientRect(); + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); +}; + +$.fn.focusWithoutScrolling = function () { + if (this.inView()) + this.focus(); + return this; +}; + +$(document).ready(function () { + $.ajaxSetup({ cache: false }); + window.jackettIsLocal = window.location.hostname === '127.0.0.1'; + + bindUIButtons(); + loadJackettSettings(); + +}); + +function insertWordWrap(str) { + // insert optional word wrap after punctuation to avoid overflows on long scene titles + return str.replace(/([\.\-_\/\\])/g, "$1\u200B"); +} + +function getJackettConfig(callback) { + var jqxhr = $.get("get_jackett_config", function (data) { + + callback(data); + }).fail(function () { + doNotify("Error loading Jackett settings, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); +} + +function loadJackettSettings() { + getJackettConfig(function (data) { + $("#api-key-input").val(data.config.api_key); + $(".api-key-text").text(data.config.api_key); + $("#app-version").html(data.app_version); + $("#jackett-port").val(data.config.port); + $("#jackett-basepathoverride").val(data.config.basepathoverride); + basePath = data.config.basepathoverride; + if (basePath === null || basePath === undefined) { + basePath = ''; + } + + $("#jackett-savedir").val(data.config.blackholedir); + $("#jackett-allowext").attr('checked', data.config.external); + $("#jackett-allowupdate").attr('checked', data.config.updatedisabled); + $("#jackett-prerelease").attr('checked', data.config.prerelease); + $("#jackett-logging").attr('checked', data.config.logging); + $("#jackett-omdbkey").val(data.config.omdbkey); + var password = data.config.password; + $("#jackett-adminpwd").val(password); + if (password != null && password != '') { + $("#logoutBtn").show(); + } + + $.each(data.config.notices, function (index, value) { + console.log(value); + doNotify(value, "danger", "glyphicon glyphicon-alert", false); + }) + + reloadIndexers(); + }); +} + +function reloadIndexers() { + $('#indexers').hide(); + var jqxhr = $.get("get_indexers", function (data) { + indexers = data; + configuredIndexers = []; + unconfiguredIndexers = []; + for (var i = 0; i < data.items.length; i++) { + var item = data.items[i]; + item.torznab_host = resolveUrl(basePath + "/torznab/" + item.id); + item.potato_host = resolveUrl(basePath + "/potato/" + item.id); + + if (item.last_error) + item.state = "error"; + else + item.state = "success"; + + if (item.type == "public") { + item.type_icon_content = "🔓\uFE0E"; + } + else if (item.type == "private") { + item.type_icon_content = "🔐\uFE0E"; + } + else if (item.type == "semi-private") { + item.type_icon_content = "🔒\uFE0E"; + } + else { + item.type_icon_content = ""; + } + + var main_cats_list = []; + for (var catID in item.caps) { + if (catID >= 100000) + continue; // skip custom cats + var cat = item.caps[catID]; + var mainCat = cat.split("/")[0]; + main_cats_list.push(mainCat); + } + item.mains_cats = $.unique(main_cats_list).join(", "); + + if (item.configured) + configuredIndexers.push(item); + else + unconfiguredIndexers.push(item); + } + displayConfiguredIndexersList(configuredIndexers); + $('#indexers div.dataTables_filter input').focusWithoutScrolling(); + }).fail(function () { + doNotify("Error loading indexers, request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); +} + +function displayConfiguredIndexersList(indexers) { + var indexersTemplate = Handlebars.compile($("#configured-indexer-table").html()); + var indexersTable = $(indexersTemplate({ indexers: indexers, total_configured_indexers: indexers.length })); + prepareTestButtons(indexersTable); + prepareSearchButtons(indexersTable); + prepareSetupButtons(indexersTable); + prepareDeleteButtons(indexersTable); + prepareCopyButtons(indexersTable); + indexersTable.find("table").dataTable( + { + "stateSave": true, + "pageLength": -1, + "lengthMenu": [[10, 20, 50, 100, 250, 500, -1], [10, 20, 50, 100, 250, 500, "All"]], + "order": [[0, "asc"]], + "columnDefs": [ + { + "targets": 0, + "visible": true, + "searchable": true, + "orderable": true + }, + { + "targets": 1, + "visible": true, + "searchable": true, + "orderable": true + } + ] + }); + + $('#indexers').empty(); + $('#indexers').append(indexersTable); + $('#indexers').fadeIn(); +} + +function displayUnconfiguredIndexersList() { + var UnconfiguredIndexersDialog = $($("#select-indexer").html()); + + var indexersTemplate = Handlebars.compile($("#unconfigured-indexer-table").html()); + var indexersTable = $(indexersTemplate({ indexers: unconfiguredIndexers, total_unconfigured_indexers: unconfiguredIndexers.length })); + indexersTable.find('.indexer-setup').each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + var link = $btn.data("link"); + $btn.click(function () { + $('#select-indexer-modal').modal('hide').on('hidden.bs.modal', function (e) { + displayIndexerSetup(id, link); + }); + }); + }); + indexersTable.find("table").DataTable( + { + "stateSave": true, + "fnStateSaveParams": function (oSettings, sValue) { + sValue.search.search = ""; // don't save the search filter content + return sValue; + }, + "bAutoWidth": false, + "pageLength": -1, + "lengthMenu": [[10, 20, 50, 100, 250, 500, -1], [10, 20, 50, 100, 250, 500, "All"]], + "order": [[0, "asc"]], + "columnDefs": [ + { + "name": "name", + "targets": 0, + "visible": true, + "searchable": true, + "orderable": true + }, + { + "name": "description", + "targets": 1, + "visible": true, + "searchable": true, + "orderable": true + }, + { + "name": "type", + "targets": 2, + "visible": true, + "searchable": true, + "orderable": true + }, + { + "name": "type_string", + "targets": 3, + "visible": false, + "searchable": true, + "orderable": true, + }, + { + "name": "language", + "targets": 4, + "visible": true, + "searchable": true, + "orderable": true + }, + { + "name": "buttons", + "targets": 5, + "visible": true, + "searchable" : false, + "orderable": false + } + ] + }); + + var undefindexers = UnconfiguredIndexersDialog.find('#unconfigured-indexers'); + undefindexers.append(indexersTable); + + UnconfiguredIndexersDialog.on('shown.bs.modal', function() { + $(this).find('div.dataTables_filter input').focusWithoutScrolling(); + }); + + UnconfiguredIndexersDialog.on('hidden.bs.modal', function (e) { + $('#indexers div.dataTables_filter input').focusWithoutScrolling(); + }); + + $("#modals").append(UnconfiguredIndexersDialog); + + UnconfiguredIndexersDialog.modal("show"); +} + +function copyToClipboard(text) { + // create hidden text element, if it doesn't already exist + var targetId = "_hiddenCopyText_"; + // must use a temporary form element for the selection and copy + target = document.getElementById(targetId); + if (!target) { + var target = document.createElement("textarea"); + target.style.position = "fixed"; + target.style.left = "-9999px"; + target.style.top = "0"; + target.id = targetId; + document.body.appendChild(target); + } + target.textContent = text; + // select the content + var currentFocus = document.activeElement; + target.focus(); + target.setSelectionRange(0, target.value.length); + + // copy the selection + var succeed; + try { + succeed = document.execCommand("copy"); + } catch (e) { + succeed = false; + } + // restore original focus + if (currentFocus && typeof currentFocus.focus === "function") { + $(currentFocus).focusWithoutScrolling(); + } + + target.textContent = ""; + + return succeed; +} + +function prepareCopyButtons(element) { + element.find(".indexer-button-copy").each(function (i, btn) { + var $btn = $(btn); + var title = $btn[0].title; + + $btn.click(function () { + copyToClipboard(title); + return false; + }); + }); +} + +function prepareDeleteButtons(element) { + element.find(".indexer-button-delete").each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + $btn.click(function () { + var jqxhr = $.post("delete_indexer", JSON.stringify({ indexer: id }), function (data) { + if (data.result == "error") { + doNotify("Delete error for " + id + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + doNotify("Deleted " + id, "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Error deleting indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); + }).always(function () { + reloadIndexers(); + }); + }); + }); +} + +function prepareSearchButtons(element) { + element.find('.indexer-button-search').each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + $btn.click(function() { + showSearch(id); + }); + }); +} + +function prepareSetupButtons(element) { + element.find('.indexer-setup').each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + var link = $btn.data("link"); + $btn.click(function () { + displayIndexerSetup(id, link); + }); + }); +} + +function updateTestState(id, state, message, parent) +{ + var btn = parent.find(".indexer-button-test[data-id=" +id + "]"); + + var sortmsg = message; + if (!sortmsg || state == "success") + sortmsg = ""; + + var td = btn.closest("td"); + td.attr("data-sort", sortmsg); + td.attr("data-filter", sortmsg); + + if (message) { + btn.tooltip("hide"); + btn.attr("title", message); + btn.data('bs.tooltip', false).tooltip({ title: message }); + + } + var icon = btn.find("span"); + icon.removeClass("glyphicon-ok test-success glyphicon-alert test-error glyphicon-refresh spinner test-inprogres"); + + if (state == "success") { + icon.addClass("glyphicon-ok test-success"); + } else if (state == "error") { + icon.addClass("glyphicon-alert test-error"); + } else if (state == "inprogres") { + icon.addClass("glyphicon-refresh test-inprogres spinner"); + } + var dt = $.fn.dataTable.tables({ visible: true, api: true}).rows().invalidate('dom'); + if (state != "inprogres") + dt.draw(); +} + +function testIndexer(id, notifyResult) { + var indexers = $('#indexers'); + updateTestState(id, "inprogres", null, indexers); + + if (notifyResult) + doNotify("Test started for " + id, "info", "glyphicon glyphicon-transfer"); + var jqxhr = $.post("test_indexer", JSON.stringify({ indexer: id }), function (data) { + if (data.result == "error") { + updateTestState(id, "error", data.error, indexers); + if (notifyResult) + doNotify("Test failed for " + id + ": \n" + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + updateTestState(id, "success", "Test successful", indexers); + if (notifyResult) + doNotify("Test successful for " + id, "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Error testing indexer, request to Jackett server error", "danger", "glyphicon glyphicon-alert"); + }); +} + +function prepareTestButtons(element) { + element.find(".indexer-button-test").each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + var state = $btn.data("state"); + var title = $btn.attr("title"); + $btn.tooltip(); + updateTestState(id, state, title, element); + $btn.click(function () { + testIndexer(id, true); + }); + }); +} + +function displayIndexerSetup(id, link) { + + var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: id }), function (data) { + if (data.result == "error") { + doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); + return; + } + + populateSetupForm(id, data.name, data.config, data.caps, link, data.alternativesitelinks); + + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + + $("#select-indexer-modal").modal("hide"); +} + +function populateConfigItems(configForm, config) { + // Set flag so we show fields named password as a password input + for (var i = 0; i < config.length; i++) { + config[i].ispassword = config[i].id.toLowerCase() === 'password'; + } + var $formItemContainer = configForm.find(".config-setup-form"); + $formItemContainer.empty(); + + $('.jackettrecaptcha').remove(); + + var hasReacaptcha = false; + var captchaItem = null; + for (var i = 0; i < config.length; i++) { + if (config[i].type === 'recaptcha') { + hasReacaptcha = true; + captchaItem = config[i]; + } + } + + var setupItemTemplate = Handlebars.compile($("#setup-item").html()); + if (hasReacaptcha && !window.jackettIsLocal) { + var setupValueTemplate = Handlebars.compile($("#setup-item-nonlocalrecaptcha").html()); + captchaItem.value_element = setupValueTemplate(captchaItem); + var template = setupItemTemplate(captchaItem); + $formItemContainer.append(template); + } else { + + for (var i = 0; i < config.length; i++) { + var item = config[i]; + var setupValueTemplate = Handlebars.compile($("#setup-item-" + item.type).html()); + item.value_element = setupValueTemplate(item); + var template = setupItemTemplate(item); + $formItemContainer.append(template); + if (item.type === 'recaptcha') { + var jackettrecaptcha = $('.jackettrecaptcha'); + jackettrecaptcha.data("version", item.version); + switch (item.version) { + case "1": + // The v1 reCAPTCHA code uses document.write() calls to write the CAPTCHA to the location where the script was loaded. + // As it's loaded async this doesn't work. + // We use an iframe to work around this problem. + var html = ''; + var frame = document.createElement('iframe'); + frame.id = "jackettrecaptchaiframe"; + frame.style.height = "145px"; + frame.style.weight = "326px"; + frame.style.border = "none"; + frame.onload = function () { + // auto resize iframe to content + frame.style.height = frame.contentWindow.document.body.scrollHeight + 'px'; + frame.style.width = frame.contentWindow.document.body.scrollWidth + 'px'; + } + jackettrecaptcha.append(frame); + frame.contentDocument.open(); + frame.contentDocument.write(html); + frame.contentDocument.close(); + break; + case "2": + grecaptcha.render(jackettrecaptcha[0], { + 'sitekey': item.sitekey + }); + break; + } + } + } + } +} + +function newConfigModal(title, config, caps, link, alternativesitelinks) { + var configTemplate = Handlebars.compile($("#jackett-config-setup-modal").html()); + var configForm = $(configTemplate({ title: title, caps: caps, link:link })); + $("#modals").append(configForm); + populateConfigItems(configForm, config); + + if (alternativesitelinks.length >= 1) { + var AlternativeSiteLinksTemplate = Handlebars.compile($("#setup-item-alternativesitelinks").html()); + var template = $(AlternativeSiteLinksTemplate({ "alternativesitelinks": alternativesitelinks })); + configForm.find("div[data-id='sitelink']").after(template); + } + + return configForm; +} + +function getConfigModalJson(configForm) { + var configJson = []; + configForm.find(".config-setup-form").children().each(function (i, el) { + $el = $(el); + var type = $el.data("type"); + var id = $el.data("id"); + var itemEntry = { id: id }; + switch (type) { + case "hiddendata": + itemEntry.value = $el.find(".setup-item-hiddendata input").val(); + break; + case "inputstring": + itemEntry.value = $el.find(".setup-item-inputstring input").val(); + break; + case "inputbool": + itemEntry.value = $el.find(".setup-item-inputbool input").is(":checked"); + break; + case "inputselect": + itemEntry.value = $el.find(".setup-item-inputselect select").val(); + break; + case "recaptcha": + if (window.jackettIsLocal) { + var version = $el.find('.jackettrecaptcha').data("version"); + switch (version) { + case "1": + var frameDoc = $("#jackettrecaptchaiframe")[0].contentDocument; + itemEntry.version = version; + itemEntry.challenge = $("#recaptcha_challenge_field", frameDoc).val() + itemEntry.value = $("#recaptcha_response_field", frameDoc).val() + break; + case "2": + itemEntry.value = $('.g-recaptcha-response').val(); + break; + } + } else { + itemEntry.cookie = $el.find(".setup-item-recaptcha input").val(); + } + break; + } + configJson.push(itemEntry) + }); + return configJson; +} + +function populateSetupForm(indexerId, name, config, caps, link, alternativesitelinks) { + var configForm = newConfigModal(name, config, caps, link, alternativesitelinks); + var $goButton = configForm.find(".setup-indexer-go"); + $goButton.click(function () { + var data = { indexer: indexerId, name: name }; + data.config = getConfigModalJson(configForm); + + var originalBtnText = $goButton.html(); + $goButton.prop('disabled', true); + $goButton.html($('#spinner').html()); + + var jqxhr = $.post("configure_indexer", JSON.stringify(data), function (data) { + if (data.result == "error") { + if (data.config) { + populateConfigItems(configForm, data.config); + } + doNotify("Configuration failed: " + data.error, "danger", "glyphicon glyphicon-alert"); + } + else { + configForm.modal("hide"); + reloadIndexers(); + doNotify("Successfully configured " + data.name, "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }).always(function () { + $goButton.html(originalBtnText); + $goButton.prop('disabled', false); + }); + }); + + configForm.on('hidden.bs.modal', function (e) { + $('#indexers div.dataTables_filter input').focusWithoutScrolling(); + }); + configForm.modal("show"); +} + +function resolveUrl(url) { + var a = document.createElement('a'); + a.href = url; + url = a.href; + return url; +} + +function doNotify(message, type, icon, autoHide) { + if (typeof autoHide === "undefined" || autoHide === null) + autoHide = true; + + var delay = 5000; + if (!autoHide) + delay = -1; + + $.notify({ + message: message, + icon: icon + }, { + element: 'body', + autoHide: autoHide, + delay: delay, + type: type, + allow_dismiss: true, + z_index: 9000, + mouse_over: 'pause', + placement: { + from: "bottom", + align: "center" + } + }); +} + +function clearNotifications() { + $('[data-notify="container"]').remove(); +} + +function updateReleasesRow(row) +{ + var labels = $(row).find("span.release-labels"); + var TitleLink = $(row).find("td.Title > a"); + var IMDBId = $(row).data("imdb"); + var Banner = $(row).data("banner"); + var Description = $(row).data("description"); + var DownloadVolumeFactor = parseFloat($(row).find("td.DownloadVolumeFactor").html()); + var UploadVolumeFactor = parseFloat($(row).find("td.UploadVolumeFactor").html()); + + var TitleTooltip = ""; + if (Banner) + TitleTooltip += "
"; + if (Description) + TitleTooltip += Description; + + if (TitleTooltip) { + TitleLink.data("toggle", "tooltip"); + TitleLink.tooltip({ + title: TitleTooltip, + html: true + }); + } + + labels.empty(); + + if (IMDBId) { + labels.append('\nIMDB'); + } + + if (!isNaN(DownloadVolumeFactor)) { + if (DownloadVolumeFactor == 0) { + labels.append('\nFREELEECH'); + } else if (DownloadVolumeFactor < 1) { + labels.append('\n' + DownloadVolumeFactor * 100 + '%DL'); + } else if (DownloadVolumeFactor > 1) { + labels.append('\n' + DownloadVolumeFactor * 100 + '%DL'); + } + } + + if (!isNaN(UploadVolumeFactor)) { + if (UploadVolumeFactor == 0) { + labels.append('\nNO UPLOAD'); + } else if (UploadVolumeFactor != 1) { + labels.append('\n' + UploadVolumeFactor * 100 + '%UL'); + } + } +} + +function showSearch(selectedIndexer) { + $('#select-indexer-modal').remove(); + var releaseTemplate = Handlebars.compile($("#jackett-search").html()); + var releaseDialog = $(releaseTemplate({ + indexers: configuredIndexers + })); + + $("#modals").append(releaseDialog); + + releaseDialog.on('shown.bs.modal', function () { + releaseDialog.find('#searchquery').focusWithoutScrolling(); + }); + + releaseDialog.on('hidden.bs.modal', function (e) { + $('#indexers div.dataTables_filter input').focusWithoutScrolling(); + }) ; + + var setCategories = function (tracker, 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]; + } + } + } + var select = $('#searchCategory'); + select.html(""); + $.each(cats, function (value, key) { + select.append($("") + .attr("value", value).text(key + ' (' + value + ')')); + }); + }; + + $('#searchTracker').change(jQuery.proxy(function () { + var trackerId = $('#searchTracker').val(); + setCategories(trackerId, this.items); + }, { items: configuredIndexers })); + + document.getElementById("searchquery") + .addEventListener("keyup", function (event) { + event.preventDefault(); + if (event.keyCode == 13) { + document.getElementById("jackett-search-perform").click(); + } + }); + + $('#jackett-search-perform').click(function () { + if ($('#jackett-search-perform span').hasClass("spinner")) { + // We are searchin already + return; + } + var queryObj = { + Query: releaseDialog.find('#searchquery').val(), + Category: releaseDialog.find('#searchCategory').val(), + Tracker: releaseDialog.find('#searchTracker').val().replace("'", "").replace("'", ""), + }; + + $('#jackett-search-perform').html($('#spinner').html()); + $('#searchResults div.dataTables_filter input').val(""); + clearSearchResultTable($('#searchResults')); + var jqxhr = $.post("search", queryObj, function (data) { + for (var i = 0; i < data.Results.length; i++) { + var item = data.Results[i]; + item.Title = insertWordWrap(item.Title); + item.CategoryDesc = insertWordWrap(item.CategoryDesc); + } + + $('#jackett-search-perform').html($('#search-button-ready').html()); + var searchResults = $('#searchResults'); + searchResults.empty(); + var datatable = updateSearchResultTable(searchResults, data).search('').columns().search('').draw(); + searchResults.find('div.dataTables_filter input').focusWithoutScrolling(); + }).fail(function () { + $('#jackett-search-perform').html($('#search-button-ready').html()); + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + }); + + var searchTracker = releaseDialog.find("#searchTracker"); + if (selectedIndexer) + searchTracker.val(selectedIndexer); + searchTracker.trigger("change"); + + updateSearchResultTable($('#searchResults'), []); + clearSearchResultTable($('#searchResults')); + releaseDialog.modal("show"); +} + +function clearSearchResultTable(element) { + element.find("#jackett-search-results-datatable > tbody").empty(); + element.find("#jackett-search-results-datatable > tfoot").empty(); + element.find("#jackett-search-results-datatable_info").empty(); + element.find("#jackett-search-results-datatable_paginate").empty(); +} + +// dataTable dead torrent filter +$.fn.dataTable.ext.search = [ + function (settings, data, dataIndex) { + if (settings.sInstance != "jackett-search-results-datatable") + return true; + var deadfiltercheckbox = $(settings.nTableWrapper).find(".dataTables_deadfilter input") + if (!deadfiltercheckbox.length) { + return true; + } + var seeders = data[9]; + if (!deadfiltercheckbox.get(0).checked && seeders == 0) + return false; + return true; + } +] + +function updateSearchResultTable(element, results) { + var resultsTemplate = Handlebars.compile($("#jackett-search-results").html()); + element.html($(resultsTemplate(results))); + element.find('tr.jackett-search-results-row').each(function () { updateReleasesRow(this); }); + var settings = { "deadfilter": true }; + var datatable = element.find('table').DataTable( + { + "fnStateSaveParams": function (oSettings, sValue) { + sValue.search.search = ""; // don't save the search filter content + sValue.deadfilter = settings.deadfilter; + return sValue; + }, + "fnStateLoadParams": function (oSettings, sValue) { + if ("deadfilter" in sValue) + settings.deadfilter = sValue.deadfilter; + }, + + "dom": "lfr<\"dataTables_deadfilter\">tip", + "stateSave": true, + "bAutoWidth": false, + "pageLength": 20, + "lengthMenu": [[10, 20, 50, 100, 250, 500, -1], [10, 20, 50, 100, 250, 500, "All"]], + "order": [[0, "desc"]], + "columnDefs": [ + { + "targets": 0, + "visible": false, + "searchable": false, + "type": 'date' + }, + { + "targets": 1, + "visible": true, + "searchable": false, + "iDataSort": 0 + }, + { + "targets": 4, + "visible": false, + "searchable": false, + "type": 'num' + }, + { + "targets": 5, + "visible": true, + "searchable": false, + "iDataSort": 4 + } + ], + fnPreDrawCallback: function () { + var table = this; + var deadfilterdiv = element.find(".dataTables_deadfilter"); + var deadfiltercheckbox = deadfilterdiv.find("input"); + if (!deadfiltercheckbox.length) { + deadfilterlabel = $('' + ); + deadfilterdiv.append(deadfilterlabel); + deadfiltercheckbox = deadfilterlabel.find("input") + deadfiltercheckbox.on("change", function () { + settings.deadfilter = this.checked; + table.api().draw(); + }); + deadfiltercheckbox.prop('checked', settings.deadfilter); + } + }, + initComplete: function () { + var count = 0; + this.api().columns().every(function () { + count++; + if (count === 3 || count === 8) { + var column = this; + var select = $('') + .appendTo($(column.footer()).empty()) + .on('change', function () { + var val = $.fn.dataTable.util.escapeRegex( + $(this).val() + ); + + column + .search(val ? '^' + val + '$' : '', true, false) + .draw(); + }); + + column.data().unique().sort().each(function (d, j) { + select.append('') + }); + } + }); + } + }); + return datatable; +} + +function bindUIButtons() { + $('body').on('click', '.downloadlink', function (e, b) { + $(e.target).addClass('jackettdownloaded'); + }); + + $('body').on('click', '.jacketdownloadserver', function (event) { + var href = $(event.target).parent().attr('href'); + var jqxhr = $.get(href, function (data) { + if (data.result == "error") { + doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); + return; + } else { + doNotify("Downloaded sent to the blackhole successfully.", "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + event.preventDefault(); + return false; + }); + + $('#jackett-add-indexer').click(function () { + $("#modals").empty(); + displayUnconfiguredIndexersList(); + }); + + $("#jackett-test-all").click(function () { + $(".indexer-button-test").each(function (i, btn) { + var $btn = $(btn); + var id = $btn.data("id"); + testIndexer(id, false); + }); + }); + + $("#jackett-show-releases").click(function () { + var jqxhr = $.get("GetCache", function (data) { + for (var i = 0; i < data.length; i++) { + var item = data[i]; + item.Title = insertWordWrap(item.Title); + item.CategoryDesc = insertWordWrap(item.CategoryDesc); + } + var releaseTemplate = Handlebars.compile($("#jackett-releases").html()); + var item = { releases: data, Title: 'Releases' }; + var releaseDialog = $(releaseTemplate(item)); + var table = releaseDialog.find('table'); + releaseDialog.find('tr.jackett-releases-row').each(function () { updateReleasesRow(this); }); + releaseDialog.on('hidden.bs.modal', function (e) { + $('#indexers div.dataTables_filter input').focusWithoutScrolling(); + }); + + table.DataTable( + { + "stateSave": true, + "bAutoWidth": false, + "pageLength": 20, + "lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "All"]], + "order": [[0, "desc"]], + "columnDefs": [ + { + "targets": 0, + "visible": false, + "searchable": false, + "type": 'date' + }, + { + "targets": 1, + "visible": false, + "searchable": false, + "type": 'date' + }, + { + "targets": 2, + "visible": true, + "searchable": false, + "iDataSort": 0 + }, + { + "targets": 3, + "visible": true, + "searchable": false, + "iDataSort": 1 + }, + { + "targets": 6, + "visible": false, + "searchable": false, + "type": 'num' + }, + { + "targets": 7, + "visible": true, + "searchable": false, + "iDataSort": 6 + } + ], + initComplete: function () { + var count = 0; + this.api().columns().every(function () { + count++; + if (count === 5 || count === 10) { + var column = this; + var select = $('') + .appendTo($(column.footer()).empty()) + .on('change', function () { + var val = $.fn.dataTable.util.escapeRegex( + $(this).val() + ); + + column + .search(val ? '^' + val + '$' : '', true, false) + .draw(); + }); + + column.data().unique().sort().each(function (d, j) { + select.append('') + }); + } + }); + } + }); + $("#modals").append(releaseDialog); + releaseDialog.modal("show"); + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + }); + + $("#jackett-show-search").click(function () { + showSearch(null); + }); + + $("#view-jackett-logs").click(function () { + var jqxhr = $.get("GetLogs", function (data) { + var releaseTemplate = Handlebars.compile($("#jackett-logs").html()); + var item = { logs: data }; + var releaseDialog = $(releaseTemplate(item)); + $("#modals").append(releaseDialog); + releaseDialog.modal("show"); + + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + }); + + $("#change-jackett-port").click(function () { + var jackett_port = $("#jackett-port").val(); + var jackett_basepathoverride = $("#jackett-basepathoverride").val(); + var jackett_external = $("#jackett-allowext").is(':checked'); + var jackett_update = $("#jackett-allowupdate").is(':checked'); + var jackett_prerelease = $("#jackett-prerelease").is(':checked'); + var jackett_logging = $("#jackett-logging").is(':checked'); + var jackett_omdb_key = $("#jackett-omdbkey").val(); + var jsonObject = { + port: jackett_port, + external: jackett_external, + updatedisabled: jackett_update, + prerelease: jackett_prerelease, + blackholedir: $("#jackett-savedir").val(), + logging: jackett_logging, + basepathoverride: jackett_basepathoverride, + omdbkey: jackett_omdb_key + }; + var jqxhr = $.post("set_config", JSON.stringify(jsonObject), function (data) { + if (data.result == "error") { + doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); + return; + } else { + doNotify("Redirecting you to complete configuration update..", "success", "glyphicon glyphicon-ok"); + window.setTimeout(function () { + window.location.reload(true); + }, 3000); + + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + }); + + $("#trigger-updater").click(function () { + var jqxhr = $.get("trigger_update", function (data) { + if (data.result == "error") { + doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); + return; + } else { + doNotify("Updater triggered see log for details..", "success", "glyphicon glyphicon-ok"); + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + }); + + $("#change-jackett-password").click(function () { + var password = $("#jackett-adminpwd").val(); + var jsonObject = { password: password }; + + var jqxhr = $.post("set_admin_password", JSON.stringify(jsonObject), function (data) { + + if (data.result == "error") { + doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); + return; + } else { + doNotify("Admin password has been set.", "success", "glyphicon glyphicon-ok"); + + window.setTimeout(function () { + window.location = window.location.pathname; + }, 1000); + + } + }).fail(function () { + doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert"); + }); + }); +} diff --git a/src/Jackett/Content/index.html b/src/Jackett/Content/index.html index 8d95d8ee9..8c41635b4 100644 --- a/src/Jackett/Content/index.html +++ b/src/Jackett/Content/index.html @@ -140,6 +140,10 @@ Enhanced logging: +
+ OMDB API key: + +