diff --git a/frontend/src/History/Details/HistoryDetails.js b/frontend/src/History/Details/HistoryDetails.js index de8b9192e..95ab1a715 100644 --- a/frontend/src/History/Details/HistoryDetails.js +++ b/frontend/src/History/Details/HistoryDetails.js @@ -2,255 +2,43 @@ import PropTypes from 'prop-types'; import React from 'react'; import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; -import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription'; -import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle'; -import Link from 'Components/Link/Link'; -import formatDateTime from 'Utilities/Date/formatDateTime'; -import formatAge from 'Utilities/Number/formatAge'; import translate from 'Utilities/String/translate'; import styles from './HistoryDetails.css'; function HistoryDetails(props) { const { + indexer, eventType, - sourceTitle, - data, - shortDateFormat, - timeFormat + data } = props; - if (eventType === 'grabbed') { + if (eventType === 'indexerQuery') { const { - indexer, - releaseGroup, - nzbInfoUrl, - downloadClient, - downloadId, - age, - ageHours, - ageMinutes, - publishedDate + query, + queryResults } = data; return ( { !!indexer && } { - !!releaseGroup && + !!data && - } - - { - !!nzbInfoUrl && - - - Info URL - - - - {nzbInfoUrl} - - - } - - { - !!downloadClient && - - } - - { - !!downloadId && - - } - - { - !!indexer && - - } - - { - !!publishedDate && - - } - - ); - } - - if (eventType === 'downloadFailed') { - const { - message - } = data; - - return ( - - - - { - !!message && - - } - - ); - } - - if (eventType === 'downloadFolderImported') { - const { - droppedPath, - importedPath - } = data; - - return ( - - - - { - !!droppedPath && - - } - - { - !!importedPath && - - } - - ); - } - - if (eventType === 'movieFileDeleted') { - const { - reason - } = data; - - let reasonMessage = ''; - - switch (reason) { - case 'Manual': - reasonMessage = 'File was deleted by via UI'; - break; - case 'MissingFromDisk': - reasonMessage = 'Prowlarr was unable to find the file on disk so it was removed'; - break; - case 'Upgrade': - reasonMessage = 'File was deleted to import an upgrade'; - break; - default: - reasonMessage = ''; - } - - return ( - - - - - - ); - } - - if (eventType === 'movieFileRenamed') { - const { - sourcePath, - sourceRelativePath, - path, - relativePath - } = data; - - return ( - - - - - - - - - - ); - } - - if (eventType === 'downloadIgnored') { - const { - message - } = data; - - return ( - - - - { - !!message && - } @@ -262,15 +50,15 @@ function HistoryDetails(props) { ); } HistoryDetails.propTypes = { + indexer: PropTypes.object.isRequired, eventType: PropTypes.string.isRequired, - sourceTitle: PropTypes.string.isRequired, data: PropTypes.object.isRequired, shortDateFormat: PropTypes.string.isRequired, timeFormat: PropTypes.string.isRequired diff --git a/frontend/src/History/Details/HistoryDetailsModal.js b/frontend/src/History/Details/HistoryDetailsModal.js index b5e5c0622..26d0b9957 100644 --- a/frontend/src/History/Details/HistoryDetailsModal.js +++ b/frontend/src/History/Details/HistoryDetailsModal.js @@ -14,18 +14,8 @@ import styles from './HistoryDetailsModal.css'; function getHeaderTitle(eventType) { switch (eventType) { - case 'grabbed': - return 'Grabbed'; - case 'downloadFailed': - return 'Download Failed'; - case 'downloadFolderImported': - return 'Movie Imported'; - case 'movieFileDeleted': - return 'Movie File Deleted'; - case 'movieFileRenamed': - return 'Movie File Renamed'; - case 'downloadIgnored': - return 'Download Ignored'; + case 'indexerQuery': + return 'Indexer Query'; default: return 'Unknown'; } @@ -35,7 +25,7 @@ function HistoryDetailsModal(props) { const { isOpen, eventType, - sourceTitle, + indexer, data, isMarkingAsFailed, shortDateFormat, @@ -57,7 +47,7 @@ function HistoryDetailsModal(props) { @@ -93,7 +93,40 @@ class HistoryRow extends Component { key={name} className={styles.indexer} > - {movie.name} + {indexer.name} + + ); + } + + if (name === 'successful') { + return ( + + {data.successful} + + ); + } + + if (name === 'elapsedTime') { + return ( + + {`${data.elapsedTime}ms`} + + ); + } + + if (name === 'query') { + return ( + + {data.query} ); } @@ -128,8 +161,8 @@ class HistoryRow extends Component { { + (indexer, uiSettings) => { return { - movie, + indexer, shortDateFormat: uiSettings.shortDateFormat, timeFormat: uiSettings.timeFormat }; diff --git a/frontend/src/Indexer/Edit/EditMovieModal.js b/frontend/src/Indexer/Edit/EditMovieModal.js deleted file mode 100644 index 24d9e432a..000000000 --- a/frontend/src/Indexer/Edit/EditMovieModal.js +++ /dev/null @@ -1,25 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Modal from 'Components/Modal/Modal'; -import EditMovieModalContentConnector from './EditMovieModalContentConnector'; - -function EditMovieModal({ isOpen, onModalClose, ...otherProps }) { - return ( - - - - ); -} - -EditMovieModal.propTypes = { - isOpen: PropTypes.bool.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default EditMovieModal; diff --git a/frontend/src/Indexer/Edit/EditMovieModalConnector.js b/frontend/src/Indexer/Edit/EditMovieModalConnector.js deleted file mode 100644 index affea9d0c..000000000 --- a/frontend/src/Indexer/Edit/EditMovieModalConnector.js +++ /dev/null @@ -1,39 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { clearPendingChanges } from 'Store/Actions/baseActions'; -import EditMovieModal from './EditMovieModal'; - -const mapDispatchToProps = { - clearPendingChanges -}; - -class EditMovieModalConnector extends Component { - - // - // Listeners - - onModalClose = () => { - this.props.clearPendingChanges({ section: 'movies' }); - this.props.onModalClose(); - } - - // - // Render - - render() { - return ( - - ); - } -} - -EditMovieModalConnector.propTypes = { - onModalClose: PropTypes.func.isRequired, - clearPendingChanges: PropTypes.func.isRequired -}; - -export default connect(undefined, mapDispatchToProps)(EditMovieModalConnector); diff --git a/frontend/src/Indexer/Edit/EditMovieModalContent.css b/frontend/src/Indexer/Edit/EditMovieModalContent.css deleted file mode 100644 index a2b6014df..000000000 --- a/frontend/src/Indexer/Edit/EditMovieModalContent.css +++ /dev/null @@ -1,5 +0,0 @@ -.deleteButton { - composes: button from '~Components/Link/Button.css'; - - margin-right: auto; -} diff --git a/frontend/src/Indexer/Edit/EditMovieModalContent.js b/frontend/src/Indexer/Edit/EditMovieModalContent.js deleted file mode 100644 index a2d3234ea..000000000 --- a/frontend/src/Indexer/Edit/EditMovieModalContent.js +++ /dev/null @@ -1,180 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import Form from 'Components/Form/Form'; -import FormGroup from 'Components/Form/FormGroup'; -import FormInputGroup from 'Components/Form/FormInputGroup'; -import FormLabel from 'Components/Form/FormLabel'; -import Button from 'Components/Link/Button'; -import SpinnerButton from 'Components/Link/SpinnerButton'; -import ModalBody from 'Components/Modal/ModalBody'; -import ModalContent from 'Components/Modal/ModalContent'; -import ModalFooter from 'Components/Modal/ModalFooter'; -import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes, kinds } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import styles from './EditMovieModalContent.css'; - -class EditMovieModalContent extends Component { - - // - // Lifecycle - - constructor(props, context) { - super(props, context); - - this.state = { - isConfirmMoveModalOpen: false - }; - } - - // - // Listeners - - onSavePress = () => { - const { - isPathChanging, - onSavePress - } = this.props; - - if (isPathChanging && !this.state.isConfirmMoveModalOpen) { - this.setState({ isConfirmMoveModalOpen: true }); - } else { - this.setState({ isConfirmMoveModalOpen: false }); - - onSavePress(false); - } - } - - // - // Render - - render() { - const { - title, - item, - isSaving, - originalPath, - onInputChange, - onModalClose, - onDeleteMoviePress, - ...otherProps - } = this.props; - - const { - monitored, - qualityProfileId, - minimumAvailability, - // Id, - path, - tags - } = item; - - return ( - - - {translate('Edit')} - {title} - - - -
- - {translate('Monitored')} - - - - - - {translate('MinimumAvailability')} - - - - - - {translate('QualityProfile')} - - - - - - {translate('Path')} - - - - - - {translate('Tags')} - - - -
-
- - - - - - - - {translate('Save')} - - -
- ); - } -} - -EditMovieModalContent.propTypes = { - indexerId: PropTypes.number.isRequired, - title: PropTypes.string.isRequired, - item: PropTypes.object.isRequired, - isSaving: PropTypes.bool.isRequired, - isPathChanging: PropTypes.bool.isRequired, - originalPath: PropTypes.string.isRequired, - onInputChange: PropTypes.func.isRequired, - onSavePress: PropTypes.func.isRequired, - onModalClose: PropTypes.func.isRequired, - onDeleteMoviePress: PropTypes.func.isRequired -}; - -export default EditMovieModalContent; diff --git a/frontend/src/Indexer/Edit/EditMovieModalContentConnector.js b/frontend/src/Indexer/Edit/EditMovieModalContentConnector.js deleted file mode 100644 index e4d369ef5..000000000 --- a/frontend/src/Indexer/Edit/EditMovieModalContentConnector.js +++ /dev/null @@ -1,115 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { saveMovie, setMovieValue } from 'Store/Actions/movieActions'; -import createIndexerSelector from 'Store/Selectors/createIndexerSelector'; -import selectSettings from 'Store/Selectors/selectSettings'; -import EditMovieModalContent from './EditMovieModalContent'; - -function createIsPathChangingSelector() { - return createSelector( - (state) => state.movies.pendingChanges, - createIndexerSelector(), - (pendingChanges, movie) => { - const path = pendingChanges.path; - - if (path == null) { - return false; - } - - return movie.path !== path; - } - ); -} - -function createMapStateToProps() { - return createSelector( - (state) => state.movies, - createIndexerSelector(), - createIsPathChangingSelector(), - (moviesState, movie, isPathChanging) => { - const { - isSaving, - saveError, - pendingChanges - } = moviesState; - - const movieSettings = { - monitored: movie.monitored, - qualityProfileId: movie.qualityProfileId, - minimumAvailability: movie.minimumAvailability, - path: movie.path, - tags: movie.tags - }; - - const settings = selectSettings(movieSettings, pendingChanges, saveError); - - return { - title: movie.title, - isSaving, - saveError, - isPathChanging, - originalPath: movie.path, - item: settings.settings, - ...settings - }; - } - ); -} - -const mapDispatchToProps = { - dispatchSetMovieValue: setMovieValue, - dispatchSaveMovie: saveMovie -}; - -class EditMovieModalContentConnector extends Component { - - // - // Lifecycle - - componentDidUpdate(prevProps, prevState) { - if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) { - this.props.onModalClose(); - } - } - - // - // Listeners - - onInputChange = ({ name, value }) => { - this.props.dispatchSetMovieValue({ name, value }); - } - - onSavePress = (moveFiles) => { - this.props.dispatchSaveMovie({ - id: this.props.indexerId, - moveFiles - }); - } - - // - // Render - - render() { - return ( - - ); - } -} - -EditMovieModalContentConnector.propTypes = { - indexerId: PropTypes.number, - isSaving: PropTypes.bool.isRequired, - saveError: PropTypes.object, - dispatchSetMovieValue: PropTypes.func.isRequired, - dispatchSaveMovie: PropTypes.func.isRequired, - onModalClose: PropTypes.func.isRequired -}; - -export default connect(createMapStateToProps, mapDispatchToProps)(EditMovieModalContentConnector); diff --git a/frontend/src/Indexer/Index/Menus/MovieIndexSortMenu.js b/frontend/src/Indexer/Index/Menus/MovieIndexSortMenu.js index ed65bd980..23940e497 100644 --- a/frontend/src/Indexer/Index/Menus/MovieIndexSortMenu.js +++ b/frontend/src/Indexer/Index/Menus/MovieIndexSortMenu.js @@ -47,6 +47,15 @@ function MovieIndexSortMenu(props) { {translate('Added')} + + {'Priority'} + + - ); -} - -MovieIndexProgressBar.propTypes = { - monitored: PropTypes.bool.isRequired, - hasFile: PropTypes.bool.isRequired, - isAvailable: PropTypes.bool.isRequired, - status: PropTypes.string.isRequired, - posterWidth: PropTypes.number.isRequired, - detailedProgressBar: PropTypes.bool.isRequired, - queueStatus: PropTypes.string, - queueState: PropTypes.string -}; - -export default MovieIndexProgressBar; diff --git a/frontend/src/Indexer/Index/Table/IndexerStatusCell.css b/frontend/src/Indexer/Index/Table/IndexerStatusCell.css new file mode 100644 index 000000000..fbcd5eee9 --- /dev/null +++ b/frontend/src/Indexer/Index/Table/IndexerStatusCell.css @@ -0,0 +1,9 @@ +.status { + composes: cell from '~Components/Table/Cells/TableRowCell.css'; + + width: 60px; +} + +.statusIcon { + width: 20px !important; +} diff --git a/frontend/src/Indexer/Index/Table/IndexerStatusCell.js b/frontend/src/Indexer/Index/Table/IndexerStatusCell.js new file mode 100644 index 000000000..e8b8e854e --- /dev/null +++ b/frontend/src/Indexer/Index/Table/IndexerStatusCell.js @@ -0,0 +1,44 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Icon from 'Components/Icon'; +import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell'; +import { icons } from 'Helpers/Props'; +import styles from './IndexerStatusCell.css'; + +function IndexerStatusCell(props) { + const { + className, + enabled, + component: Component, + ...otherProps + } = props; + + return ( + + { + !enabled && + + } + + ); +} + +IndexerStatusCell.propTypes = { + className: PropTypes.string.isRequired, + enabled: PropTypes.bool.isRequired, + component: PropTypes.elementType +}; + +IndexerStatusCell.defaultProps = { + className: styles.status, + component: VirtualTableRowCell +}; + +export default IndexerStatusCell; diff --git a/frontend/src/Indexer/Index/Table/MovieIndexHeader.css b/frontend/src/Indexer/Index/Table/MovieIndexHeader.css index 77082acce..a5cfffcc1 100644 --- a/frontend/src/Indexer/Index/Table/MovieIndexHeader.css +++ b/frontend/src/Indexer/Index/Table/MovieIndexHeader.css @@ -10,6 +10,7 @@ flex: 4 0 110px; } +.priority, .privacy, .protocol { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; diff --git a/frontend/src/Indexer/Index/Table/MovieIndexRow.css b/frontend/src/Indexer/Index/Table/MovieIndexRow.css index f28c01a81..3e33a1775 100644 --- a/frontend/src/Indexer/Index/Table/MovieIndexRow.css +++ b/frontend/src/Indexer/Index/Table/MovieIndexRow.css @@ -17,6 +17,7 @@ flex: 4 0 110px; } +.priority, .protocol, .privacy { composes: cell; diff --git a/frontend/src/Indexer/Index/Table/MovieIndexRow.js b/frontend/src/Indexer/Index/Table/MovieIndexRow.js index c68cb9e18..c220b3944 100644 --- a/frontend/src/Indexer/Index/Table/MovieIndexRow.js +++ b/frontend/src/Indexer/Index/Table/MovieIndexRow.js @@ -5,11 +5,14 @@ import IconButton from 'Components/Link/IconButton'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell'; import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell'; -import { icons, kinds } from 'Helpers/Props'; +import TagListConnector from 'Components/TagListConnector'; +import { icons } from 'Helpers/Props'; import DeleteIndexerModal from 'Indexer/Delete/DeleteIndexerModal'; import EditIndexerModalConnector from 'Settings/Indexers/Indexers/EditIndexerModalConnector'; +import titleCase from 'Utilities/String/titleCase'; import translate from 'Utilities/String/translate'; import CapabilitiesLabel from './CapabilitiesLabel'; +import IndexerStatusCell from './IndexerStatusCell'; import ProtocolLabel from './ProtocolLabel'; import styles from './MovieIndexRow.css'; @@ -61,8 +64,10 @@ class MovieIndexRow extends Component { enableRss, enableAutomaticSearch, enableInteractiveSearch, + tags, protocol, privacy, + priority, added, capabilities, columns, @@ -103,28 +108,13 @@ class MovieIndexRow extends Component { if (column.name === 'status') { return ( - - { - enableRss || enableAutomaticSearch || enableInteractiveSearch ? - : - null - } - { - !enableRss && !enableAutomaticSearch && !enableInteractiveSearch ? - : - null - } - + enabled={enableRss || enableAutomaticSearch || enableInteractiveSearch} + status={status} + component={VirtualTableRowCell} + /> ); } @@ -146,12 +136,23 @@ class MovieIndexRow extends Component { className={styles[column.name]} > ); } + if (column.name === 'priority') { + return ( + + {priority} + + ); + } + if (column.name === 'protocol') { return ( + + + ); + } + if (column.name === 'actions') { return ( ); diff --git a/frontend/src/Search/SearchIndexFilterModalConnector.js b/frontend/src/Search/SearchIndexFilterModalConnector.js new file mode 100644 index 000000000..2cfb3b426 --- /dev/null +++ b/frontend/src/Search/SearchIndexFilterModalConnector.js @@ -0,0 +1,24 @@ +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import FilterModal from 'Components/Filter/FilterModal'; +import { setReleasesFilter } from 'Store/Actions/releaseActions'; + +function createMapStateToProps() { + return createSelector( + (state) => state.releases.items, + (state) => state.releases.filterBuilderProps, + (sectionItems, filterBuilderProps) => { + return { + sectionItems, + filterBuilderProps, + customFilterType: 'releases' + }; + } + ); +} + +const mapDispatchToProps = { + dispatchSetFilter: setReleasesFilter +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal); diff --git a/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js b/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js index c8848a079..3b93fe91a 100644 --- a/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js +++ b/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js @@ -15,17 +15,7 @@ function NotificationEventItems(props) { } = props; const { - onGrab, - onDownload, - onUpgrade, - onRename, - onDelete, onHealthIssue, - supportsOnGrab, - supportsOnDownload, - supportsOnUpgrade, - supportsOnRename, - supportsOnDelete, supportsOnHealthIssue, includeHealthWarnings } = item; @@ -39,64 +29,6 @@ function NotificationEventItems(props) { link="https://github.com/Prowlarr/Prowlarr/wiki/Connections" />
-
- -
- -
- -
- - { - onDownload.value && -
- -
- } - -
- -
- -
- -
-
value; - - case filterTypes.GREATER_THAN_OR_EQUAL: - return rejectionCount >= value; - - case filterTypes.LESS_THAN: - return rejectionCount < value; - - case filterTypes.LESS_THAN_OR_EQUAL: - return rejectionCount <= value; - - case filterTypes.NOT_EQUAL: - return rejectionCount !== value; - - default: - return false; - } - } - }, - filterBuilderProps: [ { name: 'title', @@ -204,17 +149,6 @@ export const defaultState = { name: 'peers', label: translate('Peers'), type: filterBuilderTypes.NUMBER - }, - { - name: 'quality', - label: translate('Quality'), - type: filterBuilderTypes.EXACT, - valueType: filterBuilderValueTypes.QUALITY - }, - { - name: 'rejectionCount', - label: translate('RejectionCount'), - type: filterBuilderTypes.NUMBER } ], selectedFilterKey: 'all' @@ -235,7 +169,7 @@ export const SET_RELEASES_SORT = 'releases/setReleasesSort'; export const CLEAR_RELEASES = 'releases/clearReleases'; export const GRAB_RELEASE = 'releases/grabRelease'; export const UPDATE_RELEASE = 'releases/updateRelease'; -export const SET_RELEASES_FILTER = 'releases/setMovieReleasesFilter'; +export const SET_RELEASES_FILTER = 'releases/setReleasesFilter'; export const SET_RELEASES_TABLE_OPTION = 'releases/setReleasesTableOption'; // diff --git a/src/NzbDrone.Core/Applications/AppIndexerMapService.cs b/src/NzbDrone.Core/Applications/AppIndexerMapService.cs index f79132b52..dc361931d 100644 --- a/src/NzbDrone.Core/Applications/AppIndexerMapService.cs +++ b/src/NzbDrone.Core/Applications/AppIndexerMapService.cs @@ -1,5 +1,9 @@ using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.Applications { @@ -10,7 +14,7 @@ namespace NzbDrone.Core.Applications void DeleteAllForApp(int appId); } - public class AppIndexerMapService : IAppIndexerMapService + public class AppIndexerMapService : IAppIndexerMapService, IHandle> { private readonly IAppIndexerMapRepository _appIndexerMapRepository; @@ -33,5 +37,10 @@ namespace NzbDrone.Core.Applications { return _appIndexerMapRepository.Insert(appIndexerMap); } + + public void Handle(ProviderDeletedEvent message) + { + _appIndexerMapRepository.DeleteAllForApp(message.ProviderId); + } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/001_initial_setup.cs b/src/NzbDrone.Core/Datastore/Migration/001_initial_setup.cs index 757c4b40d..3164dad6c 100644 --- a/src/NzbDrone.Core/Datastore/Migration/001_initial_setup.cs +++ b/src/NzbDrone.Core/Datastore/Migration/001_initial_setup.cs @@ -14,7 +14,6 @@ namespace NzbDrone.Core.Datastore.Migration Create.TableForModel("History") .WithColumn("IndexerId").AsInt32() - .WithColumn("SourceTitle").AsString() .WithColumn("Date").AsDateTime() .WithColumn("Data").AsString() .WithColumn("EventType").AsInt32().Nullable() diff --git a/src/NzbDrone.Core/History/History.cs b/src/NzbDrone.Core/History/History.cs index 7126a09c4..0071fe252 100644 --- a/src/NzbDrone.Core/History/History.cs +++ b/src/NzbDrone.Core/History/History.cs @@ -12,7 +12,6 @@ namespace NzbDrone.Core.History } public int IndexerId { get; set; } - public string SourceTitle { get; set; } public DateTime Date { get; set; } public HistoryEventType EventType { get; set; } public Dictionary Data { get; set; } diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 2283457c9..e2e25a503 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -86,10 +86,14 @@ namespace NzbDrone.Core.History { Date = DateTime.UtcNow, IndexerId = message.IndexerId, - EventType = HistoryEventType.IndexerQuery, - SourceTitle = message.Query + EventType = HistoryEventType.IndexerQuery }; + history.Data.Add("ElapsedTime", message.Time.ToString()); + history.Data.Add("Query", message.Query.SceneTitles.FirstOrDefault() ?? string.Empty); + history.Data.Add("Successful", message.Successful.ToString()); + history.Data.Add("QueryResults", message.Results.HasValue ? message.Results.ToString() : null); + _historyRepository.Insert(history); } diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index d54280311..2fcbae2b7 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using NLog; @@ -53,10 +54,15 @@ namespace NzbDrone.Core.IndexerSearch { var spec = new TSpec() { - InteractiveSearch = interactiveSearch + InteractiveSearch = interactiveSearch, + SceneTitles = new List() }; - spec.SceneTitles = new List { query }; + if (query.IsNotNullOrWhiteSpace()) + { + spec.SceneTitles.Add(query); + } + spec.IndexerIds = indexerIds; return spec; @@ -86,21 +92,25 @@ namespace NzbDrone.Core.IndexerSearch taskList.Add(taskFactory.StartNew(() => { + var sw = Stopwatch.StartNew(); try { var indexerReports = searchAction(indexerLocal); - _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase.QueryTitles.Join(", "))); - lock (reports) { reports.AddRange(indexerReports); } + + _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, sw.ElapsedMilliseconds, true, indexerReports.Count())); } catch (Exception e) { + _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, sw.ElapsedMilliseconds, false)); _logger.Error(e, "Error while searching for {0}", criteriaBase); } + + sw.Stop(); }).LogExceptions()); } diff --git a/src/NzbDrone.Core/Indexers/IndexerQueryEvent.cs b/src/NzbDrone.Core/Indexers/IndexerQueryEvent.cs index dada6bb30..e83500c7c 100644 --- a/src/NzbDrone.Core/Indexers/IndexerQueryEvent.cs +++ b/src/NzbDrone.Core/Indexers/IndexerQueryEvent.cs @@ -1,16 +1,23 @@ using NzbDrone.Common.Messaging; +using NzbDrone.Core.IndexerSearch.Definitions; namespace NzbDrone.Core.Indexers { public class IndexerQueryEvent : IEvent { public int IndexerId { get; set; } - public string Query { get; set; } + public SearchCriteriaBase Query { get; set; } + public long Time { get; set; } + public bool Successful { get; set; } + public int? Results { get; set; } - public IndexerQueryEvent(int indexerId, string query) + public IndexerQueryEvent(int indexerId, SearchCriteriaBase query, long time, bool successful, int? results = null) { IndexerId = indexerId; Query = query; + Time = time; + Successful = successful; + Results = results; } } } diff --git a/src/Prowlarr.Api.V1/History/HistoryResource.cs b/src/Prowlarr.Api.V1/History/HistoryResource.cs index 46e8951c0..4075489ee 100644 --- a/src/Prowlarr.Api.V1/History/HistoryResource.cs +++ b/src/Prowlarr.Api.V1/History/HistoryResource.cs @@ -1,16 +1,13 @@ using System; using System.Collections.Generic; using NzbDrone.Core.History; -using NzbDrone.Core.Languages; using Prowlarr.Http.REST; namespace Prowlarr.Api.V1.History { public class HistoryResource : RestResource { - public int MovieId { get; set; } - public string SourceTitle { get; set; } - public bool QualityCutoffNotMet { get; set; } + public int IndexerId { get; set; } public DateTime Date { get; set; } public string DownloadId { get; set; } @@ -32,8 +29,7 @@ namespace Prowlarr.Api.V1.History { Id = model.Id, - MovieId = model.IndexerId, - SourceTitle = model.SourceTitle, + IndexerId = model.IndexerId, //QualityCutoffNotMet Date = model.Date,