mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Automatic History cleanup setting
This commit is contained in:
@@ -7,7 +7,7 @@ import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
|
|||||||
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
|
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
|
||||||
import { fetchIndexers } from 'Store/Actions/indexerActions';
|
import { fetchIndexers } from 'Store/Actions/indexerActions';
|
||||||
import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions';
|
import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions';
|
||||||
import { fetchIndexerCategories, fetchIndexerFlags, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions';
|
import { fetchGeneralSettings, fetchIndexerCategories, fetchIndexerFlags, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions';
|
||||||
import { fetchStatus } from 'Store/Actions/systemActions';
|
import { fetchStatus } from 'Store/Actions/systemActions';
|
||||||
import { fetchTags } from 'Store/Actions/tagActions';
|
import { fetchTags } from 'Store/Actions/tagActions';
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
@@ -47,6 +47,7 @@ const selectIsPopulated = createSelector(
|
|||||||
(state) => state.customFilters.isPopulated,
|
(state) => state.customFilters.isPopulated,
|
||||||
(state) => state.tags.isPopulated,
|
(state) => state.tags.isPopulated,
|
||||||
(state) => state.settings.ui.isPopulated,
|
(state) => state.settings.ui.isPopulated,
|
||||||
|
(state) => state.settings.general.isPopulated,
|
||||||
(state) => state.settings.languages.isPopulated,
|
(state) => state.settings.languages.isPopulated,
|
||||||
(state) => state.indexers.isPopulated,
|
(state) => state.indexers.isPopulated,
|
||||||
(state) => state.indexerStatus.isPopulated,
|
(state) => state.indexerStatus.isPopulated,
|
||||||
@@ -57,6 +58,7 @@ const selectIsPopulated = createSelector(
|
|||||||
customFiltersIsPopulated,
|
customFiltersIsPopulated,
|
||||||
tagsIsPopulated,
|
tagsIsPopulated,
|
||||||
uiSettingsIsPopulated,
|
uiSettingsIsPopulated,
|
||||||
|
generalSettingsIsPopulated,
|
||||||
languagesIsPopulated,
|
languagesIsPopulated,
|
||||||
indexersIsPopulated,
|
indexersIsPopulated,
|
||||||
indexerStatusIsPopulated,
|
indexerStatusIsPopulated,
|
||||||
@@ -68,6 +70,7 @@ const selectIsPopulated = createSelector(
|
|||||||
customFiltersIsPopulated &&
|
customFiltersIsPopulated &&
|
||||||
tagsIsPopulated &&
|
tagsIsPopulated &&
|
||||||
uiSettingsIsPopulated &&
|
uiSettingsIsPopulated &&
|
||||||
|
generalSettingsIsPopulated &&
|
||||||
languagesIsPopulated &&
|
languagesIsPopulated &&
|
||||||
indexersIsPopulated &&
|
indexersIsPopulated &&
|
||||||
indexerStatusIsPopulated &&
|
indexerStatusIsPopulated &&
|
||||||
@@ -82,6 +85,7 @@ const selectErrors = createSelector(
|
|||||||
(state) => state.customFilters.error,
|
(state) => state.customFilters.error,
|
||||||
(state) => state.tags.error,
|
(state) => state.tags.error,
|
||||||
(state) => state.settings.ui.error,
|
(state) => state.settings.ui.error,
|
||||||
|
(state) => state.settings.general.error,
|
||||||
(state) => state.settings.languages.error,
|
(state) => state.settings.languages.error,
|
||||||
(state) => state.indexers.error,
|
(state) => state.indexers.error,
|
||||||
(state) => state.indexerStatus.error,
|
(state) => state.indexerStatus.error,
|
||||||
@@ -92,6 +96,7 @@ const selectErrors = createSelector(
|
|||||||
customFiltersError,
|
customFiltersError,
|
||||||
tagsError,
|
tagsError,
|
||||||
uiSettingsError,
|
uiSettingsError,
|
||||||
|
generalSettingsError,
|
||||||
languagesError,
|
languagesError,
|
||||||
indexersError,
|
indexersError,
|
||||||
indexerStatusError,
|
indexerStatusError,
|
||||||
@@ -103,6 +108,7 @@ const selectErrors = createSelector(
|
|||||||
customFiltersError ||
|
customFiltersError ||
|
||||||
tagsError ||
|
tagsError ||
|
||||||
uiSettingsError ||
|
uiSettingsError ||
|
||||||
|
generalSettingsError ||
|
||||||
languagesError ||
|
languagesError ||
|
||||||
indexersError ||
|
indexersError ||
|
||||||
indexerStatusError ||
|
indexerStatusError ||
|
||||||
@@ -116,6 +122,7 @@ const selectErrors = createSelector(
|
|||||||
customFiltersError,
|
customFiltersError,
|
||||||
tagsError,
|
tagsError,
|
||||||
uiSettingsError,
|
uiSettingsError,
|
||||||
|
generalSettingsError,
|
||||||
languagesError,
|
languagesError,
|
||||||
indexersError,
|
indexersError,
|
||||||
indexerStatusError,
|
indexerStatusError,
|
||||||
@@ -177,6 +184,9 @@ function createMapDispatchToProps(dispatch, props) {
|
|||||||
dispatchFetchUISettings() {
|
dispatchFetchUISettings() {
|
||||||
dispatch(fetchUISettings());
|
dispatch(fetchUISettings());
|
||||||
},
|
},
|
||||||
|
dispatchFetchGeneralSettings() {
|
||||||
|
dispatch(fetchGeneralSettings());
|
||||||
|
},
|
||||||
dispatchFetchStatus() {
|
dispatchFetchStatus() {
|
||||||
dispatch(fetchStatus());
|
dispatch(fetchStatus());
|
||||||
},
|
},
|
||||||
@@ -212,6 +222,7 @@ class PageConnector extends Component {
|
|||||||
this.props.dispatchFetchIndexerCategories();
|
this.props.dispatchFetchIndexerCategories();
|
||||||
this.props.dispatchFetchIndexerFlags();
|
this.props.dispatchFetchIndexerFlags();
|
||||||
this.props.dispatchFetchUISettings();
|
this.props.dispatchFetchUISettings();
|
||||||
|
this.props.dispatchFetchGeneralSettings();
|
||||||
this.props.dispatchFetchStatus();
|
this.props.dispatchFetchStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,6 +248,7 @@ class PageConnector extends Component {
|
|||||||
dispatchFetchIndexerCategories,
|
dispatchFetchIndexerCategories,
|
||||||
dispatchFetchIndexerFlags,
|
dispatchFetchIndexerFlags,
|
||||||
dispatchFetchUISettings,
|
dispatchFetchUISettings,
|
||||||
|
dispatchFetchGeneralSettings,
|
||||||
dispatchFetchStatus,
|
dispatchFetchStatus,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@@ -277,6 +289,7 @@ PageConnector.propTypes = {
|
|||||||
dispatchFetchIndexerCategories: PropTypes.func.isRequired,
|
dispatchFetchIndexerCategories: PropTypes.func.isRequired,
|
||||||
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
|
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
|
||||||
dispatchFetchUISettings: PropTypes.func.isRequired,
|
dispatchFetchUISettings: PropTypes.func.isRequired,
|
||||||
|
dispatchFetchGeneralSettings: PropTypes.func.isRequired,
|
||||||
dispatchFetchStatus: PropTypes.func.isRequired,
|
dispatchFetchStatus: PropTypes.func.isRequired,
|
||||||
onSidebarVisibleChange: PropTypes.func.isRequired
|
onSidebarVisibleChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
@@ -13,6 +13,7 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
|
|||||||
import TablePager from 'Components/Table/TablePager';
|
import TablePager from 'Components/Table/TablePager';
|
||||||
import { align, icons } from 'Helpers/Props';
|
import { align, icons } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
import HistoryOptionsConnector from './HistoryOptionsConnector';
|
||||||
import HistoryRowConnector from './HistoryRowConnector';
|
import HistoryRowConnector from './HistoryRowConnector';
|
||||||
|
|
||||||
class History extends Component {
|
class History extends Component {
|
||||||
@@ -58,6 +59,7 @@ class History extends Component {
|
|||||||
<TableOptionsModalWrapper
|
<TableOptionsModalWrapper
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
optionsComponent={HistoryOptionsConnector}
|
||||||
>
|
>
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label={translate('Options')}
|
label={translate('Options')}
|
||||||
|
80
frontend/src/History/HistoryOptions.js
Normal file
80
frontend/src/History/HistoryOptions.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
|
import { inputTypes } from 'Helpers/Props';
|
||||||
|
|
||||||
|
class HistoryOptions extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
historyCleanupDays: props.historyCleanupDays
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const {
|
||||||
|
historyCleanupDays
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (historyCleanupDays !== prevProps.historyCleanupDays) {
|
||||||
|
this.setState({
|
||||||
|
historyCleanupDays
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onGlobalInputChange = ({ name, value }) => {
|
||||||
|
const {
|
||||||
|
dispatchSaveGeneralSettings
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const setting = { [name]: value };
|
||||||
|
|
||||||
|
this.setState(setting, () => {
|
||||||
|
dispatchSaveGeneralSettings(setting);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
historyCleanupDays
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>History Cleanup</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.NUMBER}
|
||||||
|
name="historyCleanupDays"
|
||||||
|
value={historyCleanupDays}
|
||||||
|
helpText="Set to 0 to disable automatic cleanup"
|
||||||
|
helpTextWarning="History items older than the selected number of days will be cleaned up automatically"
|
||||||
|
onChange={this.onGlobalInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryOptions.propTypes = {
|
||||||
|
historyCleanupDays: PropTypes.bool.isRequired,
|
||||||
|
dispatchSaveGeneralSettings: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HistoryOptions;
|
21
frontend/src/History/HistoryOptionsConnector.js
Normal file
21
frontend/src/History/HistoryOptionsConnector.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import { saveGeneralSettings } from 'Store/Actions/settingsActions';
|
||||||
|
import HistoryOptions from './HistoryOptions';
|
||||||
|
|
||||||
|
function createMapStateToProps() {
|
||||||
|
return createSelector(
|
||||||
|
(state) => state.settings.general.item,
|
||||||
|
(generalSettings) => {
|
||||||
|
return {
|
||||||
|
...generalSettings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
dispatchSaveGeneralSettings: saveGeneralSettings
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(createMapStateToProps, mapDispatchToProps)(HistoryOptions);
|
@@ -7,7 +7,7 @@
|
|||||||
.indexer {
|
.indexer {
|
||||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||||
|
|
||||||
width: 80px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.releaseGroup {
|
.releaseGroup {
|
||||||
|
@@ -77,28 +77,16 @@ namespace NzbDrone.Core.Configuration
|
|||||||
return _repository.Get(key.ToLower()) != null;
|
return _repository.Get(key.ToLower()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AutoUnmonitorPreviouslyDownloadedMovies
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("AutoUnmonitorPreviouslyDownloadedMovies"); }
|
|
||||||
set { SetValue("AutoUnmonitorPreviouslyDownloadedMovies", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Retention
|
public int Retention
|
||||||
{
|
{
|
||||||
get { return GetValueInt("Retention", 0); }
|
get { return GetValueInt("Retention", 0); }
|
||||||
set { SetValue("Retention", value); }
|
set { SetValue("Retention", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string RecycleBin
|
public int HistoryCleanupDays
|
||||||
{
|
{
|
||||||
get { return GetValue("RecycleBin", string.Empty); }
|
get { return GetValueInt("HistoryCleanupDays", 365); }
|
||||||
set { SetValue("RecycleBin", value); }
|
set { SetValue("HistoryCleanupDays", value); }
|
||||||
}
|
|
||||||
|
|
||||||
public int RecycleBinCleanupDays
|
|
||||||
{
|
|
||||||
get { return GetValueInt("RecycleBinCleanupDays", 7); }
|
|
||||||
set { SetValue("RecycleBinCleanupDays", value); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int RssSyncInterval
|
public int RssSyncInterval
|
||||||
@@ -202,20 +190,6 @@ namespace NzbDrone.Core.Configuration
|
|||||||
set { SetValue("RemoveFailedDownloads", value); }
|
set { SetValue("RemoveFailedDownloads", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CreateEmptyMovieFolders
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("CreateEmptyMovieFolders", false); }
|
|
||||||
|
|
||||||
set { SetValue("CreateEmptyMovieFolders", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DeleteEmptyFolders
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("DeleteEmptyFolders", false); }
|
|
||||||
|
|
||||||
set { SetValue("DeleteEmptyFolders", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DownloadClientWorkingFolders
|
public string DownloadClientWorkingFolders
|
||||||
{
|
{
|
||||||
get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); }
|
get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); }
|
||||||
@@ -236,76 +210,6 @@ namespace NzbDrone.Core.Configuration
|
|||||||
set { SetValue("DownloadClientHistoryLimit", value); }
|
set { SetValue("DownloadClientHistoryLimit", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SkipFreeSpaceCheckWhenImporting
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("SkipFreeSpaceCheckWhenImporting", false); }
|
|
||||||
|
|
||||||
set { SetValue("SkipFreeSpaceCheckWhenImporting", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int MinimumFreeSpaceWhenImporting
|
|
||||||
{
|
|
||||||
get { return GetValueInt("MinimumFreeSpaceWhenImporting", 100); }
|
|
||||||
|
|
||||||
set { SetValue("MinimumFreeSpaceWhenImporting", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CopyUsingHardlinks
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("CopyUsingHardlinks", true); }
|
|
||||||
|
|
||||||
set { SetValue("CopyUsingHardlinks", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnableMediaInfo
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("EnableMediaInfo", true); }
|
|
||||||
|
|
||||||
set { SetValue("EnableMediaInfo", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ImportExtraFiles
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("ImportExtraFiles", false); }
|
|
||||||
|
|
||||||
set { SetValue("ImportExtraFiles", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ExtraFileExtensions
|
|
||||||
{
|
|
||||||
get { return GetValue("ExtraFileExtensions", "srt"); }
|
|
||||||
|
|
||||||
set { SetValue("ExtraFileExtensions", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AutoRenameFolders
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("AutoRenameFolders", false); }
|
|
||||||
|
|
||||||
set { SetValue("AutoRenameFolders", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public RescanAfterRefreshType RescanAfterRefresh
|
|
||||||
{
|
|
||||||
get { return GetValueEnum("RescanAfterRefresh", RescanAfterRefreshType.Always); }
|
|
||||||
|
|
||||||
set { SetValue("RescanAfterRefresh", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetPermissionsLinux
|
|
||||||
{
|
|
||||||
get { return GetValueBoolean("SetPermissionsLinux", false); }
|
|
||||||
|
|
||||||
set { SetValue("SetPermissionsLinux", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string FileChmod
|
|
||||||
{
|
|
||||||
get { return GetValue("FileChmod", "0644"); }
|
|
||||||
|
|
||||||
set { SetValue("FileChmod", value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int FirstDayOfWeek
|
public int FirstDayOfWeek
|
||||||
{
|
{
|
||||||
get { return GetValueInt("FirstDayOfWeek", (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); }
|
get { return GetValueInt("FirstDayOfWeek", (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); }
|
||||||
|
@@ -22,24 +22,8 @@ namespace NzbDrone.Core.Configuration
|
|||||||
bool AutoRedownloadFailed { get; set; }
|
bool AutoRedownloadFailed { get; set; }
|
||||||
bool RemoveFailedDownloads { get; set; }
|
bool RemoveFailedDownloads { get; set; }
|
||||||
|
|
||||||
//Media Management
|
//History
|
||||||
bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; }
|
int HistoryCleanupDays { get; set; }
|
||||||
string RecycleBin { get; set; }
|
|
||||||
int RecycleBinCleanupDays { get; set; }
|
|
||||||
bool CreateEmptyMovieFolders { get; set; }
|
|
||||||
bool DeleteEmptyFolders { get; set; }
|
|
||||||
bool SkipFreeSpaceCheckWhenImporting { get; set; }
|
|
||||||
int MinimumFreeSpaceWhenImporting { get; set; }
|
|
||||||
bool CopyUsingHardlinks { get; set; }
|
|
||||||
bool EnableMediaInfo { get; set; }
|
|
||||||
bool ImportExtraFiles { get; set; }
|
|
||||||
string ExtraFileExtensions { get; set; }
|
|
||||||
RescanAfterRefreshType RescanAfterRefresh { get; set; }
|
|
||||||
bool AutoRenameFolders { get; set; }
|
|
||||||
|
|
||||||
//Permissions (Media Management)
|
|
||||||
bool SetPermissionsLinux { get; set; }
|
|
||||||
string FileChmod { get; set; }
|
|
||||||
|
|
||||||
//Indexers
|
//Indexers
|
||||||
int Retention { get; set; }
|
int Retention { get; set; }
|
||||||
|
8
src/NzbDrone.Core/History/CleanupHistoryCommand.cs
Normal file
8
src/NzbDrone.Core/History/CleanupHistoryCommand.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.History
|
||||||
|
{
|
||||||
|
public class CleanUpHistoryCommand : Command
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@@ -26,6 +26,6 @@ namespace NzbDrone.Core.History
|
|||||||
IndexerQuery = 2,
|
IndexerQuery = 2,
|
||||||
IndexerRss = 3,
|
IndexerRss = 3,
|
||||||
IndexerAuth = 4,
|
IndexerAuth = 4,
|
||||||
IndexerCapabilities = 5
|
IndexerInfo = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ namespace NzbDrone.Core.History
|
|||||||
void DeleteForIndexers(List<int> indexerIds);
|
void DeleteForIndexers(List<int> indexerIds);
|
||||||
History MostRecentForIndexer(int indexerId);
|
History MostRecentForIndexer(int indexerId);
|
||||||
List<History> Since(DateTime date, HistoryEventType? eventType);
|
List<History> Since(DateTime date, HistoryEventType? eventType);
|
||||||
|
void Cleanup(int days);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
||||||
@@ -61,6 +62,11 @@ namespace NzbDrone.Core.History
|
|||||||
Delete(c => indexerIds.Contains(c.IndexerId));
|
Delete(c => indexerIds.Contains(c.IndexerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Cleanup(int days)
|
||||||
|
{
|
||||||
|
Delete(c => c.Date.AddDays(days) <= DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
public History MostRecentForIndexer(int indexerId)
|
public History MostRecentForIndexer(int indexerId)
|
||||||
{
|
{
|
||||||
return Query(x => x.IndexerId == indexerId)
|
return Query(x => x.IndexerId == indexerId)
|
||||||
|
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Indexers.Events;
|
using NzbDrone.Core.Indexers.Events;
|
||||||
@@ -29,14 +30,17 @@ namespace NzbDrone.Core.History
|
|||||||
IHandle<ProviderDeletedEvent<IIndexer>>,
|
IHandle<ProviderDeletedEvent<IIndexer>>,
|
||||||
IHandle<IndexerQueryEvent>,
|
IHandle<IndexerQueryEvent>,
|
||||||
IHandle<IndexerDownloadEvent>,
|
IHandle<IndexerDownloadEvent>,
|
||||||
IHandle<IndexerAuthEvent>
|
IHandle<IndexerAuthEvent>,
|
||||||
|
IExecute<CleanUpHistoryCommand>
|
||||||
{
|
{
|
||||||
private readonly IHistoryRepository _historyRepository;
|
private readonly IHistoryRepository _historyRepository;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public HistoryService(IHistoryRepository historyRepository, Logger logger)
|
public HistoryService(IHistoryRepository historyRepository, IConfigService configService, Logger logger)
|
||||||
{
|
{
|
||||||
_historyRepository = historyRepository;
|
_historyRepository = historyRepository;
|
||||||
|
_configService = configService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +89,23 @@ namespace NzbDrone.Core.History
|
|||||||
return _historyRepository.Since(date, eventType);
|
return _historyRepository.Since(date, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Cleanup()
|
||||||
|
{
|
||||||
|
var cleanupDays = _configService.HistoryCleanupDays;
|
||||||
|
|
||||||
|
if (cleanupDays == 0)
|
||||||
|
{
|
||||||
|
_logger.Info("Automatic cleanup of History is disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Removing items older than {0} days from the history", cleanupDays);
|
||||||
|
|
||||||
|
_historyRepository.Cleanup(cleanupDays);
|
||||||
|
|
||||||
|
_logger.Debug("History has been cleaned up.");
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(IndexerQueryEvent message)
|
public void Handle(IndexerQueryEvent message)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new History
|
||||||
@@ -171,5 +192,10 @@ namespace NzbDrone.Core.History
|
|||||||
{
|
{
|
||||||
_historyRepository.DeleteForIndexers(new List<int> { message.ProviderId });
|
_historyRepository.DeleteForIndexers(new List<int> { message.ProviderId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Execute(CleanUpHistoryCommand message)
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ using NzbDrone.Core.Applications;
|
|||||||
using NzbDrone.Core.Backup;
|
using NzbDrone.Core.Backup;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.HealthCheck;
|
using NzbDrone.Core.HealthCheck;
|
||||||
|
using NzbDrone.Core.History;
|
||||||
using NzbDrone.Core.Housekeeping;
|
using NzbDrone.Core.Housekeeping;
|
||||||
using NzbDrone.Core.IndexerVersions;
|
using NzbDrone.Core.IndexerVersions;
|
||||||
using NzbDrone.Core.Lifecycle;
|
using NzbDrone.Core.Lifecycle;
|
||||||
@@ -61,6 +62,7 @@ namespace NzbDrone.Core.Jobs
|
|||||||
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(ApplicationCheckUpdateCommand).FullName },
|
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(ApplicationCheckUpdateCommand).FullName },
|
||||||
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(CheckHealthCommand).FullName },
|
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(CheckHealthCommand).FullName },
|
||||||
new ScheduledTask { Interval = 24 * 60, TypeName = typeof(HousekeepingCommand).FullName },
|
new ScheduledTask { Interval = 24 * 60, TypeName = typeof(HousekeepingCommand).FullName },
|
||||||
|
new ScheduledTask { Interval = 24 * 60, TypeName = typeof(CleanUpHistoryCommand).FullName },
|
||||||
new ScheduledTask { Interval = 24 * 60, TypeName = typeof(IndexerDefinitionUpdateCommand).FullName },
|
new ScheduledTask { Interval = 24 * 60, TypeName = typeof(IndexerDefinitionUpdateCommand).FullName },
|
||||||
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(ApplicationIndexerSyncCommand).FullName },
|
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(ApplicationIndexerSyncCommand).FullName },
|
||||||
|
|
||||||
@@ -106,40 +108,6 @@ namespace NzbDrone.Core.Jobs
|
|||||||
return interval * 60 * 24;
|
return interval * 60 * 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetRssSyncInterval()
|
|
||||||
{
|
|
||||||
var interval = _configService.RssSyncInterval;
|
|
||||||
|
|
||||||
if (interval > 0 && interval < 10)
|
|
||||||
{
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interval < 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetImportListSyncInterval()
|
|
||||||
{
|
|
||||||
var interval = _configService.ImportListSyncInterval;
|
|
||||||
|
|
||||||
if (interval > 0 && interval < 10)
|
|
||||||
{
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interval < 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Handle(CommandExecutedEvent message)
|
public void Handle(CommandExecutedEvent message)
|
||||||
{
|
{
|
||||||
var scheduledTask = _scheduledTaskRepository.All().SingleOrDefault(c => c.TypeName == message.Command.Body.GetType().FullName);
|
var scheduledTask = _scheduledTaskRepository.All().SingleOrDefault(c => c.TypeName == message.Command.Body.GetType().FullName);
|
||||||
|
@@ -40,6 +40,7 @@ namespace Prowlarr.Api.V1.Config
|
|||||||
public string BackupFolder { get; set; }
|
public string BackupFolder { get; set; }
|
||||||
public int BackupInterval { get; set; }
|
public int BackupInterval { get; set; }
|
||||||
public int BackupRetention { get; set; }
|
public int BackupRetention { get; set; }
|
||||||
|
public int HistoryCleanupDays { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HostConfigResourceMapper
|
public static class HostConfigResourceMapper
|
||||||
@@ -80,7 +81,8 @@ namespace Prowlarr.Api.V1.Config
|
|||||||
CertificateValidation = configService.CertificateValidation,
|
CertificateValidation = configService.CertificateValidation,
|
||||||
BackupFolder = configService.BackupFolder,
|
BackupFolder = configService.BackupFolder,
|
||||||
BackupInterval = configService.BackupInterval,
|
BackupInterval = configService.BackupInterval,
|
||||||
BackupRetention = configService.BackupRetention
|
BackupRetention = configService.BackupRetention,
|
||||||
|
HistoryCleanupDays = configService.HistoryCleanupDays
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +0,0 @@
|
|||||||
using FluentValidation;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Validation;
|
|
||||||
using NzbDrone.Core.Validation.Paths;
|
|
||||||
using Prowlarr.Http;
|
|
||||||
|
|
||||||
namespace Prowlarr.Api.V1.Config
|
|
||||||
{
|
|
||||||
[V1ApiController("config/mediamanagement")]
|
|
||||||
public class MediaManagementConfigController : ConfigController<MediaManagementConfigResource>
|
|
||||||
{
|
|
||||||
public MediaManagementConfigController(IConfigService configService, PathExistsValidator pathExistsValidator, FileChmodValidator fileChmodValidator)
|
|
||||||
: base(configService)
|
|
||||||
{
|
|
||||||
SharedValidator.RuleFor(c => c.RecycleBinCleanupDays).GreaterThanOrEqualTo(0);
|
|
||||||
SharedValidator.RuleFor(c => c.FileChmod).SetValidator(fileChmodValidator).When(c => !string.IsNullOrEmpty(c.FileChmod) && (OsInfo.IsLinux || OsInfo.IsOsx));
|
|
||||||
SharedValidator.RuleFor(c => c.RecycleBin).IsValidPath().SetValidator(pathExistsValidator).When(c => !string.IsNullOrWhiteSpace(c.RecycleBin));
|
|
||||||
SharedValidator.RuleFor(c => c.MinimumFreeSpaceWhenImporting).GreaterThanOrEqualTo(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override MediaManagementConfigResource ToResource(IConfigService model)
|
|
||||||
{
|
|
||||||
return MediaManagementConfigResourceMapper.ToResource(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using Prowlarr.Http.REST;
|
|
||||||
|
|
||||||
namespace Prowlarr.Api.V1.Config
|
|
||||||
{
|
|
||||||
public class MediaManagementConfigResource : RestResource
|
|
||||||
{
|
|
||||||
public bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; }
|
|
||||||
public string RecycleBin { get; set; }
|
|
||||||
public int RecycleBinCleanupDays { get; set; }
|
|
||||||
public bool CreateEmptyMovieFolders { get; set; }
|
|
||||||
public bool DeleteEmptyFolders { get; set; }
|
|
||||||
public RescanAfterRefreshType RescanAfterRefresh { get; set; }
|
|
||||||
public bool AutoRenameFolders { get; set; }
|
|
||||||
public bool PathsDefaultStatic { get; set; }
|
|
||||||
|
|
||||||
public bool SetPermissionsLinux { get; set; }
|
|
||||||
public string FileChmod { get; set; }
|
|
||||||
|
|
||||||
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
|
|
||||||
public int MinimumFreeSpaceWhenImporting { get; set; }
|
|
||||||
public bool CopyUsingHardlinks { get; set; }
|
|
||||||
public bool ImportExtraFiles { get; set; }
|
|
||||||
public string ExtraFileExtensions { get; set; }
|
|
||||||
public bool EnableMediaInfo { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MediaManagementConfigResourceMapper
|
|
||||||
{
|
|
||||||
public static MediaManagementConfigResource ToResource(IConfigService model)
|
|
||||||
{
|
|
||||||
return new MediaManagementConfigResource
|
|
||||||
{
|
|
||||||
AutoUnmonitorPreviouslyDownloadedMovies = model.AutoUnmonitorPreviouslyDownloadedMovies,
|
|
||||||
RecycleBin = model.RecycleBin,
|
|
||||||
RecycleBinCleanupDays = model.RecycleBinCleanupDays,
|
|
||||||
CreateEmptyMovieFolders = model.CreateEmptyMovieFolders,
|
|
||||||
DeleteEmptyFolders = model.DeleteEmptyFolders,
|
|
||||||
RescanAfterRefresh = model.RescanAfterRefresh,
|
|
||||||
AutoRenameFolders = model.AutoRenameFolders,
|
|
||||||
|
|
||||||
SetPermissionsLinux = model.SetPermissionsLinux,
|
|
||||||
FileChmod = model.FileChmod,
|
|
||||||
|
|
||||||
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
|
|
||||||
MinimumFreeSpaceWhenImporting = model.MinimumFreeSpaceWhenImporting,
|
|
||||||
CopyUsingHardlinks = model.CopyUsingHardlinks,
|
|
||||||
ImportExtraFiles = model.ImportExtraFiles,
|
|
||||||
ExtraFileExtensions = model.ExtraFileExtensions,
|
|
||||||
EnableMediaInfo = model.EnableMediaInfo
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user