New: Optionally remove from queue by changing category to 'Post-Import Category' when configured

(cherry picked from commit 345854d0fe9b65a561fdab12aac688782a420aa5)

Closes #4510
pull/4511/head
Mark McDowall 3 months ago committed by Bogdan
parent 6a1fbd64b4
commit 6517485e0f

@ -25,7 +25,7 @@ import toggleSelected from 'Utilities/Table/toggleSelected';
import QueueFilterModal from './QueueFilterModal';
import QueueOptionsConnector from './QueueOptionsConnector';
import QueueRowConnector from './QueueRowConnector';
import RemoveQueueItemsModal from './RemoveQueueItemsModal';
import RemoveQueueItemModal from './RemoveQueueItemModal';
class Queue extends Component {
@ -309,9 +309,16 @@ class Queue extends Component {
}
</PageContentBody>
<RemoveQueueItemsModal
<RemoveQueueItemModal
isOpen={isConfirmRemoveModalOpen}
selectedCount={selectedCount}
canChangeCategory={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
return !!(item && item.downloadClientHasPostImportCategory);
})
)}
canIgnore={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
@ -319,7 +326,7 @@ class Queue extends Component {
return !!(item && item.artistId && item.albumId);
})
)}
allPending={isConfirmRemoveModalOpen && (
pending={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);

@ -98,6 +98,7 @@ class QueueRow extends Component {
indexer,
outputPath,
downloadClient,
downloadClientHasPostImportCategory,
downloadForced,
estimatedCompletionTime,
added,
@ -403,6 +404,7 @@ class QueueRow extends Component {
<RemoveQueueItemModal
isOpen={isRemoveQueueItemModalOpen}
sourceTitle={title}
canChangeCategory={!!downloadClientHasPostImportCategory}
canIgnore={!!artist}
isPending={isPending}
onRemovePress={this.onRemoveQueueItemModalConfirmed}
@ -432,6 +434,7 @@ QueueRow.propTypes = {
indexer: PropTypes.string,
outputPath: PropTypes.string,
downloadClient: PropTypes.string,
downloadClientHasPostImportCategory: PropTypes.bool,
downloadForced: PropTypes.bool.isRequired,
estimatedCompletionTime: PropTypes.string,
added: PropTypes.string,

@ -1,175 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
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 Modal from 'Components/Modal/Modal';
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, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class RemoveQueueItemModal extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
removeFromClient: true,
blocklist: false,
skipRedownload: false
};
}
//
// Control
resetState = function() {
this.setState({
removeFromClient: true,
blocklist: false,
skipRedownload: false
});
};
//
// Listeners
onRemoveFromClientChange = ({ value }) => {
this.setState({ removeFromClient: value });
};
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
//
// Render
render() {
const {
isOpen,
sourceTitle,
canIgnore,
isPending
} = this.props;
const { removeFromClient, blocklist, skipRedownload } = this.state;
return (
<Modal
isOpen={isOpen}
size={sizes.MEDIUM}
onModalClose={this.onModalClose}
>
<ModalContent
onModalClose={this.onModalClose}
>
<ModalHeader>
Remove - {sourceTitle}
</ModalHeader>
<ModalBody>
<div>
Are you sure you want to remove '{sourceTitle}' from the queue?
</div>
{
isPending ?
null :
<FormGroup>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="removeFromClient"
value={removeFromClient}
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveFromClientChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>
{translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistReleaseHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blocklist &&
<FormGroup>
<FormLabel>
{translate('SkipRedownload')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup>
}
</ModalBody>
<ModalFooter>
<Button onPress={this.onModalClose}>
Close
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
Remove
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
}
RemoveQueueItemModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
sourceTitle: PropTypes.string.isRequired,
canIgnore: PropTypes.bool.isRequired,
isPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default RemoveQueueItemModal;

@ -0,0 +1,230 @@
import React, { useCallback, useMemo, useState } from 'react';
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 Modal from 'Components/Modal/Modal';
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, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RemoveQueueItemModal.css';
interface RemovePressProps {
remove: boolean;
changeCategory: boolean;
blocklist: boolean;
skipRedownload: boolean;
}
interface RemoveQueueItemModalProps {
isOpen: boolean;
sourceTitle: string;
canChangeCategory: boolean;
canIgnore: boolean;
isPending: boolean;
selectedCount?: number;
onRemovePress(props: RemovePressProps): void;
onModalClose: () => void;
}
type RemovalMethod = 'removeFromClient' | 'changeCategory' | 'ignore';
type BlocklistMethod =
| 'doNotBlocklist'
| 'blocklistAndSearch'
| 'blocklistOnly';
function RemoveQueueItemModal(props: RemoveQueueItemModalProps) {
const {
isOpen,
sourceTitle,
canIgnore,
canChangeCategory,
isPending,
selectedCount,
onRemovePress,
onModalClose,
} = props;
const multipleSelected = selectedCount && selectedCount > 1;
const [removalMethod, setRemovalMethod] =
useState<RemovalMethod>('removeFromClient');
const [blocklistMethod, setBlocklistMethod] =
useState<BlocklistMethod>('doNotBlocklist');
const { title, message } = useMemo(() => {
if (!selectedCount) {
return {
title: translate('RemoveQueueItem', { sourceTitle }),
message: translate('RemoveQueueItemConfirmation', { sourceTitle }),
};
}
if (selectedCount === 1) {
return {
title: translate('RemoveSelectedItem'),
message: translate('RemoveSelectedItemQueueMessageText'),
};
}
return {
title: translate('RemoveSelectedItems'),
message: translate('RemoveSelectedItemsQueueMessageText', {
selectedCount,
}),
};
}, [sourceTitle, selectedCount]);
const removalMethodOptions = useMemo(() => {
return [
{
key: 'removeFromClient',
value: translate('RemoveFromDownloadClient'),
hint: multipleSelected
? translate('RemoveMultipleFromDownloadClientHint')
: translate('RemoveFromDownloadClientHint'),
},
{
key: 'changeCategory',
value: translate('ChangeCategory'),
isDisabled: !canChangeCategory,
hint: multipleSelected
? translate('ChangeCategoryMultipleHint')
: translate('ChangeCategoryHint'),
},
{
key: 'ignore',
value: multipleSelected
? translate('IgnoreDownloads')
: translate('IgnoreDownload'),
isDisabled: !canIgnore,
hint: multipleSelected
? translate('IgnoreDownloadsHint')
: translate('IgnoreDownloadHint'),
},
];
}, [canChangeCategory, canIgnore, multipleSelected]);
const blocklistMethodOptions = useMemo(() => {
return [
{
key: 'doNotBlocklist',
value: translate('DoNotBlocklist'),
hint: translate('DoNotBlocklistHint'),
},
{
key: 'blocklistAndSearch',
value: translate('BlocklistAndSearch'),
hint: multipleSelected
? translate('BlocklistAndSearchMultipleHint')
: translate('BlocklistAndSearchHint'),
},
{
key: 'blocklistOnly',
value: translate('BlocklistOnly'),
hint: multipleSelected
? translate('BlocklistMultipleOnlyHint')
: translate('BlocklistOnlyHint'),
},
];
}, [multipleSelected]);
const handleRemovalMethodChange = useCallback(
({ value }: { value: RemovalMethod }) => {
setRemovalMethod(value);
},
[setRemovalMethod]
);
const handleBlocklistMethodChange = useCallback(
({ value }: { value: BlocklistMethod }) => {
setBlocklistMethod(value);
},
[setBlocklistMethod]
);
const handleConfirmRemove = useCallback(() => {
onRemovePress({
remove: removalMethod === 'removeFromClient',
changeCategory: removalMethod === 'changeCategory',
blocklist: blocklistMethod !== 'doNotBlocklist',
skipRedownload: blocklistMethod === 'blocklistOnly',
});
setRemovalMethod('removeFromClient');
setBlocklistMethod('doNotBlocklist');
}, [
removalMethod,
blocklistMethod,
setRemovalMethod,
setBlocklistMethod,
onRemovePress,
]);
const handleModalClose = useCallback(() => {
setRemovalMethod('removeFromClient');
setBlocklistMethod('doNotBlocklist');
onModalClose();
}, [setRemovalMethod, setBlocklistMethod, onModalClose]);
return (
<Modal isOpen={isOpen} size={sizes.MEDIUM} onModalClose={handleModalClose}>
<ModalContent onModalClose={handleModalClose}>
<ModalHeader>{title}</ModalHeader>
<ModalBody>
<div className={styles.message}>{message}</div>
{isPending ? null : (
<FormGroup>
<FormLabel>{translate('RemoveQueueItemRemovalMethod')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="removalMethod"
value={removalMethod}
values={removalMethodOptions}
isDisabled={!canChangeCategory && !canIgnore}
helpTextWarning={translate(
'RemoveQueueItemRemovalMethodHelpTextWarning'
)}
onChange={handleRemovalMethodChange}
/>
</FormGroup>
)}
<FormGroup>
<FormLabel>
{multipleSelected
? translate('BlocklistReleases')
: translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="blocklistMethod"
value={blocklistMethod}
values={blocklistMethodOptions}
helpText={translate('BlocklistReleaseHelpText')}
onChange={handleBlocklistMethodChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button onPress={handleModalClose}>{translate('Close')}</Button>
<Button kind={kinds.DANGER} onPress={handleConfirmRemove}>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
export default RemoveQueueItemModal;

@ -276,6 +276,7 @@ FormInputGroup.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.any,
values: PropTypes.arrayOf(PropTypes.any),
isDisabled: PropTypes.bool,
type: PropTypes.string.isRequired,
kind: PropTypes.oneOf(kinds.all),
min: PropTypes.number,

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

@ -65,7 +65,7 @@ namespace Lidarr.Api.V1.Queue
}
[RestDeleteById]
public void RemoveAction(int id, bool removeFromClient = true, bool blocklist = false, bool skipRedownload = false)
public void RemoveAction(int id, bool removeFromClient = true, bool blocklist = false, bool skipRedownload = false, bool changeCategory = false)
{
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
@ -83,12 +83,12 @@ namespace Lidarr.Api.V1.Queue
throw new NotFoundException();
}
Remove(trackedDownload, removeFromClient, blocklist, skipRedownload);
Remove(trackedDownload, removeFromClient, blocklist, skipRedownload, changeCategory);
_trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId);
}
[HttpDelete("bulk")]
public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blocklist = false, [FromQuery] bool skipRedownload = false)
public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blocklist = false, [FromQuery] bool skipRedownload = false, [FromQuery] bool changeCategory = false)
{
var trackedDownloadIds = new List<string>();
var pendingToRemove = new List<NzbDrone.Core.Queue.Queue>();
@ -119,7 +119,7 @@ namespace Lidarr.Api.V1.Queue
foreach (var trackedDownload in trackedToRemove.DistinctBy(t => t.DownloadItem.DownloadId))
{
Remove(trackedDownload, removeFromClient, blocklist, skipRedownload);
Remove(trackedDownload, removeFromClient, blocklist, skipRedownload, changeCategory);
trackedDownloadIds.Add(trackedDownload.DownloadItem.DownloadId);
}
@ -269,7 +269,7 @@ namespace Lidarr.Api.V1.Queue
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
}
private TrackedDownload Remove(TrackedDownload trackedDownload, bool removeFromClient, bool blocklist, bool skipRedownload)
private TrackedDownload Remove(TrackedDownload trackedDownload, bool removeFromClient, bool blocklist, bool skipRedownload, bool changeCategory)
{
if (removeFromClient)
{
@ -282,13 +282,24 @@ namespace Lidarr.Api.V1.Queue
downloadClient.RemoveItem(trackedDownload.DownloadItem, true);
}
else if (changeCategory)
{
var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient);
if (downloadClient == null)
{
throw new BadRequestException();
}
downloadClient.MarkItemAsImported(trackedDownload.DownloadItem);
}
if (blocklist)
{
_failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId, skipRedownload);
}
if (!removeFromClient && !blocklist)
if (!removeFromClient && !blocklist && !changeCategory)
{
if (!_ignoredDownloadService.IgnoreDownload(trackedDownload))
{

@ -35,6 +35,7 @@ namespace Lidarr.Api.V1.Queue
public string DownloadId { get; set; }
public DownloadProtocol Protocol { get; set; }
public string DownloadClient { get; set; }
public bool DownloadClientHasPostImportCategory { get; set; }
public string Indexer { get; set; }
public string OutputPath { get; set; }
public bool DownloadForced { get; set; }
@ -76,6 +77,7 @@ namespace Lidarr.Api.V1.Queue
DownloadId = model.DownloadId,
Protocol = model.Protocol,
DownloadClient = model.DownloadClient,
DownloadClientHasPostImportCategory = model.DownloadClientHasPostImportCategory,
Indexer = model.Indexer,
OutputPath = model.OutputPath,
DownloadForced = model.DownloadForced

@ -132,7 +132,7 @@ namespace NzbDrone.Core.Download.Clients.Aria2
CanMoveFiles = false,
CanBeRemoved = torrent.Status == "complete",
Category = null,
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = torrent.InfoHash?.ToUpper(),
IsEncrypted = false,
Message = torrent.ErrorMessage,

@ -89,7 +89,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
yield return new DownloadClientItem
{
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "Lidarr",
Title = item.Title,

@ -59,7 +59,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
yield return new DownloadClientItem
{
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "Lidarr",
Title = item.Title,

@ -135,7 +135,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
item.Title = torrent.Name;
item.Category = Settings.MusicCategory;
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, Settings.MusicImportedCategory.IsNotNullOrWhiteSpace());
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath));
item.OutputPath = outputPath + torrent.Name;

@ -89,7 +89,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
var item = new DownloadClientItem()
{
Category = Settings.MusicCategory,
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = CreateDownloadId(torrent.Id, serialNumber),
Title = torrent.Title,
TotalSize = torrent.Size,

@ -97,7 +97,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
var item = new DownloadClientItem()
{
Category = Settings.MusicCategory,
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = CreateDownloadId(nzb.Id, serialNumber),
Title = nzb.Title,
TotalSize = nzb.Size,

@ -108,7 +108,7 @@ namespace NzbDrone.Core.Download.Clients.Flood
var item = new DownloadClientItem
{
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = torrent.Key,
Title = properties.Name,
OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(properties.Directory)),

@ -73,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.FreeboxDownload
Category = Settings.Category,
Title = torrent.Name,
TotalSize = torrent.Size,
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
RemainingSize = (long)(torrent.Size * (double)(1 - ((double)torrent.ReceivedPrct / 10000))),
RemainingTime = torrent.Eta <= 0 ? null : TimeSpan.FromSeconds(torrent.Eta),
SeedRatio = torrent.StopRatio <= 0 ? 0 : torrent.StopRatio / 100,

@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
var item = new DownloadClientItem
{
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = torrent.InfoHash.ToUpper(),
OutputPath = outputPath + torrent.Name,
RemainingSize = torrent.TotalSize - torrent.DownloadedBytes,

@ -56,7 +56,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
{
var queueItem = new DownloadClientItem();
queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false);
queueItem.DownloadId = vortexQueueItem.AddUUID ?? vortexQueueItem.Id.ToString();
queueItem.Category = vortexQueueItem.GroupName;
queueItem.Title = vortexQueueItem.UiTitle;

@ -72,7 +72,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
queueItem.Title = item.NzbName;
queueItem.TotalSize = totalSize;
queueItem.Category = item.Category;
queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false);
queueItem.CanMoveFiles = true;
queueItem.CanBeRemoved = true;
@ -119,7 +119,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var historyItem = new DownloadClientItem();
var itemDir = item.FinalDir.IsNullOrWhiteSpace() ? item.DestDir : item.FinalDir;
historyItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
historyItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false);
historyItem.DownloadId = droneParameter == null ? item.Id.ToString() : droneParameter.Value.ToString();
historyItem.Title = item.Name;
historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo);

@ -73,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
var historyItem = new DownloadClientItem
{
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = GetDownloadClientId(file),
Title = title,

@ -229,7 +229,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
Category = torrent.Category.IsNotNullOrWhiteSpace() ? torrent.Category : torrent.Label,
Title = torrent.Name,
TotalSize = torrent.Size,
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, Settings.MusicImportedCategory.IsNotNullOrWhiteSpace()),
RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)),
RemainingTime = GetRemainingTime(torrent),
SeedRatio = torrent.Ratio

@ -63,7 +63,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
}
var queueItem = new DownloadClientItem();
queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false);
queueItem.DownloadId = sabQueueItem.Id;
queueItem.Category = sabQueueItem.Category;
queueItem.Title = sabQueueItem.Title;
@ -118,7 +118,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var historyItem = new DownloadClientItem
{
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false),
DownloadId = sabHistoryItem.Id,
Category = sabHistoryItem.Category,
Title = sabHistoryItem.Title,

@ -72,7 +72,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
item.Category = Settings.MusicCategory;
item.Title = torrent.Name;
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false);
item.OutputPath = GetOutputPath(outputPath, torrent);
item.TotalSize = torrent.TotalSize;

@ -143,7 +143,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
}
var item = new DownloadClientItem();
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, Settings.MusicImportedCategory.IsNotNullOrWhiteSpace());
item.Title = torrent.Name;
item.DownloadId = torrent.Hash;
item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.Path));

@ -120,7 +120,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
item.Title = torrent.Name;
item.TotalSize = torrent.Size;
item.Category = torrent.Label;
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, Settings.MusicImportedCategory.IsNotNullOrWhiteSpace());
item.RemainingSize = torrent.Remaining;
item.SeedRatio = torrent.Ratio;

@ -38,8 +38,10 @@ namespace NzbDrone.Core.Download
public string Type { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public bool HasPostImportCategory { get; set; }
public static DownloadClientItemClientInfo FromDownloadClient<TSettings>(DownloadClientBase<TSettings> downloadClient)
public static DownloadClientItemClientInfo FromDownloadClient<TSettings>(
DownloadClientBase<TSettings> downloadClient, bool hasPostImportCategory)
where TSettings : IProviderConfig, new()
{
return new DownloadClientItemClientInfo
@ -47,7 +49,8 @@ namespace NzbDrone.Core.Download
Protocol = downloadClient.Protocol,
Type = downloadClient.Name,
Id = downloadClient.Definition.Id,
Name = downloadClient.Definition.Name
Name = downloadClient.Definition.Name,
HasPostImportCategory = hasPostImportCategory
};
}
}

@ -160,6 +160,12 @@
"BindAddressHelpText": "Valid IP address, localhost or '*' for all interfaces",
"BindAddressHelpTextWarning": "Requires restart to take effect",
"Blocklist": "Blocklist",
"BlocklistAndSearch": "Blocklist and Search",
"BlocklistAndSearchHint": "Start a search for a replacement after blocklisting",
"BlocklistAndSearchMultipleHint": "Start searches for replacements after blocklisting",
"BlocklistMultipleOnlyHint": "Blocklist without searching for replacements",
"BlocklistOnly": "Blocklist Only",
"BlocklistOnlyHint": "Blocklist without searching for a replacement",
"BlocklistRelease": "Blocklist Release",
"BlocklistReleaseHelpText": "Prevents {appName} from automatically grabbing these files again",
"BlocklistReleases": "Blocklist Releases",
@ -176,6 +182,9 @@
"CatalogNumber": "Catalog Number",
"CertificateValidation": "Certificate Validation",
"CertificateValidationHelpText": "Change how strict HTTPS certification validation is. Do not change unless you understand the risks.",
"ChangeCategory": "Change Category",
"ChangeCategoryHint": "Changes download to the 'Post-Import Category' from Download Client",
"ChangeCategoryMultipleHint": "Changes downloads to the 'Post-Import Category' from Download Client",
"ChangeFileDate": "Change File Date",
"ChangeHasNotBeenSavedYet": "Change has not been saved yet",
"ChmodFolder": "chmod Folder",
@ -332,6 +341,8 @@
"DiscNumber": "Disc Number",
"Discography": "Discography",
"DiskSpace": "Disk Space",
"DoNotBlocklist": "Do not Blocklist",
"DoNotBlocklistHint": "Remove without blocklisting",
"DoNotPrefer": "Do Not Prefer",
"DoNotUpgradeAutomatically": "Do not Upgrade Automatically",
"Docker": "Docker",
@ -491,6 +502,10 @@
"ICalLink": "iCal Link",
"IconForCutoffUnmet": "Icon for Cutoff Unmet",
"IfYouDontAddAnImportListExclusionAndTheArtistHasAMetadataProfileOtherThanNoneThenThisAlbumMayBeReaddedDuringTheNextArtistRefresh": "If you don't add an import list exclusion and the artist has a metadata profile other than 'None' then this album may be re-added during the next artist refresh.",
"IgnoreDownload": "Ignore Download",
"IgnoreDownloadHint": "Stops {appName} from processing this download further",
"IgnoreDownloads": "Ignore Downloads",
"IgnoreDownloadsHint": "Stops {appName} from processing these downloads further",
"Ignored": "Ignored",
"IgnoredAddresses": "Ignored Addresses",
"IgnoredHelpText": "The release will be rejected if it contains one or more of terms (case insensitive)",
@ -861,9 +876,15 @@
"RemoveFailedDownloadsHelpText": "Remove failed downloads from download client history",
"RemoveFilter": "Remove filter",
"RemoveFromBlocklist": "Remove from blocklist",
"RemoveFromDownloadClient": "Remove From Download Client",
"RemoveFromDownloadClientHelpTextWarning": "Removing will remove the download and the file(s) from the download client.",
"RemoveFromDownloadClient": "Remove from Download Client",
"RemoveFromDownloadClientHint": "Removes download and file(s) from download client",
"RemoveFromQueue": "Remove from queue",
"RemoveMultipleFromDownloadClientHint": "Removes downloads and files from download client",
"RemoveQueueItem": "Remove - {sourceTitle}",
"RemoveQueueItemConfirmation": "Are you sure you want to remove '{sourceTitle}' from the queue?",
"RemoveQueueItemRemovalMethod": "Removal Method",
"RemoveQueueItemRemovalMethodHelpTextWarning": "'Remove from Download Client' will remove the download and the file(s) from the download client.",
"RemoveQueueItemsRemovalMethodHelpTextWarning": "'Remove from Download Client' will remove the downloads and the files from the download client.",
"RemoveSelected": "Remove Selected",
"RemoveSelectedItem": "Remove Selected Item",
"RemoveSelectedItemBlocklistMessageText": "Are you sure you want to remove the selected items from the blocklist?",

@ -28,6 +28,7 @@ namespace NzbDrone.Core.Queue
public RemoteAlbum RemoteAlbum { get; set; }
public DownloadProtocol Protocol { get; set; }
public string DownloadClient { get; set; }
public bool DownloadClientHasPostImportCategory { get; set; }
public string Indexer { get; set; }
public string OutputPath { get; set; }
public string ErrorMessage { get; set; }

@ -90,7 +90,8 @@ namespace NzbDrone.Core.Queue
Indexer = trackedDownload.Indexer,
OutputPath = trackedDownload.DownloadItem.OutputPath.ToString(),
DownloadForced = downloadForced,
Added = trackedDownload.Added
Added = trackedDownload.Added,
DownloadClientHasPostImportCategory = trackedDownload.DownloadItem.DownloadClientInfo.HasPostImportCategory
};
queue.Id = HashConverter.GetHashInt31($"trackedDownload-{trackedDownload.DownloadClient}-{trackedDownload.DownloadItem.DownloadId}-album{album?.Id ?? 0}");

Loading…
Cancel
Save