New: Ability to skip redownload when marking an item as failed from Activity Queue

pull/5835/head
PearsonFlyer 1 year ago committed by Mark McDowall
parent 38f263931f
commit d7025a98de

@ -45,14 +45,14 @@ class QueueRow extends Component {
this.setState({ isRemoveQueueItemModalOpen: true }); this.setState({ isRemoveQueueItemModalOpen: true });
}; };
onRemoveQueueItemModalConfirmed = (blocklist) => { onRemoveQueueItemModalConfirmed = (blocklist, skipRedownload) => {
const { const {
onRemoveQueueItemPress, onRemoveQueueItemPress,
onQueueRowModalOpenOrClose onQueueRowModalOpenOrClose
} = this.props; } = this.props;
onQueueRowModalOpenOrClose(false); onQueueRowModalOpenOrClose(false);
onRemoveQueueItemPress(blocklist); onRemoveQueueItemPress(blocklist, skipRedownload);
this.setState({ isRemoveQueueItemModalOpen: false }); this.setState({ isRemoveQueueItemModalOpen: false });
}; };

@ -10,6 +10,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props'; import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class RemoveQueueItemModal extends Component { class RemoveQueueItemModal extends Component {
@ -21,7 +22,8 @@ class RemoveQueueItemModal extends Component {
this.state = { this.state = {
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}; };
} }
@ -31,7 +33,8 @@ class RemoveQueueItemModal extends Component {
resetState = function() { resetState = function() {
this.setState({ this.setState({
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}); });
}; };
@ -46,6 +49,10 @@ class RemoveQueueItemModal extends Component {
this.setState({ blocklist: value }); this.setState({ blocklist: value });
}; };
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => { onRemoveConfirmed = () => {
const state = this.state; const state = this.state;
@ -69,7 +76,7 @@ class RemoveQueueItemModal extends Component {
isPending isPending
} = this.props; } = this.props;
const { remove, blocklist } = this.state; const { remove, blocklist, skipRedownload } = this.state;
return ( return (
<Modal <Modal
@ -118,6 +125,20 @@ class RemoveQueueItemModal extends Component {
/> />
</FormGroup> </FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

@ -23,7 +23,8 @@ class RemoveQueueItemsModal extends Component {
this.state = { this.state = {
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}; };
} }
@ -33,7 +34,8 @@ class RemoveQueueItemsModal extends Component {
resetState = function() { resetState = function() {
this.setState({ this.setState({
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}); });
}; };
@ -48,6 +50,10 @@ class RemoveQueueItemsModal extends Component {
this.setState({ blocklist: value }); this.setState({ blocklist: value });
}; };
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => { onRemoveConfirmed = () => {
const state = this.state; const state = this.state;
@ -71,7 +77,7 @@ class RemoveQueueItemsModal extends Component {
allPending allPending
} = this.props; } = this.props;
const { remove, blocklist } = this.state; const { remove, blocklist, skipRedownload } = this.state;
return ( return (
<Modal <Modal
@ -122,6 +128,20 @@ class RemoveQueueItemsModal extends Component {
/> />
</FormGroup> </FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

@ -381,13 +381,14 @@ export const actionHandlers = handleThunks({
const { const {
id, id,
remove, remove,
blocklist blocklist,
skipRedownload
} = payload; } = payload;
dispatch(updateItem({ section: paged, id, isRemoving: true })); dispatch(updateItem({ section: paged, id, isRemoving: true }));
const promise = createAjaxRequest({ const promise = createAjaxRequest({
url: `/queue/${id}?removeFromClient=${remove}&blocklist=${blocklist}`, url: `/queue/${id}?removeFromClient=${remove}&blocklist=${blocklist}&skipRedownload=${skipRedownload}`,
method: 'DELETE' method: 'DELETE'
}).request; }).request;
@ -404,7 +405,8 @@ export const actionHandlers = handleThunks({
const { const {
ids, ids,
remove, remove,
blocklist blocklist,
skipRedownload
} = payload; } = payload;
dispatch(batchActions([ dispatch(batchActions([
@ -420,7 +422,7 @@ export const actionHandlers = handleThunks({
])); ]));
const promise = createAjaxRequest({ const promise = createAjaxRequest({
url: `/queue/bulk?removeFromClient=${remove}&blocklist=${blocklist}`, url: `/queue/bulk?removeFromClient=${remove}&blocklist=${blocklist}&skipRedownload=${skipRedownload}`,
method: 'DELETE', method: 'DELETE',
dataType: 'json', dataType: 'json',
contentType: 'application/json', contentType: 'application/json',

@ -23,5 +23,6 @@ namespace NzbDrone.Core.Download
public Dictionary<string, string> Data { get; set; } public Dictionary<string, string> Data { get; set; }
public TrackedDownload TrackedDownload { get; set; } public TrackedDownload TrackedDownload { get; set; }
public List<Language> Languages { get; set; } public List<Language> Languages { get; set; }
public bool SkipRedownload { get; set; }
} }
} }

@ -9,8 +9,8 @@ namespace NzbDrone.Core.Download
{ {
public interface IFailedDownloadService public interface IFailedDownloadService
{ {
void MarkAsFailed(int historyId); void MarkAsFailed(int historyId, bool skipRedownload = false);
void MarkAsFailed(string downloadId); void MarkAsFailed(string downloadId, bool skipRedownload = false);
void Check(TrackedDownload trackedDownload); void Check(TrackedDownload trackedDownload);
void ProcessFailed(TrackedDownload trackedDownload); void ProcessFailed(TrackedDownload trackedDownload);
} }
@ -30,14 +30,14 @@ namespace NzbDrone.Core.Download
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
} }
public void MarkAsFailed(int historyId) public void MarkAsFailed(int historyId, bool skipRedownload = false)
{ {
var history = _historyService.Get(historyId); var history = _historyService.Get(historyId);
var downloadId = history.DownloadId; var downloadId = history.DownloadId;
if (downloadId.IsNullOrWhiteSpace()) if (downloadId.IsNullOrWhiteSpace())
{ {
PublishDownloadFailedEvent(new List<EpisodeHistory> { history }, "Manually marked as failed"); PublishDownloadFailedEvent(new List<EpisodeHistory> { history }, "Manually marked as failed", skipRedownload: skipRedownload);
return; return;
} }
@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download
PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed"); PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed");
} }
public void MarkAsFailed(string downloadId) public void MarkAsFailed(string downloadId, bool skipRedownload = false)
{ {
var history = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed); var history = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed);
@ -65,7 +65,7 @@ namespace NzbDrone.Core.Download
{ {
var trackedDownload = _trackedDownloadService.Find(downloadId); var trackedDownload = _trackedDownloadService.Find(downloadId);
PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload); PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload, skipRedownload: skipRedownload);
} }
} }
@ -125,7 +125,7 @@ namespace NzbDrone.Core.Download
PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload); PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload);
} }
private void PublishDownloadFailedEvent(List<EpisodeHistory> historyItems, string message, TrackedDownload trackedDownload = null) private void PublishDownloadFailedEvent(List<EpisodeHistory> historyItems, string message, TrackedDownload trackedDownload = null, bool skipRedownload = false)
{ {
var historyItem = historyItems.First(); var historyItem = historyItems.First();
@ -140,7 +140,8 @@ namespace NzbDrone.Core.Download
Message = message, Message = message,
Data = historyItem.Data, Data = historyItem.Data,
TrackedDownload = trackedDownload, TrackedDownload = trackedDownload,
Languages = historyItem.Languages Languages = historyItem.Languages,
SkipRedownload = skipRedownload
}; };
_eventAggregator.PublishEvent(downloadFailedEvent); _eventAggregator.PublishEvent(downloadFailedEvent);

@ -1,4 +1,4 @@
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch; using NzbDrone.Core.IndexerSearch;
@ -30,6 +30,12 @@ namespace NzbDrone.Core.Download
[EventHandleOrder(EventHandleOrder.Last)] [EventHandleOrder(EventHandleOrder.Last)]
public void Handle(DownloadFailedEvent message) public void Handle(DownloadFailedEvent message)
{ {
if (message.SkipRedownload)
{
_logger.Debug("Skip redownloading requested by user");
return;
}
if (!_configService.AutoRedownloadFailed) if (!_configService.AutoRedownloadFailed)
{ {
_logger.Debug("Auto redownloading failed episodes is disabled"); _logger.Debug("Auto redownloading failed episodes is disabled");

@ -276,6 +276,8 @@
"ShownClickToHide": "Shown, click to hide", "ShownClickToHide": "Shown, click to hide",
"Size": "Size", "Size": "Size",
"SizeOnDisk": "Size on disk", "SizeOnDisk": "Size on disk",
"SkipRedownloadHelpText": "Prevents Sonarr from trying to download an alternative release for this item",
"SkipRedownload": "Skip Redownload",
"Source": "Source", "Source": "Source",
"Special": "Special", "Special": "Special",
"Started": "Started", "Started": "Started",

@ -70,7 +70,7 @@ namespace Sonarr.Api.V3.Queue
} }
[RestDeleteById] [RestDeleteById]
public void RemoveAction(int id, bool removeFromClient = true, bool blocklist = false) public void RemoveAction(int id, bool removeFromClient = true, bool blocklist = false, bool skipRedownload = false)
{ {
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id); var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
@ -88,12 +88,12 @@ namespace Sonarr.Api.V3.Queue
throw new NotFoundException(); throw new NotFoundException();
} }
Remove(trackedDownload, removeFromClient, blocklist); Remove(trackedDownload, removeFromClient, blocklist, skipRedownload);
_trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId); _trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId);
} }
[HttpDelete("bulk")] [HttpDelete("bulk")]
public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blocklist = false) public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blocklist = false, [FromQuery] bool skipRedownload = false)
{ {
var trackedDownloadIds = new List<string>(); var trackedDownloadIds = new List<string>();
var pendingToRemove = new List<NzbDrone.Core.Queue.Queue>(); var pendingToRemove = new List<NzbDrone.Core.Queue.Queue>();
@ -124,7 +124,7 @@ namespace Sonarr.Api.V3.Queue
foreach (var trackedDownload in trackedToRemove.DistinctBy(t => t.DownloadItem.DownloadId)) foreach (var trackedDownload in trackedToRemove.DistinctBy(t => t.DownloadItem.DownloadId))
{ {
Remove(trackedDownload, removeFromClient, blocklist); Remove(trackedDownload, removeFromClient, blocklist, skipRedownload);
trackedDownloadIds.Add(trackedDownload.DownloadItem.DownloadId); trackedDownloadIds.Add(trackedDownload.DownloadItem.DownloadId);
} }
@ -255,7 +255,7 @@ namespace Sonarr.Api.V3.Queue
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id); _pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
} }
private TrackedDownload Remove(TrackedDownload trackedDownload, bool removeFromClient, bool blocklist) private TrackedDownload Remove(TrackedDownload trackedDownload, bool removeFromClient, bool blocklist, bool skipRedownload)
{ {
if (removeFromClient) if (removeFromClient)
{ {
@ -271,7 +271,7 @@ namespace Sonarr.Api.V3.Queue
if (blocklist) if (blocklist)
{ {
_failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId); _failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId, skipRedownload);
} }
if (!removeFromClient && !blocklist) if (!removeFromClient && !blocklist)

Loading…
Cancel
Save