Merge branch 'develop' into issue-5148
This commit is contained in:
commit
825e136443
|
@ -91,7 +91,8 @@ module.exports = (env) => {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: 'Content/styles.css'
|
filename: 'Content/styles.css',
|
||||||
|
chunkFilename: 'Content/[id]-[chunkhash].css'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
.tableScroller {
|
.tableScroller {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
transition: background-color 500ms;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--tableRowHoverBackgroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// This file is automatically generated.
|
// This file is automatically generated.
|
||||||
// Please do not change this file!
|
// Please do not change this file!
|
||||||
interface CssExports {
|
interface CssExports {
|
||||||
|
'row': string;
|
||||||
'tableScroller': string;
|
'tableScroller': string;
|
||||||
}
|
}
|
||||||
export const cssExports: CssExports;
|
export const cssExports: CssExports;
|
||||||
|
|
|
@ -65,6 +65,7 @@ const Row: React.FC<ListChildComponentProps<RowItemData>> = ({
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
|
className={styles.row}
|
||||||
>
|
>
|
||||||
<SeriesIndexRow
|
<SeriesIndexRow
|
||||||
seriesId={series.id}
|
seriesId={series.id}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class MonitoringOptionsModalContent extends Component {
|
||||||
const {
|
const {
|
||||||
isSaving,
|
isSaving,
|
||||||
saveError
|
saveError
|
||||||
} = prevProps;
|
} = this.props;
|
||||||
|
|
||||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -30,28 +30,28 @@ const caseOptions = [
|
||||||
const fileNameTokens = [
|
const fileNameTokens = [
|
||||||
{
|
{
|
||||||
token: '{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Quality Full}',
|
token: '{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Quality Full}',
|
||||||
example: 'Series Title (2010) - S01E01 - Episode Title HDTV-720p Proper'
|
example: 'The Series Title\'s! (2010) - S01E01 - Episode Title HDTV-720p Proper'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
token: '{Series Title} - {season:0}x{episode:00} - {Episode Title} {Quality Full}',
|
token: '{Series Title} - {season:0}x{episode:00} - {Episode Title} {Quality Full}',
|
||||||
example: 'Series Title (2010) - 1x01 - Episode Title HDTV-720p Proper'
|
example: 'The Series Title\'s! (2010) - 1x01 - Episode Title HDTV-720p Proper'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
token: '{Series.Title}.S{season:00}E{episode:00}.{EpisodeClean.Title}.{Quality.Full}',
|
token: '{Series.Title}.S{season:00}E{episode:00}.{EpisodeClean.Title}.{Quality.Full}',
|
||||||
example: 'Series.Title.(2010).S01E01.Episode.Title.HDTV-720p'
|
example: 'The.Series.Title\'s!.(2010).S01E01.Episode.Title.HDTV-720p'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const seriesTokens = [
|
const seriesTokens = [
|
||||||
{ token: '{Series Title}', example: 'Series Title\'s' },
|
{ token: '{Series Title}', example: 'The Series Title\'s!' },
|
||||||
{ token: '{Series CleanTitle}', example: 'Series Titles' },
|
{ token: '{Series CleanTitle}', example: 'The Series Title\'s!' },
|
||||||
{ token: '{Series CleanTitleYear}', example: 'Series Titles! 2010' },
|
{ token: '{Series CleanTitleYear}', example: 'The Series Titles! 2010' },
|
||||||
{ token: '{Series CleanTitleWithoutYear}', example: 'Series Titles!' },
|
{ token: '{Series CleanTitleWithoutYear}', example: 'The Series Title\'s!' },
|
||||||
{ token: '{Series TitleThe}', example: 'Series Title\'s, The' },
|
{ token: '{Series TitleThe}', example: 'Series Title\'s!, The' },
|
||||||
{ token: '{Series TitleTheYear}', example: 'Series Title\'s, The (2010)' },
|
{ token: '{Series TitleTheYear}', example: 'Series Title\'s!, The (2010)' },
|
||||||
{ token: '{Series TitleTheWithoutYear}', example: 'Series Title\'s, The' },
|
{ token: '{Series TitleTheWithoutYear}', example: 'Series Title\'s!, The' },
|
||||||
{ token: '{Series TitleYear}', example: 'Series Title\'s (2010)' },
|
{ token: '{Series TitleYear}', example: 'The Series Title\'s! (2010)' },
|
||||||
{ token: '{Series TitleWithoutYear}', example: 'Series Title\'s' },
|
{ token: '{Series TitleWithoutYear}', example: 'Series Title\'s!' },
|
||||||
{ token: '{Series TitleFirstCharacter}', example: 'S' },
|
{ token: '{Series TitleFirstCharacter}', example: 'S' },
|
||||||
{ token: '{Series Year}', example: '2010' }
|
{ token: '{Series Year}', example: '2010' }
|
||||||
];
|
];
|
||||||
|
@ -89,8 +89,8 @@ const episodeTitleTokens = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const qualityTokens = [
|
const qualityTokens = [
|
||||||
{ token: '{Quality Full}', example: 'HDTV-720p Proper' },
|
{ token: '{Quality Full}', example: 'WEBDL-1080p Proper' },
|
||||||
{ token: '{Quality Title}', example: 'HDTV-720p' }
|
{ token: '{Quality Title}', example: 'WEBDL-1080p' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const mediaInfoTokens = [
|
const mediaInfoTokens = [
|
||||||
|
@ -114,8 +114,8 @@ const otherTokens = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const originalTokens = [
|
const originalTokens = [
|
||||||
{ token: '{Original Title}', example: 'Series.Title.S01E01.HDTV.x264-EVOLVE' },
|
{ token: '{Original Title}', example: 'The.Series.Title\'s!.S01E01.WEBDL.1080p.x264-EVOLVE' },
|
||||||
{ token: '{Original Filename}', example: 'series.title.s01e01.hdtv.x264-EVOLVE' }
|
{ token: '{Original Filename}', example: 'the.series.title\'s!.s01e01.webdl.1080p.x264-EVOLVE' }
|
||||||
];
|
];
|
||||||
|
|
||||||
class NamingModal extends Component {
|
class NamingModal extends Component {
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -54,10 +54,14 @@ class MoreInfo extends Component {
|
||||||
{translate('IRC')}
|
{translate('IRC')}
|
||||||
</DescriptionListItemTitle>
|
</DescriptionListItemTitle>
|
||||||
<DescriptionListItemDescription>
|
<DescriptionListItemDescription>
|
||||||
<Link to="irc://irc.libera.chat/#sonarr">#sonarr on Libera</Link>
|
<Link to="irc://irc.libera.chat/#sonarr">
|
||||||
|
{translate('IRCLinkText')}
|
||||||
|
</Link>
|
||||||
</DescriptionListItemDescription>
|
</DescriptionListItemDescription>
|
||||||
<DescriptionListItemDescription>
|
<DescriptionListItemDescription>
|
||||||
<Link to="https://web.libera.chat/?channels=#sonarr">Libera webchat</Link>
|
<Link to="https://web.libera.chat/?channels=#sonarr">
|
||||||
|
{translate('LiberaWebchat')}
|
||||||
|
</Link>
|
||||||
</DescriptionListItemDescription>
|
</DescriptionListItemDescription>
|
||||||
|
|
||||||
<DescriptionListItemTitle>
|
<DescriptionListItemTitle>
|
||||||
|
|
|
@ -70,6 +70,8 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||||
[TestCase("[a] title", "a title")]
|
[TestCase("[a] title", "a title")]
|
||||||
[TestCase("backslash \\ backlash", "backslash backlash")]
|
[TestCase("backslash \\ backlash", "backslash backlash")]
|
||||||
[TestCase("I'm the Boss", "Im the Boss")]
|
[TestCase("I'm the Boss", "Im the Boss")]
|
||||||
|
[TestCase("The Title's", "The Title's")]
|
||||||
|
[TestCase("I'm after I'm", "Im after I'm")]
|
||||||
|
|
||||||
// [TestCase("", "")]
|
// [TestCase("", "")]
|
||||||
public void should_get_expected_title_back(string title, string expected)
|
public void should_get_expected_title_back(string title, string expected)
|
||||||
|
|
|
@ -54,6 +54,8 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||||
[TestCase("The Mist", 2018, "The Mist")]
|
[TestCase("The Mist", 2018, "The Mist")]
|
||||||
[TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE")]
|
[TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE")]
|
||||||
[TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It")]
|
[TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It")]
|
||||||
|
[TestCase("The Series Title's (2016)", 2016, "The Series Titles")]
|
||||||
|
[TestCase("The Series Title's", 2016, "The Series Title's")]
|
||||||
public void should_get_expected_title_back(string title, int year, string expected)
|
public void should_get_expected_title_back(string title, int year, string expected)
|
||||||
{
|
{
|
||||||
_series.Title = title;
|
_series.Title = title;
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||||
[TestCase("The Mist", 2018, "The Mist 2018")]
|
[TestCase("The Mist", 2018, "The Mist 2018")]
|
||||||
[TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE 1999")]
|
[TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE 1999")]
|
||||||
[TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It 2016")]
|
[TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It 2016")]
|
||||||
|
[TestCase("The Series Title's", 2016, "The Series Titles 2016")]
|
||||||
public void should_get_expected_title_back(string title, int year, string expected)
|
public void should_get_expected_title_back(string title, int year, string expected)
|
||||||
{
|
{
|
||||||
_series.Title = title;
|
_series.Title = title;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
public string Imdb { get; set; }
|
public string Imdb { get; set; }
|
||||||
public string Tmdb { get; set; }
|
public string Tmdb { get; set; }
|
||||||
public string Tvdb { get; set; }
|
public string Tvdb { get; set; }
|
||||||
|
public string Mal { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SimklSeriesPropsResource
|
public class SimklSeriesPropsResource
|
||||||
|
@ -23,11 +24,15 @@ namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
public class SimklSeriesResource
|
public class SimklSeriesResource
|
||||||
{
|
{
|
||||||
public SimklSeriesPropsResource Show { get; set; }
|
public SimklSeriesPropsResource Show { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("anime_type")]
|
||||||
|
public SimklAnimeType AnimeType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SimklResponse
|
public class SimklResponse
|
||||||
{
|
{
|
||||||
public List<SimklSeriesResource> Shows { get; set; }
|
public List<SimklSeriesResource> Shows { get; set; }
|
||||||
|
public List<SimklSeriesResource> Anime { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RefreshRequestResponse
|
public class RefreshRequestResponse
|
||||||
|
@ -66,4 +71,10 @@ namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
{
|
{
|
||||||
public DateTime All { get; set; }
|
public DateTime All { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SimklAnimeType
|
||||||
|
{
|
||||||
|
Tv,
|
||||||
|
Movie
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Instrumentation;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.ImportLists.Exceptions;
|
using NzbDrone.Core.ImportLists.Exceptions;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
@ -10,6 +12,11 @@ namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
public class SimklParser : IParseImportListResponse
|
public class SimklParser : IParseImportListResponse
|
||||||
{
|
{
|
||||||
private ImportListResponse _importResponse;
|
private ImportListResponse _importResponse;
|
||||||
|
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(SimklParser));
|
||||||
|
|
||||||
|
public SimklParser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IList<ImportListItemInfo> ParseResponse(ImportListResponse importResponse)
|
public virtual IList<ImportListItemInfo> ParseResponse(ImportListResponse importResponse)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +29,7 @@ namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonResponse = STJson.Deserialize<SimklResponse>(_importResponse.Content);
|
var jsonResponse = Json.Deserialize<SimklResponse>(_importResponse.Content);
|
||||||
|
|
||||||
// no shows were return
|
// no shows were return
|
||||||
if (jsonResponse == null)
|
if (jsonResponse == null)
|
||||||
|
@ -30,14 +37,40 @@ namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var show in jsonResponse.Shows)
|
if (jsonResponse.Anime != null)
|
||||||
{
|
{
|
||||||
series.AddIfNotNull(new ImportListItemInfo()
|
foreach (var show in jsonResponse.Anime)
|
||||||
{
|
{
|
||||||
Title = show.Show.Title,
|
var tentativeTvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0;
|
||||||
TvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0,
|
|
||||||
ImdbId = show.Show.Ids.Imdb
|
if (tentativeTvdbId > 0 && show.AnimeType == SimklAnimeType.Tv)
|
||||||
});
|
{
|
||||||
|
series.AddIfNotNull(new ImportListItemInfo()
|
||||||
|
{
|
||||||
|
Title = show.Show.Title,
|
||||||
|
ImdbId = show.Show.Ids.Imdb,
|
||||||
|
TvdbId = tvdbId,
|
||||||
|
MalId = int.TryParse(show.Show.Ids.Mal, out var malId) ? malId : 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Warn("Skipping info grabbing for '{0}' because it is a movie or it is not the first season of the show", show.Show.Title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonResponse.Shows != null)
|
||||||
|
{
|
||||||
|
foreach (var show in jsonResponse.Shows)
|
||||||
|
{
|
||||||
|
series.AddIfNotNull(new ImportListItemInfo()
|
||||||
|
{
|
||||||
|
Title = show.Show.Title,
|
||||||
|
TvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0,
|
||||||
|
ImdbId = show.Show.Ids.Imdb
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return series;
|
return series;
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
|
|
||||||
private IEnumerable<ImportListRequest> GetSeriesRequest()
|
private IEnumerable<ImportListRequest> GetSeriesRequest()
|
||||||
{
|
{
|
||||||
var link = $"{Settings.BaseUrl.Trim()}/sync/all-items/shows/{((SimklUserListType)Settings.ListType).ToString().ToLowerInvariant()}";
|
var link = $"{Settings.BaseUrl.Trim()}/sync/all-items/{((SimklUserShowType)Settings.ShowType).ToString().ToLowerInvariant()}/{((SimklUserListType)Settings.ListType).ToString().ToLowerInvariant()}";
|
||||||
|
|
||||||
var request = new ImportListRequest(link, HttpAccept.Json);
|
var request = new ImportListRequest(link, HttpAccept.Json);
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,13 @@ namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
public SimklUserSettings()
|
public SimklUserSettings()
|
||||||
{
|
{
|
||||||
ListType = (int)SimklUserListType.Watching;
|
ListType = (int)SimklUserListType.Watching;
|
||||||
|
ShowType = (int)SimklUserShowType.Shows;
|
||||||
}
|
}
|
||||||
|
|
||||||
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(SimklUserListType), HelpText = "Type of list you're seeking to import from")]
|
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(SimklUserListType), HelpText = "Type of list you're seeking to import from")]
|
||||||
public int ListType { get; set; }
|
public int ListType { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(1, Label = "Show Type", Type = FieldType.Select, SelectOptions = typeof(SimklUserShowType), HelpText = "Type of show you're seeking to import from")]
|
||||||
|
public int ShowType { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
|
{
|
||||||
|
public enum SimklUserShowType
|
||||||
|
{
|
||||||
|
Shows = 0,
|
||||||
|
Anime = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -139,12 +139,14 @@
|
||||||
"InstallLatest": "Install Latest",
|
"InstallLatest": "Install Latest",
|
||||||
"Interval": "Interval",
|
"Interval": "Interval",
|
||||||
"IRC": "IRC",
|
"IRC": "IRC",
|
||||||
|
"IRCLinkText": "#sonarr on Libera",
|
||||||
"Language": "Language",
|
"Language": "Language",
|
||||||
"Language that Sonarr will use for UI": "Language that Sonarr will use for UI",
|
"Language that Sonarr will use for UI": "Language that Sonarr will use for UI",
|
||||||
"Languages": "Languages",
|
"Languages": "Languages",
|
||||||
"LastDuration": "Last Duration",
|
"LastDuration": "Last Duration",
|
||||||
"LastExecution": "Last Execution",
|
"LastExecution": "Last Execution",
|
||||||
"LastWriteTime": "Last Write Time",
|
"LastWriteTime": "Last Write Time",
|
||||||
|
"LiberaWebchat": "Libera Webchat",
|
||||||
"LibraryImport": "Library Import",
|
"LibraryImport": "Library Import",
|
||||||
"Location": "Location",
|
"Location": "Location",
|
||||||
"LogFiles": "Log Files",
|
"LogFiles": "Log Files",
|
||||||
|
@ -189,7 +191,7 @@
|
||||||
"NoSeasons": "No seasons",
|
"NoSeasons": "No seasons",
|
||||||
"NoUpdatesAreAvailable": "No updates are available",
|
"NoUpdatesAreAvailable": "No updates are available",
|
||||||
"OneSeason": "1 season",
|
"OneSeason": "1 season",
|
||||||
"OnLatestVersion": "The latest version of Radarr is already installed",
|
"OnLatestVersion": "The latest version of Sonarr is already installed",
|
||||||
"Options": "Options",
|
"Options": "Options",
|
||||||
"OriginalLanguage": "Original Language",
|
"OriginalLanguage": "Original Language",
|
||||||
"PackageVersion": "Package Version",
|
"PackageVersion": "Package Version",
|
||||||
|
@ -276,6 +278,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",
|
||||||
|
|
|
@ -214,5 +214,100 @@
|
||||||
"SeasonNumber": "Número da Temporada",
|
"SeasonNumber": "Número da Temporada",
|
||||||
"SeriesTitle": "Título da Série",
|
"SeriesTitle": "Título da Série",
|
||||||
"Special": "Especial",
|
"Special": "Especial",
|
||||||
"TestParsing": "Análise de Teste"
|
"TestParsing": "Análise de Teste",
|
||||||
|
"About": "Sobre",
|
||||||
|
"Actions": "Ações",
|
||||||
|
"AppDataDirectory": "Diretório AppData",
|
||||||
|
"AptUpdater": "Usar apt para instalar atualizações",
|
||||||
|
"BackupNow": "Fazer Backup Agora",
|
||||||
|
"Backups": "Backups",
|
||||||
|
"BeforeUpdate": "Antes de atualizar",
|
||||||
|
"CancelPendingTask": "Tem certeza de que deseja cancelar esta tarefa pendente?",
|
||||||
|
"Clear": "Limpar",
|
||||||
|
"CurrentlyInstalled": "Atualmente instalado",
|
||||||
|
"DeleteBackup": "Excluir Backup",
|
||||||
|
"DeleteBackupMessageText": "Tem certeza de que deseja excluir o backup '{name}'?",
|
||||||
|
"Discord": "Discord",
|
||||||
|
"DiskSpace": "Espaço em Disco",
|
||||||
|
"Docker": "Docker",
|
||||||
|
"DockerUpdater": "Atualize o contêiner docker para receber a atualização",
|
||||||
|
"Donations": "Doações",
|
||||||
|
"DotNetVersion": ".NET",
|
||||||
|
"Download": "Baixar",
|
||||||
|
"Duration": "Duração",
|
||||||
|
"ErrorRestoringBackup": "Erro ao restaurar o backup",
|
||||||
|
"Exception": "Exceção",
|
||||||
|
"ExternalUpdater": "O Sonarr está configurado para usar um mecanismo de atualização externo",
|
||||||
|
"FailedToFetchUpdates": "Falha ao buscar atualizações",
|
||||||
|
"FailedToUpdateSettings": "Falha ao atualizar as configurações",
|
||||||
|
"FeatureRequests": "Solicitações de recursos",
|
||||||
|
"Filename": "Nome do arquivo",
|
||||||
|
"Fixed": "Corrigido",
|
||||||
|
"Forums": "Fóruns",
|
||||||
|
"FreeSpace": "Espaço Livre",
|
||||||
|
"From": "De",
|
||||||
|
"GeneralSettings": "Configurações Gerais",
|
||||||
|
"Health": "Saúde",
|
||||||
|
"HomePage": "Página Inicial",
|
||||||
|
"OnLatestVersion": "A versão mais recente do Sonarr já está instalada",
|
||||||
|
"InstallLatest": "Instalar o mais recente",
|
||||||
|
"Interval": "Intervalo",
|
||||||
|
"IRC": "IRC",
|
||||||
|
"LastDuration": "Última Duração",
|
||||||
|
"LastExecution": "Última Execução",
|
||||||
|
"LastWriteTime": "Hora da Última Gravação",
|
||||||
|
"Location": "Localização",
|
||||||
|
"LogFilesLocation": "Os arquivos de log estão localizados em: {location}",
|
||||||
|
"Logs": "Logs",
|
||||||
|
"MaintenanceRelease": "Versão de manutenção: correções de bugs e outras melhorias. Veja Github Commit History para mais detalhes",
|
||||||
|
"Manual": "Manual",
|
||||||
|
"Message": "Mensagem",
|
||||||
|
"Mode": "Modo",
|
||||||
|
"MoreInfo": "Mais informações",
|
||||||
|
"New": "Novo",
|
||||||
|
"NextExecution": "Próxima Execução",
|
||||||
|
"NoBackupsAreAvailable": "Não há backups disponíveis",
|
||||||
|
"NoEventsFound": "Nenhum evento encontrado",
|
||||||
|
"NoIssuesWithYourConfiguration": "Sem problemas com sua configuração",
|
||||||
|
"NoLeaveIt": "Não, deixe-o",
|
||||||
|
"NoLogFiles": "Nenhum arquivo de log",
|
||||||
|
"NoUpdatesAreAvailable": "Nenhuma atualização está disponível",
|
||||||
|
"Options": "Opções",
|
||||||
|
"PackageVersion": "Versão do pacote",
|
||||||
|
"PackageVersionInfo": "{packageVersion} por {packageAuthor}",
|
||||||
|
"PreviouslyInstalled": "Instalado anteriormente",
|
||||||
|
"Queued": "Enfileirados",
|
||||||
|
"ReadTheWikiForMoreInformation": "Leia o Wiki para mais informações",
|
||||||
|
"Refresh": "Atualizar",
|
||||||
|
"Reload": "Recarregar",
|
||||||
|
"RemovedFromTaskQueue": "Removido da fila de tarefas",
|
||||||
|
"Restart": "Reiniciar",
|
||||||
|
"TaskUserAgentTooltip": "User-Agent fornecido pelo aplicativo que chamou a API",
|
||||||
|
"ResetQualityDefinitions": "Redefinir Definições de Qualidade",
|
||||||
|
"ResetQualityDefinitionsMessageText": "Tem certeza de que deseja redefinir as definições de qualidade?",
|
||||||
|
"ResetTitles": "Redefinir Títulos",
|
||||||
|
"Restore": "Restaurar",
|
||||||
|
"RestoreBackup": "Restaurar backup",
|
||||||
|
"Scheduled": "Agendado",
|
||||||
|
"SeriesEditor": "Editor de séries",
|
||||||
|
"Size": "Tamanho",
|
||||||
|
"Source": "Fonte",
|
||||||
|
"Started": "Iniciado",
|
||||||
|
"StartupDirectory": "Diretório de inicialização",
|
||||||
|
"Status": "Estado",
|
||||||
|
"TestAll": "Testar Tudo",
|
||||||
|
"TheLogLevelDefault": "O padrão do nível de log é 'Info' e pode ser alterado em [Configurações gerais](/configurações /geral)",
|
||||||
|
"Time": "Horário",
|
||||||
|
"TotalSpace": "Espaço Total",
|
||||||
|
"Twitter": "Twitter",
|
||||||
|
"UnableToLoadBackups": "Não foi possível carregar os backups",
|
||||||
|
"UnableToUpdateSonarrDirectly": "Incapaz de atualizar o Sonarr diretamente,",
|
||||||
|
"UpdaterLogFiles": "Arquivos de log do atualizador",
|
||||||
|
"Uptime": "Tempo de atividade",
|
||||||
|
"Wiki": "Wiki",
|
||||||
|
"WouldYouLikeToRestoreBackup": "Gostaria de restaurar o backup '{name}'?",
|
||||||
|
"YesCancel": "Sim, Cancelar",
|
||||||
|
"Reset": "Redefinir",
|
||||||
|
"ResetDefinitionTitlesHelpText": "Redefinir títulos de definição, bem como valores",
|
||||||
|
"RestartReloadNote": "Observação: o Sonarr reiniciará automaticamente e recarregará a IU durante o processo de restauração."
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace NzbDrone.Core.Organizer
|
||||||
_standardSeries = new Series
|
_standardSeries = new Series
|
||||||
{
|
{
|
||||||
SeriesType = SeriesTypes.Standard,
|
SeriesType = SeriesTypes.Standard,
|
||||||
Title = "The Series Title!",
|
Title = "The Series Title's!",
|
||||||
Year = 2010,
|
Year = 2010,
|
||||||
ImdbId = "tt12345",
|
ImdbId = "tt12345",
|
||||||
TvdbId = 12345,
|
TvdbId = 12345,
|
||||||
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Organizer
|
||||||
_dailySeries = new Series
|
_dailySeries = new Series
|
||||||
{
|
{
|
||||||
SeriesType = SeriesTypes.Daily,
|
SeriesType = SeriesTypes.Daily,
|
||||||
Title = "The Series Title!",
|
Title = "The Series Title's!",
|
||||||
Year = 2010,
|
Year = 2010,
|
||||||
ImdbId = "tt12345",
|
ImdbId = "tt12345",
|
||||||
TvdbId = 12345,
|
TvdbId = 12345,
|
||||||
|
@ -64,7 +64,7 @@ namespace NzbDrone.Core.Organizer
|
||||||
_animeSeries = new Series
|
_animeSeries = new Series
|
||||||
{
|
{
|
||||||
SeriesType = SeriesTypes.Anime,
|
SeriesType = SeriesTypes.Anime,
|
||||||
Title = "The Series Title!",
|
Title = "The Series Title's!",
|
||||||
Year = 2010,
|
Year = 2010,
|
||||||
ImdbId = "tt12345",
|
ImdbId = "tt12345",
|
||||||
TvdbId = 12345,
|
TvdbId = 12345,
|
||||||
|
@ -141,45 +141,45 @@ namespace NzbDrone.Core.Organizer
|
||||||
|
|
||||||
_singleEpisodeFile = new EpisodeFile
|
_singleEpisodeFile = new EpisodeFile
|
||||||
{
|
{
|
||||||
Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
|
Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
|
||||||
RelativePath = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv",
|
RelativePath = "The.Series.Title's!.S01E01.1080p.WEBDL.x264-EVOLVE.mkv",
|
||||||
SceneName = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE",
|
SceneName = "The.Series.Title's!.S01E01.1080p.WEBDL.x264-EVOLVE",
|
||||||
ReleaseGroup = "RlsGrp",
|
ReleaseGroup = "RlsGrp",
|
||||||
MediaInfo = mediaInfo
|
MediaInfo = mediaInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
_multiEpisodeFile = new EpisodeFile
|
_multiEpisodeFile = new EpisodeFile
|
||||||
{
|
{
|
||||||
Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
|
Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
|
||||||
RelativePath = "Series.Title.S01E01-E03.720p.HDTV.x264-EVOLVE.mkv",
|
RelativePath = "The.Series.Title's!.S01E01-E03.1080p.WEBDL.x264-EVOLVE.mkv",
|
||||||
SceneName = "Series.Title.S01E01-E03.720p.HDTV.x264-EVOLVE",
|
SceneName = "The.Series.Title's!.S01E01-E03.1080p.WEBDL.x264-EVOLVE",
|
||||||
ReleaseGroup = "RlsGrp",
|
ReleaseGroup = "RlsGrp",
|
||||||
MediaInfo = mediaInfo,
|
MediaInfo = mediaInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
_dailyEpisodeFile = new EpisodeFile
|
_dailyEpisodeFile = new EpisodeFile
|
||||||
{
|
{
|
||||||
Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
|
Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
|
||||||
RelativePath = "Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv",
|
RelativePath = "The.Series.Title's!.2013.10.30.1080p.WEBDL.x264-EVOLVE.mkv",
|
||||||
SceneName = "Series.Title.2013.10.30.HDTV.x264-EVOLVE",
|
SceneName = "The.Series.Title's!.2013.10.30.1080p.WEBDL.x264-EVOLVE",
|
||||||
ReleaseGroup = "RlsGrp",
|
ReleaseGroup = "RlsGrp",
|
||||||
MediaInfo = mediaInfo
|
MediaInfo = mediaInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
_animeEpisodeFile = new EpisodeFile
|
_animeEpisodeFile = new EpisodeFile
|
||||||
{
|
{
|
||||||
Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
|
Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
|
||||||
RelativePath = "[RlsGroup] Series Title - 001 [720p].mkv",
|
RelativePath = "[RlsGroup] The Series Title's! - 001 [1080P].mkv",
|
||||||
SceneName = "[RlsGroup] Series Title - 001 [720p]",
|
SceneName = "[RlsGroup] The Series Title's! - 001 [1080P]",
|
||||||
ReleaseGroup = "RlsGrp",
|
ReleaseGroup = "RlsGrp",
|
||||||
MediaInfo = mediaInfoAnime
|
MediaInfo = mediaInfoAnime
|
||||||
};
|
};
|
||||||
|
|
||||||
_animeMultiEpisodeFile = new EpisodeFile
|
_animeMultiEpisodeFile = new EpisodeFile
|
||||||
{
|
{
|
||||||
Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
|
Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
|
||||||
RelativePath = "[RlsGroup] Series Title - 001 - 103 [720p].mkv",
|
RelativePath = "[RlsGroup] The Series Title's! - 001 - 103 [1080p].mkv",
|
||||||
SceneName = "[RlsGroup] Series Title - 001 - 103 [720p]",
|
SceneName = "[RlsGroup] The Series Title's! - 001 - 103 [1080p]",
|
||||||
ReleaseGroup = "RlsGrp",
|
ReleaseGroup = "RlsGrp",
|
||||||
MediaInfo = mediaInfoAnime
|
MediaInfo = mediaInfoAnime
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
public int TvdbId { get; set; }
|
public int TvdbId { get; set; }
|
||||||
public int TmdbId { get; set; }
|
public int TmdbId { get; set; }
|
||||||
public string ImdbId { get; set; }
|
public string ImdbId { get; set; }
|
||||||
|
public int MalId { get; set; }
|
||||||
public DateTime ReleaseDate { get; set; }
|
public DateTime ReleaseDate { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -5132,6 +5132,14 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "skipRedownload",
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -5162,6 +5170,14 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "skipRedownload",
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
|
|
|
@ -123,7 +123,7 @@ namespace Sonarr.Http.ClientSchema
|
||||||
Placeholder = fieldAttribute.Placeholder
|
Placeholder = fieldAttribute.Placeholder
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fieldAttribute.Type == FieldType.Select || fieldAttribute.Type == FieldType.TagSelect)
|
if (fieldAttribute.Type is FieldType.Select or FieldType.TagSelect)
|
||||||
{
|
{
|
||||||
if (fieldAttribute.SelectOptionsProviderAction.IsNotNullOrWhiteSpace())
|
if (fieldAttribute.SelectOptionsProviderAction.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
|
@ -172,31 +172,33 @@ namespace Sonarr.Http.ClientSchema
|
||||||
{
|
{
|
||||||
if (selectOptions.IsEnum)
|
if (selectOptions.IsEnum)
|
||||||
{
|
{
|
||||||
var options = selectOptions.GetFields().Where(v => v.IsStatic).Select(v =>
|
var options = selectOptions
|
||||||
{
|
.GetFields()
|
||||||
var name = v.Name.Replace('_', ' ');
|
.Where(v => v.IsStatic && !v.GetCustomAttributes(false).OfType<ObsoleteAttribute>().Any())
|
||||||
var value = Convert.ToInt32(v.GetRawConstantValue());
|
.Select(v =>
|
||||||
var attrib = v.GetCustomAttribute<FieldOptionAttribute>();
|
|
||||||
if (attrib != null)
|
|
||||||
{
|
{
|
||||||
return new SelectOption
|
var name = v.Name.Replace('_', ' ');
|
||||||
|
var value = Convert.ToInt32(v.GetRawConstantValue());
|
||||||
|
var attrib = v.GetCustomAttribute<FieldOptionAttribute>();
|
||||||
|
|
||||||
|
if (attrib != null)
|
||||||
{
|
{
|
||||||
Value = value,
|
return new SelectOption
|
||||||
Name = attrib.Label ?? name,
|
{
|
||||||
Order = attrib.Order,
|
Value = value,
|
||||||
Hint = attrib.Hint ?? $"({value})"
|
Name = attrib.Label ?? name,
|
||||||
};
|
Order = attrib.Order,
|
||||||
}
|
Hint = attrib.Hint ?? $"({value})"
|
||||||
else
|
};
|
||||||
{
|
}
|
||||||
|
|
||||||
return new SelectOption
|
return new SelectOption
|
||||||
{
|
{
|
||||||
Value = value,
|
Value = value,
|
||||||
Name = name,
|
Name = name,
|
||||||
Order = value
|
Order = value
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return options.OrderBy(o => o.Order).ToList();
|
return options.OrderBy(o => o.Order).ToList();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue