',\n controller: NfoModalInstanceCtrl,\n size: size,\n resolve: {\n nfo: function () {\n return nfo;\n }\n }\n });\n\n modalInstance.result.then();\n }\n\n $scope.getNfoTooltip = function () {\n if ($scope.result.hasNfo === \"YES\") {\n return \"Show NFO\"\n } else if ($scope.result.hasNfo === \"MAYBE\") {\n return \"Try to load NFO (may not be available)\";\n } else {\n return \"No NFO available\";\n }\n };\n }\n\n function handleNzbDownload($scope, $window) {\n $scope.downloadNzb = downloadNzb;\n\n function downloadNzb(resultItem) {\n //href = \"{{ result.link }}\"\n $window.location.href = resultItem.link;\n }\n }\n\n\n function controller($scope, $element, $http, growl, $attrs, $uibModal, $window, DebugService, localStorageService, HydraAuthService, ConfigService) {\n $scope.foo = {};\n handleDisplay($scope, localStorageService, ConfigService);\n handleSelection($scope, $element);\n handleNfoDisplay($scope, $http, growl, $uibModal, HydraAuthService);\n handleNzbDownload($scope, $window);\n\n $scope.kify = function () {\n return function (number) {\n if (number > 1000) {\n return Math.round(number / 1000) + \"k\";\n }\n return number;\n };\n };\n\n\n $scope.showCover = function (url) {\n console.log(\"Show \" + url);\n $uibModal.open({\n template: '
{group:regex}
. Case insensitive.',\n required: true\n }\n },\n {\n key: 'to',\n type: 'horizontalInput',\n templateOptions: {\n type: 'text',\n label: 'Output pattern',\n required: true,\n help: 'If a query or title matches the input pattern it will be replaced using this. You may reference groups from the input pattern by using {group}. Additionally you may use {season:0}
or {season:00}
or {episode:0}
or {episode:00}
(with and without leading zeroes). Use <remove>
to remove the match.'\n }\n },\n {\n type: 'customMappingTest',\n }\n ],\n defaultModel: {\n searchType: null,\n affectedValue: null,\n matchAll: true,\n from: null,\n to: null\n }\n }\n },\n\n\n {\n wrapper: 'fieldset',\n templateOptions: {\n label: 'Result display'\n },\n fieldGroup: [\n {\n key: 'loadAllCachedOnInternal',\n type: 'horizontalSwitch',\n templateOptions: {\n type: 'switch',\n label: 'Display all retrieved results',\n help: 'Load all results already retrieved from indexers. Might make sorting / filtering a bit slower. Will still be paged according to the limit set above.',\n advanced: true\n }\n },\n {\n key: 'loadLimitInternal',\n type: 'horizontalInput',\n templateOptions: {\n type: 'number',\n label: 'Display...',\n addonRight: {\n text: 'results per page'\n },\n max: 500,\n required: true,\n help: 'Determines the number of results shown on one page. This might also cause more API hits because indexers are queried until the number of results is matched or all indexers are exhausted. Limit is 500.',\n advanced: true\n }\n },\n {\n key: 'coverSize',\n type: 'horizontalInput',\n templateOptions: {\n type: 'number',\n label: 'Cover width',\n addonRight: {\n text: 'px'\n },\n required: true,\n help: 'Determines width of covers in search results (when enabled in display options).'\n }\n }\n ]\n }, {\n wrapper: 'fieldset',\n templateOptions: {\n label: 'Quick filters'\n },\n fieldGroup: [\n {\n key: 'showQuickFilterButtons',\n type: 'horizontalSwitch',\n templateOptions: {\n type: 'switch',\n label: 'Show quick filters',\n help: 'Show quick filter buttons for movie and TV results.'\n }\n },\n {\n key: 'alwaysShowQuickFilterButtons',\n type: 'horizontalSwitch',\n hideExpression: '!model.showQuickFilterButtons',\n templateOptions: {\n type: 'switch',\n label: 'Always show quick filters',\n help: 'Show all quick filter buttons for all types of searches.',\n advanced: true\n }\n },\n {\n key: 'customQuickFilterButtons',\n type: 'horizontalChips',\n hideExpression: '!model.showQuickFilterButtons',\n templateOptions: {\n type: 'text',\n label: 'Custom quick filters',\n help: 'Enter in the format DisplayName=Required1,Required2
. Prefix words with ! to exclude them. Apply values with enter key.',\n tooltip: 'E.g. use WEB=webdl,web-dl.
for a quick filter with the name \"WEB\" to be displayed that searches for \"webdl\" and \"web-dl\" in lowercase search results.',\n advanced: true\n }\n },\n {\n key: 'preselectQuickFilterButtons',\n type: 'horizontalMultiselect',\n hideExpression: '!model.showQuickFilterButtons',\n templateOptions: {\n label: 'Preselect quickfilters',\n help: 'Choose which quickfilters will be selected by default.',\n options: [\n {id: 'source|camts', label: 'CAM / TS'},\n {id: 'source|tv', label: 'TV'},\n {id: 'source|web', label: 'WEB'},\n {id: 'source|dvd', label: 'DVD'},\n {id: 'source|bluray', label: 'Blu-Ray'},\n {id: 'quality|q480p', label: '480p'},\n {id: 'quality|q720p', label: '720p'},\n {id: 'quality|q1080p', label: '1080p'},\n {id: 'quality|q2160p', label: '2160p'},\n {id: 'other|q3d', label: '3D'},\n {id: 'other|qx265', label: 'x265'},\n {id: 'other|qhevc', label: 'HEVC'},\n ],\n optionsFunction: function (model) {\n var customQuickFilters = [];\n _.each(model.customQuickFilterButtons, function (entry) {\n var split1 = entry.split(\"=\");\n var displayName = split1[0];\n customQuickFilters.push({id: \"custom|\" + displayName, label: displayName})\n })\n return customQuickFilters;\n },\n tooltip: 'To select custom quickfilters you just entered please save the config first.',\n buttonText: \"None\",\n advanced: true\n }\n }\n ]\n },\n {\n wrapper: 'fieldset',\n templateOptions: {\n label: 'Duplicate detection',\n tooltip: 'Hydra tries to find duplicate results from different indexers using heuristics. You can control the parameters for that but usually the default values work quite well.',\n advanced: true\n },\n fieldGroup: [\n {\n key: 'duplicateSizeThresholdInPercent',\n type: 'horizontalPercentInput',\n templateOptions: {\n type: 'text',\n label: 'Duplicate size threshold',\n required: true,\n addonRight: {\n text: '%'\n }\n\n }\n },\n {\n key: 'duplicateAgeThreshold',\n type: 'horizontalInput',\n templateOptions: {\n type: 'number',\n label: 'Duplicate age threshold',\n required: true,\n addonRight: {\n text: 'hours'\n }\n }\n }\n\n ]\n },\n {\n wrapper: 'fieldset',\n templateOptions: {\n label: 'Other',\n advanced: true\n },\n fieldGroup: [\n {\n key: 'keepSearchResultsForDays',\n type: 'horizontalInput',\n templateOptions: {\n type: 'number',\n label: 'Store results for ...',\n addonRight: {\n text: 'days'\n },\n required: true,\n tooltip: 'Found results are stored in the database for this long until they\\'re deleted. After that any links to Hydra results still stored elsewhere become invalid. You can increase the limit if you want, the disc space needed is negligible (about 75 MB for 7 days on my server).'\n }\n },\n {\n key: 'globalCacheTimeMinutes',\n type: 'horizontalInput',\n templateOptions: {\n type: 'number',\n label: 'Results cache time',\n help: 'When set search results will be cached for this time. Any search with the same parameters will return the cached results. API cache time parameters will be preferred. See wiki.',\n addonRight: {\n text: 'minutes'\n }\n }\n }\n ]\n }\n ],\n\n categoriesConfig: [\n {\n key: 'enableCategorySizes',\n type: 'horizontalSwitch',\n templateOptions: {\n type: 'switch',\n label: 'Category sizes',\n help: \"Preset min and max sizes depending on the selected category\",\n tooltip: 'Preset range of minimum and maximum sizes for its categories. When you select a category in the search area the appropriate fields are filled with these values.'\n }\n },\n {\n key: 'defaultCategory',\n type: 'horizontalSelect',\n templateOptions: {\n label: 'Default category',\n options: [],\n help: \"Set a default category. Reload page to set a category you just added.\"\n },\n controller: function ($scope) {\n var options = [];\n options.push({name: 'All', value: 'All'});\n _.each($scope.model.categories, function (cat) {\n options.push({name: cat.name, value: cat.name});\n });\n $scope.to.options = options;\n }\n },\n {\n type: 'help',\n templateOptions: {\n type: 'help',\n lines: [\n \"The category configuration is not validated in any way. You can seriously fuck up Hydra's results and overall behavior so take care.\",\n \"Restrictions will taken from a result's category, not the search request category which may not always be the same.\"\n ],\n marginTop: '50px',\n advanced: true\n }\n },\n {\n type: 'repeatSection',\n key: 'categories',\n model: rootModel.categoriesConfig,\n templateOptions: {\n btnText: 'Add new category',\n headline: 'Categories',\n advanced: true,\n fields: [\n {\n key: 'name',\n type: 'horizontalInput',\n templateOptions: {\n type: 'text',\n label: 'Name',\n help: 'Renaming categories might cause problems with repeating searches from the history.',\n required: true\n }\n },\n {\n key: 'searchType',\n type: 'horizontalSelect',\n templateOptions: {\n label: 'Search type',\n options: [\n {name: 'General', value: 'SEARCH'},\n {name: 'Audio', value: 'MUSIC'},\n {name: 'EBook', value: 'BOOK'},\n {name: 'Movie', value: 'MOVIE'},\n {name: 'TV', value: 'TVSEARCH'}\n ],\n help: \"Determines how indexers will be searched and if autocompletion is available in the GUI\"\n }\n },\n {\n key: 'subtype',\n type: 'horizontalSelect',\n templateOptions: {\n label: 'Sub type',\n options: [\n {name: 'Anime', value: 'ANIME'},\n {name: 'Audiobook', value: 'AUDIOBOOK'},\n {name: 'Comic', value: 'COMIC'},\n {name: 'Ebook', value: 'EBOOK'},\n {name: 'None', value: 'NONE'}\n ],\n help: \"Special search type. Used for indexer specific mappings between categories and newznab IDs\"\n }\n },\n {\n key: 'applyRestrictionsType',\n type: 'horizontalSelect',\n templateOptions: {\n label: 'Apply restrictions',\n options: [\n {name: 'All searches', value: 'BOTH'},\n {name: 'Internal searches', value: 'INTERNAL'},\n {name: 'API searches', value: 'API'},\n {name: 'Never', value: 'NONE'}\n ],\n help: \"For which type of search word restrictions will be applied\"\n }\n },\n {\n key: 'requiredWords',\n type: 'horizontalChips',\n templateOptions: {\n type: 'text',\n label: 'Required words',\n help: \"Must *all* be present in a title which is converted to lowercase before. Apply words with return key.\"\n }\n },\n {\n key: 'requiredRegex',\n type: 'horizontalInput',\n templateOptions: {\n type: 'text',\n label: 'Required regex',\n help: 'Must be present in a title (case is ignored).'\n }\n },\n {\n key: 'forbiddenWords',\n type: 'horizontalChips',\n templateOptions: {\n type: 'text',\n label: 'Forbidden words',\n help: \"None may be present in a title which is converted to lowercase before. Apply words with return key.\"\n }\n },\n {\n key: 'forbiddenRegex',\n type: 'horizontalInput',\n templateOptions: {\n type: 'text',\n label: 'Forbidden regex',\n help: 'Must not be present in a title (case is ignored).'\n }\n },\n {\n wrapper: 'settingWrapper',\n templateOptions: {\n label: 'Size preset',\n help: \"Will set these values on the search page\"\n },\n fieldGroup: [\n {\n key: 'minSizePreset',\n type: 'duoSetting',\n templateOptions: {\n addonRight: {\n text: 'MB'\n }\n\n }\n },\n {\n type: 'duolabel'\n },\n {\n key: 'maxSizePreset',\n type: 'duoSetting', templateOptions: {addonRight: {text: 'MB'}}\n }\n ]\n },\n {\n key: 'applySizeLimitsToApi',\n type: 'horizontalSwitch',\n templateOptions: {\n type: 'switch',\n label: 'Limit API results size',\n help: \"Enable to apply the size preset to API results from this category\"\n }\n },\n {\n key: 'newznabCategories',\n type: 'horizontalChips',\n templateOptions: {\n type: 'text',\n label: 'Newznab categories',\n help: 'Map newznab categories to Hydra categories. Used for parsing and when searching internally. Apply categories with return key.',\n tooltip: 'Hydra tries to map API search (newnzab) categories to its internal list of categories, going from specific to general. Example: If an API search is done with a catagory that matches those of \"Movies HD\" the settings for that category are used. Otherwise it checks if it matches the \"Movies\" category and, if yes, uses that one. If that one doesn\\'t match no category settings are used.